diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/textures/TextureAnimation.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/textures/TextureAnimation.kt new file mode 100644 index 000000000..04ff0c97a --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/textures/TextureAnimation.kt @@ -0,0 +1,50 @@ +/* + * Minosoft + * Copyright (C) 2021 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.textures + +import de.bixilon.minosoft.gui.rendering.textures.properties.AnimationFrame + +class TextureAnimation( + val texture: Texture, +) { + var currentFrameIndex = 0 + var currentTime = 0L + + val animationProperties = texture.properties.animation!! + + fun getCurrentFrame(): AnimationFrame { + return animationProperties.frames[currentFrameIndex] + } + + fun getAndSetNextFrame(): AnimationFrame { + currentFrameIndex = getNextIndex() + currentTime = 0L + + return animationProperties.frames[currentFrameIndex] + } + + fun getNextFrame(): AnimationFrame { + return animationProperties.frames[getNextIndex()] + } + + private fun getNextIndex(): Int { + var nextFrameIndex = currentFrameIndex + 1 + + if (nextFrameIndex == animationProperties.frames.size) { + nextFrameIndex = 0 + } + + return nextFrameIndex + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/textures/TextureArray.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/textures/TextureArray.kt index 0b7c81da9..eee88765b 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/textures/TextureArray.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/textures/TextureArray.kt @@ -17,7 +17,6 @@ import de.bixilon.minosoft.Minosoft import de.bixilon.minosoft.data.assets.MinecraftAssetsManager import de.bixilon.minosoft.data.mappings.ResourceLocation import de.bixilon.minosoft.gui.rendering.shader.Shader -import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import de.bixilon.minosoft.util.logging.Log import de.matthiasmann.twl.utils.PNGDecoder import glm_.vec2.Vec2 @@ -74,7 +73,7 @@ class TextureArray(val allTextures: MutableList) { it.add(texture) texture.properties.animation?.let { properties -> properties.animationId = animator.animatedTextures.size - animator.animatedTextures.add(texture) + animator.animatedTextures.add(TextureAnimation(texture)) val bytesPerTexture = size.x * size.y * PNGDecoder.Format.RGBA.numComponents val fullBuffer = texture.buffer!! @@ -147,24 +146,22 @@ class TextureArray(val allTextures: MutableList) { const val TEXTURE_MAX_RESOLUTION = 1024 val DEBUG_TEXTURE = Texture.getResourceTextureIdentifier(textureName = "block/debug") + + private const val INTS_PER_ANIMATED_TEXTURE = 4 } inner class Animator { - val animatedTextures: MutableList = mutableListOf() + val animatedTextures: MutableList = mutableListOf() private var animatedBufferDataId = -1 - - private var currentTick = 0 - private var lastTickIncrementTime = 0L - - - lateinit var animatedData: IntArray + var lastRun = 0L + private lateinit var animatedData: IntArray var initialized = false private set fun initBuffer() { - animatedData = IntArray(32 * 4) // 4 data ints per entry + animatedData = IntArray(32 * INTS_PER_ANIMATED_TEXTURE) // 4 data ints per entry animatedBufferDataId = glGenBuffers() @@ -184,21 +181,36 @@ class TextureArray(val allTextures: MutableList) { if (!Minosoft.getConfig().config.game.animations.textures) { return } + val currentTime = System.currentTimeMillis() - if (currentTime - lastTickIncrementTime >= ProtocolDefinition.TICK_TIME) { - currentTick++ - lastTickIncrementTime = currentTime - } + val deltaLastDraw = currentTime - lastRun + lastRun = currentTime + + for (textureAnimation in animatedTextures) { + var currentFrame = textureAnimation.getCurrentFrame() + textureAnimation.currentTime += deltaLastDraw + + if (textureAnimation.currentTime >= currentFrame.animationTime) { + currentFrame = textureAnimation.getAndSetNextFrame() + textureAnimation.currentTime = 0L + } + + val nextFrame = textureAnimation.getNextFrame() + + val interpolation = if (textureAnimation.animationProperties.interpolate) { + (textureAnimation.currentTime * 100) / currentFrame.animationTime + } else { + 0L + } - for (texture in animatedTextures) { - val animationProperties = texture.properties.animation!! + val baseAnimatedData = (textureAnimation.texture.arrayId shl 24) or textureAnimation.texture.arrayLayer - val arrayOffset = animationProperties.animationId * 4 + val arrayOffset = textureAnimation.animationProperties.animationId * INTS_PER_ANIMATED_TEXTURE - animatedData[arrayOffset] = (texture.arrayId shl 24) or (texture.arrayLayer + (currentTick % animationProperties.frameCount)) - animatedData[arrayOffset + 1] = (texture.arrayId shl 24) or (texture.arrayLayer + 1) + (currentTick % animationProperties.frameCount) - animatedData[arrayOffset + 2] = 0 + animatedData[arrayOffset] = baseAnimatedData or currentFrame.index + animatedData[arrayOffset + 1] = baseAnimatedData or nextFrame.index + animatedData[arrayOffset + 2] = interpolation.toInt() } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/textures/properties/AnimationFrame.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/textures/properties/AnimationFrame.kt new file mode 100644 index 000000000..60b8b2b0c --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/textures/properties/AnimationFrame.kt @@ -0,0 +1,23 @@ +/* + * Minosoft + * Copyright (C) 2021 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.textures.properties + +import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition + +data class AnimationFrame( + val index: Int, + val time: Int, +) { + val animationTime = time * ProtocolDefinition.TICK_TIME +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/textures/properties/AnimationProperties.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/textures/properties/AnimationProperties.kt index 8469feca8..9964957fd 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/textures/properties/AnimationProperties.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/textures/properties/AnimationProperties.kt @@ -20,12 +20,17 @@ data class AnimationProperties( val interpolate: Boolean = false, var width: Int = -1, var height: Int = -1, - @Json(name = "frametime") val frameTime: Int = 1, - val frames: Any = Any(),// ToDo, + @Json(name = "frametime") private val frameTime: Int = 1, + @Json(name = "frames") private val _frames: List = listOf(), ) { + @Transient + lateinit var frames: Array + private set + var animationId = -1 var frameCount = -1 + private set fun postInit(texture: Texture) { if (width == -1) { @@ -36,5 +41,26 @@ data class AnimationProperties( } frameCount = texture.size.y / height + + val frames: MutableList = mutableListOf() + + if (_frames.isEmpty()) { + for (i in 0 until frameCount) { + frames.add(AnimationFrame(i, frameTime)) + } + } else { + for (frame in _frames) { + if (frame is Number) { + frames.add(AnimationFrame(frame.toInt(), frameTime)) + continue + } + check(frame is Map<*, *>) { "Invalid frame: $frame" } + + frames.add(AnimationFrame((frame["index"] as Number).toInt(), (frame["time"] as Number?)?.toInt() ?: frameTime)) + } + } + + this.frames = frames.toTypedArray() + } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/textures/properties/TextureProperties.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/textures/properties/TextureProperties.kt index b919e3857..82723c449 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/textures/properties/TextureProperties.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/textures/properties/TextureProperties.kt @@ -16,4 +16,5 @@ package de.bixilon.minosoft.gui.rendering.textures.properties data class TextureProperties( val blur: Boolean = false, val clamp: Boolean = false, + // ToDo: mipmaps )