skeletal: allow multiple animations

This commit is contained in:
Bixilon 2022-06-07 20:15:54 +02:00
parent 2cf5b5f698
commit 0cb65fd1c8
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
7 changed files with 108 additions and 46 deletions

View File

@ -18,6 +18,7 @@ import de.bixilon.kotlinglm.vec2.Vec2i
import de.bixilon.kotlinglm.vec3.Vec3
import de.bixilon.minosoft.data.text.BaseComponent
import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.data.text.EmptyComponent
import de.bixilon.minosoft.data.text.TextComponent
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.font.WorldGUIConsumer
@ -46,6 +47,7 @@ interface ChatComponentRenderer<T : ChatComponent> {
return when (text) {
is BaseComponent -> BaseComponentRenderer.render(initialOffset, offset, size, element, renderWindow, consumer, options, renderInfo, text)
is TextComponent -> TextComponentRenderer.render(initialOffset, offset, size, element, renderWindow, consumer, options, renderInfo, text)
is EmptyComponent -> return true
else -> TODO("Don't know how to render ${text::class.java}")
}
}
@ -54,6 +56,7 @@ interface ChatComponentRenderer<T : ChatComponent> {
when (text) {
is BaseComponent -> BaseComponentRenderer.render3dFlat(renderWindow, offset, scale, maxSize, consumer, text, light)
is TextComponent -> TextComponentRenderer.render3dFlat(renderWindow, offset, scale, maxSize, consumer, text, light)
is EmptyComponent -> return
else -> TODO("Don't know how to render ${text::class.java}")
}
}
@ -76,6 +79,7 @@ interface ChatComponentRenderer<T : ChatComponent> {
return when (text) {
is BaseComponent -> BaseComponentRenderer.calculatePrimitiveCount(text)
is TextComponent -> TextComponentRenderer.calculatePrimitiveCount(text)
is EmptyComponent -> 0
else -> TODO("Don't know how to render ${text::class.java}")
}
}

View File

@ -92,15 +92,17 @@ class TabListEntryElement(
override fun forceSilentApply() {
// ToDo (Performance): If something changed, should we just prepare the changed
pingElement = AtlasImageElement(guiRenderer, tabList.pingBarsAtlasElements[when {
ping < 0 -> 0
ping < 150 -> 5
ping < 300 -> 4
ping < 600 -> 3
ping < 1000 -> 2
else -> 1
}])
nameElement.prefMaxSize = Vec2i(max(0, maxSize.x - pingElement.size.x), HEIGHT)
pingElement = AtlasImageElement(
guiRenderer, tabList.pingBarsAtlasElements[when {
ping < 0 -> 0
ping < 150 -> 5
ping < 300 -> 4
ping < 600 -> 3
ping < 1000 -> 2
else -> 1
}]
)
nameElement.prefMaxSize = Vec2i(max(0, maxSize.x - pingElement.size.x - skinElement.size.x - INNER_MARGIN), HEIGHT)
nameElement.text = displayName

View File

@ -0,0 +1,35 @@
/*
* Minosoft
* Copyright (C) 2020-2022 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.skeletal.instance
import de.bixilon.minosoft.gui.rendering.skeletal.model.animations.SkeletalAnimation
class SkeletalAnimationInstance(
var animation: SkeletalAnimation,
) {
var time = 0.0f
var lastFrame = -1L
fun draw(time: Long) {
if (lastFrame > 0L) {
val delta = time - lastFrame
this.time += delta / 1000.0f
}
lastFrame = time
}
fun canClear(): Boolean {
return animation.canClear(time)
}
}

View File

@ -34,34 +34,34 @@ class SkeletalInstance(
) {
private var baseTransform = Mat4().translateAssign(blockPosition.toVec3) * transform
private var previousBaseTransform = baseTransform
private var currentAnimation: SkeletalAnimation? = null
private var animationTime = 0.0f
private var animationLastFrame = -1L
private var animations: MutableList<SkeletalAnimationInstance> = mutableListOf()
private var transforms: List<Mat4> = emptyList()
var light: Int = 0xFF
fun playAnimation(name: String) {
clearAnimation()
var animation: SkeletalAnimation? = null
for (animationEntry in model.model.animations) {
if (animationEntry.name != name) {
fun getAnimation(name: String): SkeletalAnimation? {
for (animation in model.model.animations) {
if (animation.name != name) {
continue
}
animation = animationEntry
break
return animation
}
if (animation == null) {
throw IllegalArgumentException("Can not find animation $name")
}
this.currentAnimation = animation
return null
}
fun playAnimation(animation: SkeletalAnimation) {
val instance = SkeletalAnimationInstance(animation)
animations.removeAll { it.animation == animation }
animations += instance
}
fun playAnimation(name: String) {
playAnimation(getAnimation(name) ?: throw IllegalArgumentException("Can not find animation $name"))
}
fun clearAnimation() {
animationTime = 0.0f
animationLastFrame = -1L
this.currentAnimation = null
animations.clear()
}
fun draw() {
@ -80,42 +80,49 @@ class SkeletalInstance(
fun calculateTransforms(): List<Mat4> {
val baseTransform = baseTransform
val animation = currentAnimation
if (animation != null) {
if (animations.isNotEmpty()) {
val time = TimeUtil.millis
if (this.animationLastFrame > 0L) {
val delta = time - this.animationLastFrame
animationTime += delta / 1000.0f
val toRemove: MutableSet<SkeletalAnimationInstance> = mutableSetOf()
for (animation in animations) {
animation.draw(time)
if (animation.canClear()) {
toRemove += animation
}
}
animationLastFrame = time
if (animation.canClear(animationTime)) {
clearAnimation()
return calculateTransforms()
if (toRemove.isNotEmpty()) {
this.animations -= toRemove
}
}
if (animations.isEmpty()) {
if (this.transforms.isNotEmpty() && baseTransform === previousBaseTransform) {
return this.transforms
}
} else if (this.transforms.isNotEmpty() && baseTransform === previousBaseTransform) {
return this.transforms
}
val transforms: MutableList<Mat4> = mutableListOf()
for (outliner in model.model.outliner) {
calculateTransform(animationTime, baseTransform, animation, outliner, transforms)
calculateTransform(baseTransform, animations, outliner, transforms)
}
this.transforms = transforms
this.previousBaseTransform = baseTransform
return transforms
}
private fun calculateTransform(animationTime: Float, transform: Mat4, animation: SkeletalAnimation?, outliner: Any /* UUID or SkeletalOutliner */, transforms: MutableList<Mat4>) {
private fun calculateTransform(transform: Mat4, animations: List<SkeletalAnimationInstance>, outliner: Any /* UUID or SkeletalOutliner */, transforms: MutableList<Mat4>) {
if (outliner is UUID) {
return
}
check(outliner is SkeletalOutliner)
val skeletalTransform = transform * (animation?.calculateTransform(outliner, animationTime) ?: Mat4())
val skeletalTransform = Mat4(transform)
for (animation in this.animations) {
skeletalTransform *= animation.animation.calculateTransform(outliner, animation.time)
}
transforms += skeletalTransform
for (child in outliner.children) {
calculateTransform(animationTime, skeletalTransform, animation, child, transforms)
calculateTransform(skeletalTransform, animations, child, transforms)
}
}
}

View File

@ -31,6 +31,7 @@ data class SkeletalAnimation(
val length: Float,
val animators: Map<UUID, SkeletalAnimator>,
) {
fun get(channel: KeyframeChannels, animatorUUID: UUID, time: Float): Vec3? {
val animator = animators[animatorUUID] ?: return null

View File

@ -31,10 +31,14 @@ abstract class StorageBlockEntityRenderer<E : StorageBlockEntity>(
}
fun open() {
this.skeletal?.playAnimation("animation.chest.opening")
val skeletal = this.skeletal ?: return
skeletal.clearAnimation()
skeletal.playAnimation("animation.chest.opening")
}
fun close() {
this.skeletal?.playAnimation("animation.chest.closing")
val skeletal = this.skeletal ?: return
skeletal.clearAnimation()
skeletal.playAnimation("animation.chest.closing")
}
}

View File

@ -345,7 +345,7 @@
8,
24,
2
]
],
"origin": [
0,
0,
@ -425,7 +425,7 @@
8,
24,
2
]
],
"inflate": 0.25,
"origin": [
0,
@ -997,7 +997,7 @@
"uuid": "6da490f7-5540-bf4a-7f0a-12a5df3f3ce0",
"children": [
"842246c7-d06c-8ec1-c4d0-3dd83fd2ddfc",
"be9eb8b9-9c9e-8f03-89be-623f059ad715^"
"be9eb8b9-9c9e-8f03-89be-623f059ad715"
]
},
{
@ -1085,5 +1085,14 @@
"478b4925-5e2b-235f-0d95-d5d028ad624d"
]
}
],
"textures": [
{
"path": "",
"name": "",
"namespace": "",
"id": 0,
"uuid": "1f404026-8fa3-4dc9-b101-772d2994f4e6"
}
]
}