mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-19 12:25:12 -04:00
improve dynamic texture change callbacks, improve skeletal system, improve player rendering
This commit is contained in:
parent
00dca558a6
commit
c444b9f25f
@ -86,9 +86,8 @@ abstract class Entity(
|
||||
open val uuid: UUID?
|
||||
get() = connection.world.entities.getUUID(this)
|
||||
|
||||
@JvmField
|
||||
@Deprecated(message = "Use connection.version")
|
||||
protected val versionId: Int = connection.version.versionId
|
||||
@Deprecated(message = "Use connection.version", replaceWith = ReplaceWith("connection.version.versionId"))
|
||||
protected val versionId: Int get() = connection.version.versionId
|
||||
open var _attachedEntity: Int? = null
|
||||
|
||||
var vehicle: Entity? = null
|
||||
|
@ -20,13 +20,19 @@ import de.bixilon.minosoft.gui.rendering.entity.models.SkeletalEntityModel
|
||||
import de.bixilon.minosoft.gui.rendering.models.ModelLoader.Companion.bbModel
|
||||
import de.bixilon.minosoft.gui.rendering.skeletal.instance.SkeletalInstance
|
||||
import de.bixilon.minosoft.gui.rendering.skeletal.model.elements.SkeletalElement
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicStateChangeCallback
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTexture
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTextureState
|
||||
import de.bixilon.minosoft.protocol.packets.c2s.play.SettingsC2SP
|
||||
import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
||||
|
||||
open class PlayerModel(renderer: EntityRenderer, player: PlayerEntity) : SkeletalEntityModel<PlayerEntity>(renderer, player) {
|
||||
open class PlayerModel(renderer: EntityRenderer, player: PlayerEntity) : SkeletalEntityModel<PlayerEntity>(renderer, player), DynamicStateChangeCallback {
|
||||
open val skinParts: Set<SettingsC2SP.SkinParts> = player.getSkinParts()
|
||||
private var skin: DynamicTexture? = null
|
||||
protected var refreshModel = false
|
||||
|
||||
override val instance = createModel()
|
||||
private var _instance: SkeletalInstance? = null
|
||||
override var instance = createModel()
|
||||
|
||||
private fun createModel(): SkeletalInstance {
|
||||
val unbaked = renderWindow.modelLoader.entities.loadUnbakedModel(BB_MODEL)
|
||||
@ -41,12 +47,32 @@ open class PlayerModel(renderer: EntityRenderer, player: PlayerEntity) : Skeleta
|
||||
}
|
||||
elements += element
|
||||
}
|
||||
val texture = renderWindow.textureManager.getSkin(entity)
|
||||
val model = unbaked.copy(elements = elements).bake(renderWindow, mutableMapOf(0 to texture))
|
||||
val skin = renderWindow.textureManager.getSkin(entity)
|
||||
skin.usages.incrementAndGet()
|
||||
this.skin?.usages?.decrementAndGet()
|
||||
this.skin = skin
|
||||
skin.callbacks += this
|
||||
|
||||
val model = unbaked.copy(elements = elements).bake(renderWindow, mutableMapOf(0 to skin))
|
||||
|
||||
return SkeletalInstance(renderWindow, Vec3i(), model)
|
||||
}
|
||||
|
||||
override fun prepareAsync() {
|
||||
if (refreshModel) {
|
||||
_instance = instance
|
||||
instance = createModel()
|
||||
refreshModel = false
|
||||
}
|
||||
super.prepareAsync()
|
||||
}
|
||||
|
||||
override fun prepare() {
|
||||
_instance?.unload()
|
||||
_instance = null
|
||||
super.prepare()
|
||||
}
|
||||
|
||||
private fun SkeletalElement.skinCopy(parts: Set<SettingsC2SP.SkinParts>, part: SettingsC2SP.SkinParts): SkeletalElement {
|
||||
if (part in parts) {
|
||||
return this
|
||||
@ -54,6 +80,12 @@ open class PlayerModel(renderer: EntityRenderer, player: PlayerEntity) : Skeleta
|
||||
return this.copy(visible = false)
|
||||
}
|
||||
|
||||
override fun onStateChange(texture: DynamicTexture, state: DynamicTextureState) {
|
||||
if (skin === texture) {
|
||||
refreshModel = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
private val BB_MODEL = "minecraft:entities/player/steve".toResourceLocation().bbModel()
|
||||
|
@ -23,6 +23,7 @@ import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMesh
|
||||
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
|
||||
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.ShaderIdentifiable
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicStateChangeCallback
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTexture
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTextureState
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2Util.EMPTY
|
||||
@ -36,14 +37,14 @@ open class DynamicImageElement(
|
||||
size: Vec2i = Vec2i.EMPTY,
|
||||
tint: RGBColor = ChatColors.WHITE,
|
||||
parent: Element? = null,
|
||||
) : Element(guiRenderer, GUIMesh.GUIMeshStruct.FLOATS_PER_VERTEX * 6) {
|
||||
) : Element(guiRenderer, GUIMesh.GUIMeshStruct.FLOATS_PER_VERTEX * 6), DynamicStateChangeCallback {
|
||||
|
||||
var texture: DynamicTexture? = null
|
||||
set(value) {
|
||||
field?.usages?.decrementAndGet()
|
||||
field?.onStateChange = null
|
||||
field?.callbacks?.remove(this)
|
||||
value?.usages?.incrementAndGet()
|
||||
value?.onStateChange = { forceApply() }
|
||||
value?.callbacks?.add(this)
|
||||
field = value
|
||||
cacheUpToDate = false
|
||||
}
|
||||
@ -101,4 +102,10 @@ open class DynamicImageElement(
|
||||
protected fun finalize() {
|
||||
texture?.usages?.decrementAndGet()
|
||||
}
|
||||
|
||||
override fun onStateChange(texture: DynamicTexture, state: DynamicTextureState) {
|
||||
if (texture === this.texture) {
|
||||
forceApply()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,11 +19,12 @@ import de.bixilon.kotlinglm.vec3.Vec3
|
||||
import de.bixilon.minosoft.data.Axes
|
||||
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
||||
import de.bixilon.minosoft.gui.rendering.models.unbaked.ModelBakeUtil
|
||||
import de.bixilon.minosoft.gui.rendering.models.unbaked.element.UnbakedElement
|
||||
import de.bixilon.minosoft.gui.rendering.models.unbaked.element.UnbakedElement.Companion.BLOCK_RESOLUTION
|
||||
import de.bixilon.minosoft.gui.rendering.skeletal.SkeletalMesh
|
||||
import de.bixilon.minosoft.gui.rendering.skeletal.model.SkeletalModel
|
||||
import de.bixilon.minosoft.gui.rendering.skeletal.model.outliner.SkeletalOutliner
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.ShaderTexture
|
||||
import de.bixilon.minosoft.gui.rendering.util.mesh.Mesh
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.rotateAssign
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap
|
||||
@ -35,7 +36,6 @@ class BakedSkeletalModel(
|
||||
) {
|
||||
lateinit var mesh: SkeletalMesh
|
||||
|
||||
|
||||
private fun calculateOutlinerMapping(): Map<UUID, Int> {
|
||||
val mapping: Object2IntOpenHashMap<UUID> = Object2IntOpenHashMap()
|
||||
|
||||
@ -64,7 +64,7 @@ class BakedSkeletalModel(
|
||||
}
|
||||
|
||||
fun loadMesh(renderWindow: RenderWindow) {
|
||||
if (this::mesh.isInitialized) {
|
||||
if (this::mesh.isInitialized && mesh.state == Mesh.MeshStates.LOADED) {
|
||||
return
|
||||
}
|
||||
val mesh = SkeletalMesh(renderWindow, 1000)
|
||||
@ -76,7 +76,7 @@ class BakedSkeletalModel(
|
||||
if (!element.visible) {
|
||||
continue
|
||||
}
|
||||
val inflate = (element.inflate * 0.001f)
|
||||
val inflate = (element.inflate / BLOCK_RESOLUTION)
|
||||
for ((direction, face) in element.faces) {
|
||||
val positions = direction.getPositions(element.from.fromBlockCoordinates() - inflate, element.to.fromBlockCoordinates() + inflate)
|
||||
|
||||
@ -107,10 +107,14 @@ class BakedSkeletalModel(
|
||||
this.mesh = mesh
|
||||
}
|
||||
|
||||
fun unload() {
|
||||
mesh.unload()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun Vec3.fromBlockCoordinates(): Vec3 {
|
||||
return Vec3(this.x / UnbakedElement.BLOCK_RESOLUTION + 0.5f, this.y / UnbakedElement.BLOCK_RESOLUTION, this.z / UnbakedElement.BLOCK_RESOLUTION + 0.5f)
|
||||
return Vec3(this.x / BLOCK_RESOLUTION + 0.5f, this.y / BLOCK_RESOLUTION, this.z / BLOCK_RESOLUTION + 0.5f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -125,4 +125,8 @@ class SkeletalInstance(
|
||||
calculateTransform(skeletalTransform, animations, child, transforms)
|
||||
}
|
||||
}
|
||||
|
||||
fun unload() {
|
||||
model.unload()
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,6 @@
|
||||
|
||||
package de.bixilon.minosoft.gui.rendering.skeletal.model
|
||||
|
||||
import de.bixilon.kotlinglm.vec3.Vec3
|
||||
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
||||
import de.bixilon.minosoft.gui.rendering.skeletal.baked.BakedSkeletalModel
|
||||
import de.bixilon.minosoft.gui.rendering.skeletal.model.animations.SkeletalAnimation
|
||||
@ -23,14 +22,11 @@ import de.bixilon.minosoft.gui.rendering.skeletal.model.outliner.SkeletalOutline
|
||||
import de.bixilon.minosoft.gui.rendering.skeletal.model.resolution.SkeletalResolution
|
||||
import de.bixilon.minosoft.gui.rendering.skeletal.model.textures.SkeletalTexture
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.ShaderTexture
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.EMPTY
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
|
||||
|
||||
data class SkeletalModel(
|
||||
val meta: SkeletalMeta = SkeletalMeta(),
|
||||
val name: String = "empty",
|
||||
val geometryName: String = name,
|
||||
val visibleBox: Vec3 = Vec3.EMPTY,
|
||||
val resolution: SkeletalResolution = SkeletalResolution(),
|
||||
val elements: List<SkeletalElement> = emptyList(),
|
||||
val outliner: List<SkeletalOutliner> = emptyList(),
|
||||
|
@ -22,7 +22,6 @@ data class StaticSkeletalAnimation(
|
||||
val uuid: UUID,
|
||||
override val name: String,
|
||||
override val loop: AnimationLoops = AnimationLoops.LOOP,
|
||||
val override: Boolean = false,
|
||||
override val length: Float,
|
||||
val animators: Map<UUID, SkeletalAnimator>,
|
||||
) : SkeletalAnimation {
|
||||
|
@ -26,11 +26,8 @@ data class SkeletalElement(
|
||||
val name: String,
|
||||
val rescale: Boolean = false,
|
||||
val visible: Boolean = true,
|
||||
val locked: Boolean = false,
|
||||
val from: Vec3 = Vec3.EMPTY,
|
||||
val to: Vec3 = Vec3.ONE,
|
||||
val autouv: Int = 0,
|
||||
val color: Int = 0,
|
||||
val rotation: Vec3 = Vec3.EMPTY,
|
||||
val origin: Vec3 = Vec3.EMPTY,
|
||||
val uvOffset: Vec2 = Vec2.EMPTY,
|
||||
|
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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.model.meta
|
||||
|
||||
enum class ModelFormats {
|
||||
FREE,
|
||||
SKIN,
|
||||
;
|
||||
}
|
@ -15,6 +15,5 @@ package de.bixilon.minosoft.gui.rendering.skeletal.model.meta
|
||||
|
||||
data class SkeletalMeta(
|
||||
val formatVersion: String = "4.0",
|
||||
val modelFormat: String = "free", // ToDo: Enum
|
||||
val boxUV: Boolean = true,
|
||||
val modelFormat: ModelFormats = ModelFormats.FREE,
|
||||
)
|
||||
|
@ -22,14 +22,8 @@ import java.util.*
|
||||
data class SkeletalTexture(
|
||||
val path: String,
|
||||
val name: String,
|
||||
val folder: String = "",
|
||||
val namespace: String = ProtocolDefinition.DEFAULT_NAMESPACE,
|
||||
val id: Int,
|
||||
val particle: Boolean = true,
|
||||
val renderMode: String = "normal", // ToDo: enum
|
||||
val visible: Boolean = true,
|
||||
val mode: String = "bitmap", // ToDo: enum
|
||||
val saved: Boolean = true,
|
||||
val uuid: UUID,
|
||||
) {
|
||||
val resourceLocation = ResourceLocation(namespace, path).texture()
|
||||
|
@ -17,6 +17,7 @@ import de.bixilon.kotlinglm.vec2.Vec2
|
||||
import de.bixilon.kotlinglm.vec2.Vec2i
|
||||
import de.bixilon.minosoft.config.profile.profiles.account.AccountProfileManager
|
||||
import de.bixilon.minosoft.data.entities.entities.player.PlayerEntity
|
||||
import de.bixilon.minosoft.data.player.LocalPlayerEntity
|
||||
import de.bixilon.minosoft.data.player.properties.PlayerProperties
|
||||
import de.bixilon.minosoft.data.player.properties.textures.PlayerTexture.Companion.isSteve
|
||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||
@ -56,7 +57,6 @@ abstract class TextureManager {
|
||||
}
|
||||
|
||||
fun loadDefaultSkins(connection: PlayConnection) {
|
||||
// ToDo: For testing purposes only, they will be moved to static textures
|
||||
steveTexture = dynamicTextures.pushBuffer(UUID(0L, 0L)) { connection.assetsManager["minecraft:entity/steve".toResourceLocation().texture()].readTexture().second }.apply { usages.incrementAndGet() }
|
||||
alexTexture = dynamicTextures.pushBuffer(UUID(1L, 0L)) { connection.assetsManager["minecraft:entity/alex".toResourceLocation().texture()].readTexture().second }.apply { usages.incrementAndGet() }
|
||||
skin = getSkin(connection.account.supportsSkins, connection.account.uuid, connection.account.properties).apply { usages.incrementAndGet() }
|
||||
@ -86,6 +86,9 @@ abstract class TextureManager {
|
||||
}
|
||||
|
||||
fun getSkin(player: PlayerEntity): DynamicTexture {
|
||||
if (player is LocalPlayerEntity) {
|
||||
return skin
|
||||
}
|
||||
return getSkin(true, player.uuid ?: return steveTexture, player.tabListItem.properties)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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.system.base.texture.dynamic
|
||||
|
||||
interface DynamicStateChangeCallback {
|
||||
|
||||
fun onStateChange(texture: DynamicTexture, state: DynamicTextureState)
|
||||
}
|
@ -23,5 +23,5 @@ interface DynamicTexture : ShaderTexture {
|
||||
|
||||
val state: DynamicTextureState
|
||||
|
||||
var onStateChange: (() -> Unit)?
|
||||
var callbacks: MutableSet<DynamicStateChangeCallback>
|
||||
}
|
||||
|
@ -14,6 +14,8 @@
|
||||
package de.bixilon.minosoft.gui.rendering.system.opengl.texture.dynamic
|
||||
|
||||
import de.bixilon.kotlinglm.vec2.Vec2
|
||||
import de.bixilon.kutil.collections.CollectionUtil.synchronizedSetOf
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicStateChangeCallback
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTexture
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTextureState
|
||||
import java.nio.ByteBuffer
|
||||
@ -25,12 +27,17 @@ class OpenGLDynamicTexture(
|
||||
shaderId: Int,
|
||||
) : DynamicTexture {
|
||||
var data: Array<ByteBuffer>? = null
|
||||
override var onStateChange: (() -> Unit)? = null
|
||||
override var callbacks: MutableSet<DynamicStateChangeCallback> = synchronizedSetOf()
|
||||
override val usages = AtomicInteger()
|
||||
override var state: DynamicTextureState = DynamicTextureState.WAITING
|
||||
set(value) {
|
||||
if (field == value) {
|
||||
return
|
||||
}
|
||||
field = value
|
||||
onStateChange?.invoke()
|
||||
for (callback in callbacks) {
|
||||
callback.onStateChange(this, value)
|
||||
}
|
||||
}
|
||||
|
||||
override var shaderId: Int = shaderId
|
||||
|
Loading…
x
Reference in New Issue
Block a user