From a0a52f57b4c69e8be0ea1660d574dc0ac3b73386 Mon Sep 17 00:00:00 2001 From: Moritz Zwerger Date: Tue, 17 Oct 2023 10:14:16 +0200 Subject: [PATCH] skeletal: animation instancing --- .../resources/model/skeletal/dummy.smodel | 34 ++++++------- .../storage/StorageBlockEntityRenderer.kt | 6 +-- .../skeletal/baked/BakedSkeletalModel.kt | 3 +- .../baked/animation/AbstractAnimation.kt | 19 +++++++ .../animation/keyframe/KeyframeAnimation.kt | 25 ++++++++++ .../animation/keyframe/KeyframeAnimator.kt | 25 ++++++++++ .../skeletal/instance/AnimationManager.kt | 50 +++++++++++++++++++ .../skeletal/instance/SkeletalInstance.kt | 3 ++ .../rendering/skeletal/model/SkeletalModel.kt | 4 +- .../model/animations/SkeletalAnimation.kt | 22 +++++--- .../animations/animators/SkeletalAnimator.kt | 25 +++++++++- .../models/block/entities/single_chest.smodel | 34 ++++++------- 12 files changed, 200 insertions(+), 50 deletions(-) create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/baked/animation/AbstractAnimation.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/baked/animation/keyframe/KeyframeAnimation.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/baked/animation/keyframe/KeyframeAnimator.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/instance/AnimationManager.kt diff --git a/src/integration-test/resources/model/skeletal/dummy.smodel b/src/integration-test/resources/model/skeletal/dummy.smodel index 3a9979279..fc9be0ff1 100644 --- a/src/integration-test/resources/model/skeletal/dummy.smodel +++ b/src/integration-test/resources/model/skeletal/dummy.smodel @@ -67,24 +67,22 @@ } }, "animations": { - "open": { - "loop": "hold", - "length": 0.3, - "animators": [ - { - "transform": "base.head", - "keyframes": [ - { - "type": "rotate", - "interpolation": "sine", - "keyframes": { - "0.0": [0, 0, 0], - "0.3": [-90, 0, 0] - } + "open": [ + { + "transform": "head", + "loop": "hold", + "length": 0.3, + "keyframes": [ + { + "type": "rotate", + "interpolation": "sine", + "keyframes": { + "0.0": [0, 0, 0], + "0.3": [-90, 0, 0] } - ] - } - ] - } + } + ] + } + ] } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/StorageBlockEntityRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/StorageBlockEntityRenderer.kt index cc38a352d..2f94bbd9e 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/StorageBlockEntityRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/StorageBlockEntityRenderer.kt @@ -13,10 +13,8 @@ package de.bixilon.minosoft.gui.rendering.chunk.entities.renderer.storage -import de.bixilon.minosoft.data.direction.Directions import de.bixilon.minosoft.data.entities.block.container.storage.StorageBlockEntity import de.bixilon.minosoft.data.registries.blocks.state.BlockState -import de.bixilon.minosoft.data.world.positions.BlockPosition import de.bixilon.minosoft.gui.rendering.RenderContext import de.bixilon.minosoft.gui.rendering.chunk.entities.BlockEntityRenderer import de.bixilon.minosoft.gui.rendering.skeletal.instance.SkeletalInstance @@ -33,11 +31,11 @@ abstract class StorageBlockEntityRenderer( @Deprecated("refactor") fun playOpen() { - TODO() + skeletal?.animation?.play("open") } @Deprecated("refactor") fun playClose() { - TODO() + skeletal?.animation?.play("close") } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/baked/BakedSkeletalModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/baked/BakedSkeletalModel.kt index 5a51b4077..30c096a0d 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/baked/BakedSkeletalModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/baked/BakedSkeletalModel.kt @@ -16,12 +16,13 @@ package de.bixilon.minosoft.gui.rendering.skeletal.baked import de.bixilon.minosoft.gui.rendering.RenderContext import de.bixilon.minosoft.gui.rendering.skeletal.SkeletalMesh import de.bixilon.minosoft.gui.rendering.skeletal.instance.SkeletalInstance +import de.bixilon.minosoft.gui.rendering.skeletal.model.animations.SkeletalAnimation data class BakedSkeletalModel( val mesh: SkeletalMesh, val transform: BakedSkeletalTransform, val transformCount: Int, - // TODO: animations + val animations: Map, ) { private var state = SkeletalModelStates.DECLARED diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/baked/animation/AbstractAnimation.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/baked/animation/AbstractAnimation.kt new file mode 100644 index 000000000..229dab29e --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/baked/animation/AbstractAnimation.kt @@ -0,0 +1,19 @@ +/* + * Minosoft + * Copyright (C) 2020-2023 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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.skeletal.baked.animation + +interface AbstractAnimation { + + fun draw(delta: Float): Boolean +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/baked/animation/keyframe/KeyframeAnimation.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/baked/animation/keyframe/KeyframeAnimation.kt new file mode 100644 index 000000000..4ad6d48fd --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/baked/animation/keyframe/KeyframeAnimation.kt @@ -0,0 +1,25 @@ +/* + * Minosoft + * Copyright (C) 2020-2023 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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.skeletal.baked.animation.keyframe + +import de.bixilon.minosoft.gui.rendering.skeletal.baked.animation.AbstractAnimation + +class KeyframeAnimation( + val animators: Array, +) : AbstractAnimation { + + override fun draw(delta: Float): Boolean { + TODO("Not yet implemented") + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/baked/animation/keyframe/KeyframeAnimator.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/baked/animation/keyframe/KeyframeAnimator.kt new file mode 100644 index 000000000..9841db856 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/baked/animation/keyframe/KeyframeAnimator.kt @@ -0,0 +1,25 @@ +/* + * Minosoft + * Copyright (C) 2020-2023 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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.skeletal.baked.animation.keyframe + +import de.bixilon.minosoft.gui.rendering.skeletal.instance.TransformInstance +import de.bixilon.minosoft.gui.rendering.skeletal.model.animations.animators.AnimationLoops +import de.bixilon.minosoft.gui.rendering.skeletal.model.animations.animators.keyframes.SkeletalKeyframe + +class KeyframeAnimator( + val transform: TransformInstance, + val loop: AnimationLoops, + val length: Float, + val keyframes: List, +) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/instance/AnimationManager.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/instance/AnimationManager.kt new file mode 100644 index 000000000..10631306e --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/instance/AnimationManager.kt @@ -0,0 +1,50 @@ +/* + * Minosoft + * Copyright (C) 2020-2023 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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.skeletal.instance + +import de.bixilon.kutil.time.TimeUtil.nanos +import de.bixilon.minosoft.gui.rendering.skeletal.baked.animation.AbstractAnimation + +class AnimationManager(val instance: SkeletalInstance) { + private var lastDraw = -1L + + + fun play(animation: AbstractAnimation) { + // TODO: don't play animations twice, reset them? + } + + fun play(name: String) { + val animation = instance.model.animations[name] ?: throw IllegalArgumentException("Can not find animation $name!") + play(animation.instance(instance)) + } + + fun stop(animation: AbstractAnimation) { + // TODO + } + + fun stop(name: String) { + // TODO + } + + + fun draw() { + val nanos = nanos() + val delta = nanos - lastDraw + draw(delta / 1000.0f) + } + + fun draw(delta: Float) { + // TODO + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/instance/SkeletalInstance.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/instance/SkeletalInstance.kt index e31350406..e8f28a9cb 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/instance/SkeletalInstance.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/instance/SkeletalInstance.kt @@ -28,9 +28,12 @@ class SkeletalInstance( val model: BakedSkeletalModel, val transform: TransformInstance, ) { + val animation = AnimationManager(this) var light = 0xFF + fun draw() { + animation.draw() context.skeletal.draw(this, light) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/model/SkeletalModel.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/model/SkeletalModel.kt index 07970486b..bc36933de 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/model/SkeletalModel.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/model/SkeletalModel.kt @@ -32,7 +32,7 @@ import java.util.concurrent.atomic.AtomicInteger data class SkeletalModel( val elements: Map, val textures: Map, - val animations: Map, + val animations: Map, val transforms: Map, ) { val loadedTextures: MutableMap = mutableMapOf() @@ -74,6 +74,6 @@ data class SkeletalModel( element.bake(mesh, textures, baseTransform) } - return BakedSkeletalModel(mesh, baseTransform, transformId.get()) + return BakedSkeletalModel(mesh, baseTransform, transformId.get(), animations) } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/model/animations/SkeletalAnimation.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/model/animations/SkeletalAnimation.kt index e17eb2f59..e9f13da6f 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/model/animations/SkeletalAnimation.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/model/animations/SkeletalAnimation.kt @@ -13,11 +13,21 @@ package de.bixilon.minosoft.gui.rendering.skeletal.model.animations -import de.bixilon.minosoft.gui.rendering.skeletal.model.animations.animators.AnimationLoops +import com.fasterxml.jackson.annotation.JsonValue +import de.bixilon.kutil.array.ArrayUtil.cast +import de.bixilon.minosoft.gui.rendering.skeletal.baked.animation.keyframe.KeyframeAnimation +import de.bixilon.minosoft.gui.rendering.skeletal.baked.animation.keyframe.KeyframeAnimator +import de.bixilon.minosoft.gui.rendering.skeletal.instance.SkeletalInstance import de.bixilon.minosoft.gui.rendering.skeletal.model.animations.animators.SkeletalAnimator -class SkeletalAnimation( - val loop: AnimationLoops, - val length: Float, - val animators: List -) +class SkeletalAnimation(@JsonValue val animators: List) { + + fun instance(instance: SkeletalInstance): KeyframeAnimation { + val array: Array = arrayOfNulls(this.animators.size) + + for ((index, animator) in this.animators.withIndex()) { + array[index] = animator.instance(instance) + } + return KeyframeAnimation(array.cast()) + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/model/animations/animators/SkeletalAnimator.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/model/animations/animators/SkeletalAnimator.kt index 00b16a035..3ef1b0271 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/model/animations/animators/SkeletalAnimator.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/model/animations/animators/SkeletalAnimator.kt @@ -13,9 +13,32 @@ package de.bixilon.minosoft.gui.rendering.skeletal.model.animations.animators +import de.bixilon.minosoft.gui.rendering.skeletal.baked.animation.keyframe.KeyframeAnimator +import de.bixilon.minosoft.gui.rendering.skeletal.instance.SkeletalInstance +import de.bixilon.minosoft.gui.rendering.skeletal.instance.TransformInstance import de.bixilon.minosoft.gui.rendering.skeletal.model.animations.animators.keyframes.SkeletalKeyframe data class SkeletalAnimator( val transform: String, + val loop: AnimationLoops, + val length: Float, val keyframes: List, -) +) { + private val split = transform.split(".", "/").toTypedArray() + + private fun SkeletalInstance.getTransform(): TransformInstance { + var transform = this.transform + if (split.size == 1 && split[0] == "base") return transform + + for (name in split) { + transform = transform.children[name] ?: throw IllegalStateException("Animation is referencing unknown transform!") + } + return transform + } + + fun instance(instance: SkeletalInstance): KeyframeAnimator { + val transform = instance.getTransform() + + return KeyframeAnimator(transform, loop, length, keyframes) + } +} diff --git a/src/main/resources/assets/minecraft/models/block/entities/single_chest.smodel b/src/main/resources/assets/minecraft/models/block/entities/single_chest.smodel index af8c35540..4fe741c9c 100644 --- a/src/main/resources/assets/minecraft/models/block/entities/single_chest.smodel +++ b/src/main/resources/assets/minecraft/models/block/entities/single_chest.smodel @@ -75,24 +75,22 @@ } ] }, - "close": { - "loop": "hold", - "length": 0.5, - "animators": [ - { - "transform": "base.lid", - "keyframes": [ - { - "type": "rotate", - "interpolation": "sine", - "keyframes": { - "0.0": [-90, 0, 0], - "0.5": [0, 0, 0] - } + "close": [ + { + "transform": "base.lid", + "loop": "hold", + "length": 0.5, + "keyframes": [ + { + "type": "rotate", + "interpolation": "sine", + "keyframes": { + "0.0": [-90, 0, 0], + "0.5": [0, 0, 0] } - ] - } - ] - } + } + ] + } + ] } }