mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-19 12:25:12 -04:00
skeletal: allow multiple animations
This commit is contained in:
parent
2cf5b5f698
commit
0cb65fd1c8
@ -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}")
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user