skeletal: animation instancing

This commit is contained in:
Moritz Zwerger 2023-10-17 10:14:16 +02:00
parent 6a55f94424
commit a0a52f57b4
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
12 changed files with 200 additions and 50 deletions

View File

@ -67,12 +67,11 @@
} }
}, },
"animations": { "animations": {
"open": { "open": [
{
"transform": "head",
"loop": "hold", "loop": "hold",
"length": 0.3, "length": 0.3,
"animators": [
{
"transform": "base.head",
"keyframes": [ "keyframes": [
{ {
"type": "rotate", "type": "rotate",
@ -87,4 +86,3 @@
] ]
} }
} }
}

View File

@ -13,10 +13,8 @@
package de.bixilon.minosoft.gui.rendering.chunk.entities.renderer.storage 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.entities.block.container.storage.StorageBlockEntity
import de.bixilon.minosoft.data.registries.blocks.state.BlockState 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.RenderContext
import de.bixilon.minosoft.gui.rendering.chunk.entities.BlockEntityRenderer import de.bixilon.minosoft.gui.rendering.chunk.entities.BlockEntityRenderer
import de.bixilon.minosoft.gui.rendering.skeletal.instance.SkeletalInstance import de.bixilon.minosoft.gui.rendering.skeletal.instance.SkeletalInstance
@ -33,11 +31,11 @@ abstract class StorageBlockEntityRenderer<E : StorageBlockEntity>(
@Deprecated("refactor") @Deprecated("refactor")
fun playOpen() { fun playOpen() {
TODO() skeletal?.animation?.play("open")
} }
@Deprecated("refactor") @Deprecated("refactor")
fun playClose() { fun playClose() {
TODO() skeletal?.animation?.play("close")
} }
} }

View File

@ -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.RenderContext
import de.bixilon.minosoft.gui.rendering.skeletal.SkeletalMesh import de.bixilon.minosoft.gui.rendering.skeletal.SkeletalMesh
import de.bixilon.minosoft.gui.rendering.skeletal.instance.SkeletalInstance import de.bixilon.minosoft.gui.rendering.skeletal.instance.SkeletalInstance
import de.bixilon.minosoft.gui.rendering.skeletal.model.animations.SkeletalAnimation
data class BakedSkeletalModel( data class BakedSkeletalModel(
val mesh: SkeletalMesh, val mesh: SkeletalMesh,
val transform: BakedSkeletalTransform, val transform: BakedSkeletalTransform,
val transformCount: Int, val transformCount: Int,
// TODO: animations val animations: Map<String, SkeletalAnimation>,
) { ) {
private var state = SkeletalModelStates.DECLARED private var state = SkeletalModelStates.DECLARED

View File

@ -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 <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.baked.animation
interface AbstractAnimation {
fun draw(delta: Float): Boolean
}

View File

@ -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 <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.baked.animation.keyframe
import de.bixilon.minosoft.gui.rendering.skeletal.baked.animation.AbstractAnimation
class KeyframeAnimation(
val animators: Array<KeyframeAnimator>,
) : AbstractAnimation {
override fun draw(delta: Float): Boolean {
TODO("Not yet implemented")
}
}

View File

@ -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 <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.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<SkeletalKeyframe>,
)

View File

@ -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 <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.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
}
}

View File

@ -28,9 +28,12 @@ class SkeletalInstance(
val model: BakedSkeletalModel, val model: BakedSkeletalModel,
val transform: TransformInstance, val transform: TransformInstance,
) { ) {
val animation = AnimationManager(this)
var light = 0xFF var light = 0xFF
fun draw() { fun draw() {
animation.draw()
context.skeletal.draw(this, light) context.skeletal.draw(this, light)
} }

View File

@ -32,7 +32,7 @@ import java.util.concurrent.atomic.AtomicInteger
data class SkeletalModel( data class SkeletalModel(
val elements: Map<String, SkeletalElement>, val elements: Map<String, SkeletalElement>,
val textures: Map<ResourceLocation, SkeletalTexture>, val textures: Map<ResourceLocation, SkeletalTexture>,
val animations: Map<ResourceLocation, SkeletalAnimation>, val animations: Map<String, SkeletalAnimation>,
val transforms: Map<String, SkeletalTransform>, val transforms: Map<String, SkeletalTransform>,
) { ) {
val loadedTextures: MutableMap<ResourceLocation, SkeletalTextureInstance> = mutableMapOf() val loadedTextures: MutableMap<ResourceLocation, SkeletalTextureInstance> = mutableMapOf()
@ -74,6 +74,6 @@ data class SkeletalModel(
element.bake(mesh, textures, baseTransform) element.bake(mesh, textures, baseTransform)
} }
return BakedSkeletalModel(mesh, baseTransform, transformId.get()) return BakedSkeletalModel(mesh, baseTransform, transformId.get(), animations)
} }
} }

View File

@ -13,11 +13,21 @@
package de.bixilon.minosoft.gui.rendering.skeletal.model.animations 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 import de.bixilon.minosoft.gui.rendering.skeletal.model.animations.animators.SkeletalAnimator
class SkeletalAnimation( class SkeletalAnimation(@JsonValue val animators: List<SkeletalAnimator>) {
val loop: AnimationLoops,
val length: Float, fun instance(instance: SkeletalInstance): KeyframeAnimation {
val animators: List<SkeletalAnimator> val array: Array<KeyframeAnimator?> = arrayOfNulls(this.animators.size)
)
for ((index, animator) in this.animators.withIndex()) {
array[index] = animator.instance(instance)
}
return KeyframeAnimation(array.cast())
}
}

View File

@ -13,9 +13,32 @@
package de.bixilon.minosoft.gui.rendering.skeletal.model.animations.animators 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 import de.bixilon.minosoft.gui.rendering.skeletal.model.animations.animators.keyframes.SkeletalKeyframe
data class SkeletalAnimator( data class SkeletalAnimator(
val transform: String, val transform: String,
val loop: AnimationLoops,
val length: Float,
val keyframes: List<SkeletalKeyframe>, val keyframes: List<SkeletalKeyframe>,
) ) {
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)
}
}

View File

@ -75,12 +75,11 @@
} }
] ]
}, },
"close": { "close": [
"loop": "hold",
"length": 0.5,
"animators": [
{ {
"transform": "base.lid", "transform": "base.lid",
"loop": "hold",
"length": 0.5,
"keyframes": [ "keyframes": [
{ {
"type": "rotate", "type": "rotate",
@ -95,4 +94,3 @@
] ]
} }
} }
}