player light

This commit is contained in:
Moritz Zwerger 2023-10-28 20:00:10 +02:00
parent d1b8dc18c7
commit b0d143943b
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
18 changed files with 108 additions and 68 deletions

View File

@ -115,7 +115,8 @@ class ChunkLight(val chunk: Chunk) {
chunk.minSection - 1 -> bottom[index].toInt()
chunk.maxSection + 1 -> return top[index].toInt() or SectionLight.SKY_LIGHT_MASK // top has always sky=15
else -> chunk[sectionHeight]?.light?.get(index)?.toInt() ?: 0x00
}
} and 0xFF
if (y >= heightmap[heightmapIndex]) {
// set sky=15
return light or SectionLight.SKY_LIGHT_MASK

View File

@ -20,7 +20,7 @@ import de.bixilon.minosoft.gui.rendering.entities.renderer.EntityRenderer
import de.bixilon.minosoft.gui.rendering.skeletal.baked.BakedSkeletalModel
import de.bixilon.minosoft.gui.rendering.util.mat.mat4.Mat4Util.rotateRadAssign
abstract class BipedModel(renderer: EntityRenderer<*>, model: BakedSkeletalModel) : SkeletalFeature(renderer, model) {
abstract class BipedModel<R : EntityRenderer<*>>(renderer: R, model: BakedSkeletalModel) : SkeletalFeature(renderer, model) {
val head = instance.transform.children["head"]!!

View File

@ -13,23 +13,22 @@
package de.bixilon.minosoft.gui.rendering.entities.model.biped
import de.bixilon.kutil.cast.CastUtil.unsafeCast
import de.bixilon.minosoft.data.entities.entities.player.local.LocalPlayerEntity
import de.bixilon.minosoft.gui.rendering.entities.renderer.EntityRenderer
import de.bixilon.minosoft.gui.rendering.entities.renderer.player.PlayerRenderer
import de.bixilon.minosoft.gui.rendering.skeletal.baked.BakedSkeletalModel
import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTextureState
import de.bixilon.minosoft.gui.rendering.system.base.texture.skin.PlayerSkin
open class PlayerModel(
renderer: EntityRenderer<*>,
renderer: PlayerRenderer<*>,
model: BakedSkeletalModel,
val skin: PlayerSkin,
) : BipedModel(renderer, model) {
) : BipedModel<PlayerRenderer<*>>(renderer, model) {
override val shader get() = manager.playerShader
override fun draw() {
val renderer = this.renderer.unsafeCast<PlayerRenderer<*>>()
manager.context.system.reset(faceCulling = renderer.entity is LocalPlayerEntity) // TODO: and !renderSelf
shader.use()
shader.texture = if (skin.texture.state == DynamicTextureState.LOADED) skin.texture.shaderId else 0 // TODO: use default skins if not loaded yet
shader.texture = renderer.skin?.shaderId ?: renderer.renderer.context.textures.debugTexture.shaderId
shader.light = renderer.light.value
manager.upload(instance)
instance.model.mesh.draw()

View File

@ -15,9 +15,9 @@ package de.bixilon.minosoft.gui.rendering.entities.renderer.player
import de.bixilon.kutil.observer.DataObserver.Companion.observe
import de.bixilon.minosoft.data.entities.entities.player.local.LocalPlayerEntity
import de.bixilon.minosoft.data.entities.entities.player.properties.textures.metadata.SkinModel
import de.bixilon.minosoft.gui.rendering.entities.EntitiesRenderer
import de.bixilon.minosoft.gui.rendering.entities.model.biped.PlayerModel
import de.bixilon.minosoft.gui.rendering.system.base.texture.skin.PlayerSkin
open class LocalPlayerRenderer(renderer: EntitiesRenderer, entity: LocalPlayerEntity) : PlayerRenderer<LocalPlayerEntity>(renderer, entity) {
@ -25,7 +25,7 @@ open class LocalPlayerRenderer(renderer: EntitiesRenderer, entity: LocalPlayerEn
renderer.context.camera.view::view.observe(this, instant = true) { hitbox.enabled = it.renderSelf; model?.enabled = it.renderSelf }
}
override fun createModel(skin: PlayerSkin): PlayerModel? {
override fun createModel(skin: SkinModel): PlayerModel? {
val model = super.createModel(skin) ?: return null
model.enabled = renderer.context.camera.view.view.renderSelf
return model

View File

@ -25,56 +25,76 @@ import de.bixilon.minosoft.gui.rendering.entities.renderer.EntityRenderer
import de.bixilon.minosoft.gui.rendering.models.loader.ModelLoader
import de.bixilon.minosoft.gui.rendering.models.loader.SkeletalLoader.Companion.sModel
import de.bixilon.minosoft.gui.rendering.skeletal.baked.BakedSkeletalModel
import de.bixilon.minosoft.gui.rendering.system.base.texture.skin.PlayerSkin
import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTexture
import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTextureListener
import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTextureState
open class PlayerRenderer<E : PlayerEntity>(renderer: EntitiesRenderer, entity: E) : EntityRenderer<E>(renderer, entity) {
open class PlayerRenderer<E : PlayerEntity>(renderer: EntitiesRenderer, entity: E) : EntityRenderer<E>(renderer, entity), DynamicTextureListener {
protected var model: PlayerModel? = null
private var refreshSkin = true
var skin: DynamicTexture? = null
private var refresh = true
init {
entity.additional::properties.observe(this) { refreshSkin = true }
entity.additional::properties.observe(this) { refresh = true }
// TODO: observe entity layers?
}
override fun update(millis: Long) {
if (refreshSkin) updateModel()
if (refresh) updateModel()
super.update(millis)
}
private fun getSkin(): PlayerSkin? {
return renderer.context.textures.skins.getSkin(entity, fetch = false, async = true)
private fun setSkin(): SkinModel? {
val skin = renderer.context.textures.skins.getSkin(entity, fetch = false, async = true) ?: return null
this.skin?.removeListener(this)
if (skin.texture.state == DynamicTextureState.LOADED) {
this.skin = skin.texture
return skin.model
} else {
this.skin = skin.default
skin.texture.addListener(this)
}
return skin.model
}
private fun updateModel() {
this.model?.let { this.features -= it }
val model = createModel()
this.model = model
this.refreshSkin = false
this.refresh = false
if (model == null) return
this.features += model
}
private fun createModel(): PlayerModel? {
val skin = getSkin() ?: return null
val skin = setSkin() ?: return null
return createModel(skin)
}
protected open fun createModel(skin: PlayerSkin): PlayerModel? {
protected open fun createModel(skin: SkinModel): PlayerModel? {
val model = getModel(skin) ?: return null
return PlayerModel(this, model, skin)
return PlayerModel(this, model)
}
private fun getModel(skin: PlayerSkin): BakedSkeletalModel? {
val name = when (skin.model) {
private fun getModel(skin: SkinModel): BakedSkeletalModel? {
val name = when (skin) {
SkinModel.WIDE -> WIDE
SkinModel.SLIM -> SLIM
}
return renderer.context.models.skeletal[WIDE] // TODO: implement both models and use accordingly
}
override fun onDynamicTextureChange(texture: DynamicTexture): Boolean {
if (texture.state != DynamicTextureState.LOADED) return false
this.skin = texture
return true
}
companion object : RegisteredEntityModelFactory<PlayerEntity>, Identified {
override val identifier get() = PlayerEntity.identifier

View File

@ -21,8 +21,8 @@ import de.bixilon.minosoft.gui.rendering.gui.elements.Element
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.dynamic.DynamicStateChangeCallback
import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTexture
import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTextureListener
import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicTextureState
import de.bixilon.minosoft.gui.rendering.system.base.texture.shader.ShaderTexture
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2Util.EMPTY
@ -35,7 +35,7 @@ open class DynamicImageElement(
size: Vec2 = Vec2.EMPTY,
tint: RGBColor = ChatColors.WHITE,
parent: Element? = null,
) : Element(guiRenderer, GUIMesh.GUIMeshStruct.FLOATS_PER_VERTEX * 6), DynamicStateChangeCallback {
) : Element(guiRenderer, GUIMesh.GUIMeshStruct.FLOATS_PER_VERTEX * 6), DynamicTextureListener {
var texture: DynamicTexture? = null
set(value) {
@ -95,9 +95,11 @@ open class DynamicImageElement(
override fun forceSilentApply() = Unit
override fun silentApply(): Boolean = false
override fun onDynamicTextureChange(texture: DynamicTexture) {
override fun onDynamicTextureChange(texture: DynamicTexture): Boolean {
if (texture === this.texture) {
forceApply()
return false
}
return true
}
}

View File

@ -41,12 +41,12 @@ class GLSLShaderCode(
val lineReader = StringReader(line)
lineReader.skipWhitespaces()
val remaining = lineReader.peekRemaining() ?: continue
fun pushLine() {
code.append(line)
code.append(remaining)
code.append('\n')
}
val remaining = lineReader.peekRemaining() ?: continue
when {
remaining.startsWith("#include ") -> {
val reader = GLSLStringReader(remaining.removePrefix("#include "))
@ -71,6 +71,11 @@ class GLSLShaderCode(
code.append('\n')
}
}
remaining.startsWith("//") -> continue
remaining.startsWith("/*") -> continue
remaining.startsWith("*/") -> continue
remaining.startsWith("*") -> continue
else -> pushLine()
}
}

View File

@ -22,7 +22,7 @@ import de.bixilon.minosoft.gui.rendering.system.base.texture.shader.ShaderTextur
abstract class DynamicTexture(
val identifier: Any,
) : ShaderTexture {
private val callbacks: MutableSet<DynamicStateChangeCallback> = mutableSetOf()
private val callbacks: MutableSet<DynamicTextureListener> = mutableSetOf()
private val lock = SimpleLock()
var data: MipmapTextureData? = null
@ -33,8 +33,12 @@ abstract class DynamicTexture(
}
field = value
lock.acquire()
for (callback in callbacks) {
ignoreAll { callback.onDynamicTextureChange(this) }
val iterator = callbacks.iterator()
for (callback in iterator) {
val remove = ignoreAll { callback.onDynamicTextureChange(this) } ?: continue
if (remove) {
iterator.remove()
}
}
lock.release()
}
@ -51,15 +55,15 @@ abstract class DynamicTexture(
return end ?: floatArrayOf(1.0f, 1.0f) // TODO: memory
}
operator fun plusAssign(callback: DynamicStateChangeCallback) = addListener(callback)
fun addListener(callback: DynamicStateChangeCallback) {
operator fun plusAssign(callback: DynamicTextureListener) = addListener(callback)
fun addListener(callback: DynamicTextureListener) {
lock.lock()
callbacks += callback
lock.unlock()
}
operator fun minusAssign(callback: DynamicStateChangeCallback) = removeListener(callback)
fun removeListener(callback: DynamicStateChangeCallback) {
operator fun minusAssign(callback: DynamicTextureListener) = removeListener(callback)
fun removeListener(callback: DynamicTextureListener) {
lock.lock()
callbacks -= callback
lock.unlock()

View File

@ -13,7 +13,7 @@
package de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic
fun interface DynamicStateChangeCallback {
fun interface DynamicTextureListener {
fun onDynamicTextureChange(texture: DynamicTexture)
fun onDynamicTextureChange(texture: DynamicTexture): Boolean
}

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2020-2022 Moritz Zwerger
* 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.
*
@ -18,5 +18,6 @@ import de.bixilon.minosoft.gui.rendering.system.base.texture.dynamic.DynamicText
class PlayerSkin(
val texture: DynamicTexture,
val default: DynamicTexture?,
val model: SkinModel,
)

View File

@ -51,7 +51,7 @@ class SkinManager(private val textureManager: TextureManager) {
private fun getSkin(uuid: UUID, properties: PlayerProperties?, async: Boolean = true): PlayerSkin? {
val texture = properties?.textures?.skin ?: return default[uuid]
return PlayerSkin(textureManager.dynamicTextures.pushRaw(texture.getHash(), async) { texture.read() }, texture.metadata.model)
return PlayerSkin(textureManager.dynamicTextures.pushRaw(texture.getHash(), async) { texture.read() }, default[uuid]?.texture, texture.metadata.model)
}
fun getSkin(player: PlayerEntity, properties: PlayerProperties? = null, fetch: Boolean = true, async: Boolean = true): PlayerSkin? {

View File

@ -58,7 +58,7 @@ class DefaultSkinProvider(
this[skin.model][skin.name] = texture
if (skin.fallback) {
this.fallback = PlayerSkin(texture, skin.model)
this.fallback = PlayerSkin(texture, texture, skin.model)
}
}
@ -88,7 +88,7 @@ class DefaultSkinProvider(
}
operator fun get(skin: DefaultSkin, model: SkinModel): PlayerSkin? {
return this[model][skin.name]?.let { PlayerSkin(it, model) }
return this[model][skin.name]?.let { PlayerSkin(it, null, model) }
}
operator fun get(uuid: UUID?): PlayerSkin? {

View File

@ -25,6 +25,7 @@ import de.bixilon.minosoft.gui.rendering.exceptions.ShaderLoadingException
import de.bixilon.minosoft.gui.rendering.system.base.buffer.uniform.UniformBuffer
import de.bixilon.minosoft.gui.rendering.system.base.shader.NativeShader
import de.bixilon.minosoft.gui.rendering.system.base.shader.code.glsl.GLSLShaderCode
import it.unimi.dsi.fastutil.ints.IntArrayList
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap
import org.lwjgl.opengl.GL11.GL_FALSE
import org.lwjgl.opengl.GL43.*
@ -40,7 +41,7 @@ class OpenGLNativeShader(
override var loaded: Boolean = false
private set
override val defines: MutableMap<String, Any> = mutableMapOf()
private var shader = -1
private var handler = -1
private val uniformLocations: Object2IntOpenHashMap<String> = Object2IntOpenHashMap()
private fun load(resourceLocation: ResourceLocation, shaderType: Int): Int {
@ -66,13 +67,13 @@ class OpenGLNativeShader(
}
override fun load() {
shader = glCreateProgram()
handler = glCreateProgram()
if (shader.toLong() == MemoryUtil.NULL) {
if (handler.toLong() == MemoryUtil.NULL) {
throw ShaderLoadingException()
}
val programs: MutableList<Int> = mutableListOf()
val programs = IntArrayList(3)
programs += load(vertex, GL_VERTEX_SHADER)
@ -83,15 +84,15 @@ class OpenGLNativeShader(
programs += load(fragment, GL_FRAGMENT_SHADER)
for (program in programs) {
glAttachShader(shader, program)
glAttachShader(handler, program)
}
glLinkProgram(shader)
glLinkProgram(handler)
glValidateProgram(shader)
glValidateProgram(handler)
if (glGetProgrami(shader, GL_LINK_STATUS) == GL_FALSE) {
throw ShaderLoadingException(getProgramInfoLog(shader))
if (glGetProgrami(handler, GL_LINK_STATUS) == GL_FALSE) {
throw ShaderLoadingException(getProgramInfoLog(handler))
}
for (program in programs) {
glDeleteShader(program)
@ -103,9 +104,9 @@ class OpenGLNativeShader(
override fun unload() {
check(loaded) { "Not loaded!" }
glDeleteProgram(this.shader)
glDeleteProgram(this.handler)
loaded = false
this.shader = -1
this.handler = -1
context.system.nativeShaders -= this
}
@ -117,7 +118,7 @@ class OpenGLNativeShader(
private fun getUniformLocation(uniformName: String): Int {
val location = uniformLocations.getOrPut(uniformName) {
val location = glGetUniformLocation(shader, uniformName)
val location = glGetUniformLocation(handler, uniformName)
if (location < 0) {
throw IllegalArgumentException("No uniform named $uniformName in $this")
}
@ -192,17 +193,17 @@ class OpenGLNativeShader(
override fun setUniformBuffer(uniformName: String, uniformBuffer: UniformBuffer) {
val index = uniformLocations.getOrPut(uniformName) {
val index = glGetUniformBlockIndex(shader, uniformName)
val index = glGetUniformBlockIndex(handler, uniformName)
if (index < 0) {
throw IllegalArgumentException("No uniform buffer called $uniformName")
}
return@getOrPut index
}
glUniformBlockBinding(shader, index, uniformBuffer.bindingIndex)
glUniformBlockBinding(handler, index, uniformBuffer.bindingIndex)
}
fun unsafeUse() {
glUseProgram(shader)
glUseProgram(handler)
}
override val log: String

View File

@ -24,16 +24,16 @@ out vec4 foutColor;
in vec4 finTintColor;
// flat in bool finSkinLayer;
flat in uint finSkinLayer;
flat in uint finTextureIndex;
in vec3 finTextureCoordinates;
void main() {
foutColor = getTexture(finTextureIndex, finTextureCoordinates);
// if (finSkinLayer) {
// if (foutColor.a < 0.5) discard;
// }
foutColor = getTexture(finTextureIndex, finTextureCoordinates) * finTintColor;
if (finSkinLayer > 0u) {
if (foutColor.a < 0.5f) discard;
}
foutColor.a = 1.0f;
set_fog();
}

View File

@ -23,7 +23,7 @@ out vec3 finFragmentPosition;
uniform uint uIndexLayer;
uniform uint uLight;
// flat out bool finSkinLayer;
flat out uint finSkinLayer;
flat out uint finTextureIndex;
out vec3 finTextureCoordinates;
@ -31,12 +31,16 @@ out vec3 finTextureCoordinates;
out vec4 finTintColor;
#include "minosoft:skeletal/vertex"
#include "minosoft:color"
void main() {
uint partTransformNormal = floatBitsToUint(vinPartTransformNormal);
run_skeletal(partTransformNormal, vinPosition);
// finSkinLayer = (partTransformNormal >> 13u & 0x07u) > 0u;
finTintColor = getRGBColor(uLight);
finSkinLayer = (partTransformNormal >> 13u & 0x07u);
vec4 light = getRGBColor(uLight & 0xFFFFFFu);
finTintColor *= light;
finTextureIndex = uIndexLayer >> 28u;
finTextureCoordinates = vec3(vinUV, ((uIndexLayer >> 12) & 0xFFFFu));

View File

@ -15,6 +15,7 @@
vec4 getRGBColor(uint color) {
return vec4(((color >> 16u) & 0xFFu) / 255.0f, ((color >> 8u) & 0xFFu) / 255.0f, (color & 0xFFu) / 255.0f, 1.0f);
}
vec4 getRGBAColor(uint color) {
return vec4(((color >> 24u) & 0xFFu) / 255.0f, ((color >> 16u) & 0xFFu) / 255.0f, ((color >> 8u) & 0xFFu) / 255.0f, (color & 0xFFu) / 255.0f);
}

View File

@ -16,8 +16,6 @@ uniform mat4 uViewProjectionMatrix;
#include "minosoft:skeletal/buffer"
#include "minosoft:skeletal/shade"
uniform uint uLight;
#include "minosoft:light"
void run_skeletal(uint inTransformNormal, vec3 inPosition) {
mat4 transform = uSkeletalTransforms[(inTransformNormal >> 12u) & 0x7Fu];
@ -25,6 +23,6 @@ void run_skeletal(uint inTransformNormal, vec3 inPosition) {
gl_Position = uViewProjectionMatrix * position;
vec3 normal = transformNormal(decodeNormal(inTransformNormal & 0xFFFu), transform);
finTintColor = getLight(uLight & 0xFFu) * vec4(vec3(getShade(normal)), 1.0f);
finTintColor = vec4(vec3(getShade(normal)), 1.0f);
finFragmentPosition = position.xyz;
}

View File

@ -25,9 +25,13 @@ layout (location = 3) in float vinIndexLayerAnimation;// texture index (0xF00000
#include "minosoft:animation/buffer"
#include "minosoft:animation/main_vertex"
uniform uint uLight;
#include "minosoft:light"
void main() {
run_skeletal(floatBitsToUint(vinTransformNormal), vinPosition);
run_animation();
finTintColor *= getLight(uLight & 0xFFu);
}