rendering: more animations

* Known bugs: Not all textures are animated
This commit is contained in:
Bixilon 2021-03-18 21:42:16 +01:00
parent fa6990b0b2
commit d348f8b7c5
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
5 changed files with 134 additions and 22 deletions

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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
}
}

View File

@ -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<Texture>) {
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<Texture>) {
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<Texture> = mutableListOf()
val animatedTextures: MutableList<TextureAnimation> = 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<Texture>) {
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()
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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
}

View File

@ -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<Any> = listOf(),
) {
@Transient
lateinit var frames: Array<AnimationFrame>
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<AnimationFrame> = 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()
}
}

View File

@ -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
)