Updated render classes structure to be less alien

This commit is contained in:
DBotThePony 2023-09-06 00:04:48 +07:00
parent 370c93226b
commit ef838d52c2
Signed by: DBot
GPG Key ID: DCC23B5715498507
19 changed files with 137 additions and 391 deletions

View File

@ -1,21 +1,10 @@
package ru.dbotthepony.kstarbound.client package ru.dbotthepony.kstarbound.client
import it.unimi.dsi.fastutil.objects.ReferenceArraySet
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
import ru.dbotthepony.kstarbound.client.render.ConfiguredStaticMesh
import ru.dbotthepony.kstarbound.client.render.entity.EntityRenderer import ru.dbotthepony.kstarbound.client.render.entity.EntityRenderer
import ru.dbotthepony.kstarbound.client.render.LayeredRenderer import ru.dbotthepony.kstarbound.world.Chunk
import ru.dbotthepony.kstarbound.client.render.TileLayerList import ru.dbotthepony.kstarbound.world.ChunkPos
import ru.dbotthepony.kstarbound.defs.tile.LiquidDefinition
import ru.dbotthepony.kstarbound.world.*
import ru.dbotthepony.kstarbound.world.CHUNK_SIZEd
import ru.dbotthepony.kstarbound.world.api.ITileAccess
import ru.dbotthepony.kstarbound.world.entities.Entity import ru.dbotthepony.kstarbound.world.entities.Entity
import ru.dbotthepony.kvector.vector.Vector2d
import ru.dbotthepony.kvector.vector.Vector2f
import ru.dbotthepony.kvector.vector.Vector2i
import java.io.Closeable
import java.util.LinkedList
/** /**
* Псевдо zPos у фоновых тайлов * Псевдо zPos у фоновых тайлов
@ -70,6 +59,6 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
} }
override fun onEntityRemoved(entity: Entity) { override fun onEntityRemoved(entity: Entity) {
entityRenderers.remove(entity)!!.close() entityRenderers.remove(entity)
} }
} }

View File

@ -4,10 +4,10 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectFunction
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap
import it.unimi.dsi.fastutil.longs.LongArraySet import it.unimi.dsi.fastutil.longs.LongArraySet
import it.unimi.dsi.fastutil.objects.ReferenceArraySet import it.unimi.dsi.fastutil.objects.ReferenceArraySet
import ru.dbotthepony.kstarbound.client.render.ConfiguredStaticMesh import ru.dbotthepony.kstarbound.client.render.ConfiguredMesh
import ru.dbotthepony.kstarbound.client.render.LayeredRenderer import ru.dbotthepony.kstarbound.client.render.LayeredRenderer
import ru.dbotthepony.kstarbound.client.render.Mesh import ru.dbotthepony.kstarbound.client.render.Mesh
import ru.dbotthepony.kstarbound.client.render.TileLayerList import ru.dbotthepony.kstarbound.client.render.MultiMeshBuilder
import ru.dbotthepony.kstarbound.defs.tile.LiquidDefinition import ru.dbotthepony.kstarbound.defs.tile.LiquidDefinition
import ru.dbotthepony.kstarbound.math.roundTowardsNegativeInfinity import ru.dbotthepony.kstarbound.math.roundTowardsNegativeInfinity
import ru.dbotthepony.kstarbound.math.roundTowardsPositiveInfinity import ru.dbotthepony.kstarbound.math.roundTowardsPositiveInfinity
@ -51,23 +51,16 @@ class ClientWorld(
inner class RenderRegion(val x: Int, val y: Int) { inner class RenderRegion(val x: Int, val y: Int) {
inner class Layer(private val view: ITileAccess, private val isBackground: Boolean) { inner class Layer(private val view: ITileAccess, private val isBackground: Boolean) {
private val state get() = client.gl private val state get() = client.gl
private val layers = TileLayerList() val bakedMeshes = ArrayList<Pair<ConfiguredMesh<*>, Int>>()
val bakedMeshes = ArrayList<Pair<ConfiguredStaticMesh, Int>>()
var isDirty = true var isDirty = true
fun bake() { fun bake() {
if (!isDirty) return if (!isDirty) return
isDirty = false isDirty = false
if (state.isSameThread()) {
for (mesh in bakedMeshes) {
mesh.first.close()
}
}
bakedMeshes.clear() bakedMeshes.clear()
layers.clear() val meshes = MultiMeshBuilder()
for (x in 0 until renderRegionWidth) { for (x in 0 until renderRegionWidth) {
for (y in 0 until renderRegionHeight) { for (y in 0 until renderRegionHeight) {
@ -77,30 +70,22 @@ class ClientWorld(
val material = tile.material val material = tile.material
if (material != null) { if (material != null) {
client.tileRenderers.getTileRenderer(material.materialName).tesselate(tile, view, layers, Vector2i(x, y), background = isBackground) client.tileRenderers.getMaterialRenderer(material.materialName).tesselate(tile, view, meshes, Vector2i(x, y), background = isBackground)
} }
val modifier = tile.modifier val modifier = tile.modifier
if (modifier != null) { if (modifier != null) {
client.tileRenderers.getModifierRenderer(modifier.modName).tesselate(tile, view, layers, Vector2i(x, y), background = isBackground, isModifier = true) client.tileRenderers.getModifierRenderer(modifier.modName).tesselate(tile, view, meshes, Vector2i(x, y), background = isBackground, isModifier = true)
} }
} }
} }
if (layers.isNotEmpty) { for ((baked, builder, zLevel) in meshes.meshes()) {
for (mesh in bakedMeshes) { bakedMeshes.add(ConfiguredMesh(baked, Mesh(state, builder)) to zLevel)
mesh.first.close()
}
bakedMeshes.clear()
for ((baked, builder, zLevel) in layers.layers()) {
bakedMeshes.add(ConfiguredStaticMesh(baked, builder) to zLevel)
}
layers.clear()
} }
meshes.clear()
} }
} }
@ -150,7 +135,7 @@ class ClientWorld(
for ((baked, zLevel) in background.bakedMeshes) { for ((baked, zLevel) in background.bakedMeshes) {
layers.add(zLevel + Z_LEVEL_BACKGROUND) { layers.add(zLevel + Z_LEVEL_BACKGROUND) {
it.push().last().translateWithMultiplication(renderOrigin.x, renderOrigin.y) it.push().last().translateWithMultiplication(renderOrigin.x, renderOrigin.y)
baked.renderStacked(it) baked.render(it.last())
it.pop() it.pop()
} }
} }
@ -158,7 +143,7 @@ class ClientWorld(
for ((baked, zLevel) in foreground.bakedMeshes) { for ((baked, zLevel) in foreground.bakedMeshes) {
layers.add(zLevel) { layers.add(zLevel) {
it.push().last().translateWithMultiplication(renderOrigin.x, renderOrigin.y) it.push().last().translateWithMultiplication(renderOrigin.x, renderOrigin.y)
baked.renderStacked(it) baked.render(it.last())
it.pop() it.pop()
} }
} }

View File

@ -16,9 +16,7 @@ data class BlendFunc(
Func.ZERO Func.ZERO
) )
constructor( constructor(source: Func, destination: Func) : this(
source: Func, destination: Func
) : this(
source, source,
destination, destination,
source, source,

View File

@ -13,7 +13,7 @@ import org.lwjgl.opengl.GL45.glCheckNamedFramebufferStatus
import org.lwjgl.opengl.GL45.glNamedFramebufferTexture import org.lwjgl.opengl.GL45.glNamedFramebufferTexture
import org.lwjgl.opengl.GL46 import org.lwjgl.opengl.GL46
class GLFrameBuffer(val state: GLStateTracker) : AutoCloseable { class GLFrameBuffer(val state: GLStateTracker) {
init { init {
state.ensureSameThread() state.ensureSameThread()
} }
@ -22,6 +22,7 @@ class GLFrameBuffer(val state: GLStateTracker) : AutoCloseable {
init { init {
checkForGLError("Creating framebuffer") checkForGLError("Creating framebuffer")
state.registerCleanable(this, GL46::glDeleteFramebuffers, pointer)
} }
val isComplete: Boolean get() { val isComplete: Boolean get() {
@ -50,7 +51,6 @@ class GLFrameBuffer(val state: GLStateTracker) : AutoCloseable {
} }
fun reattachTexture(width: Int, height: Int, format: Int = GL_RGB) { fun reattachTexture(width: Int, height: Int, format: Int = GL_RGB) {
texture?.close()
texture = null texture = null
attachTexture(width, height, format) attachTexture(width, height, format)
} }
@ -76,17 +76,4 @@ class GLFrameBuffer(val state: GLStateTracker) : AutoCloseable {
state.readFramebuffer = null state.readFramebuffer = null
} }
} }
private val cleanable = state.registerCleanable(this, GL46::glDeleteFramebuffers, pointer)
var isValid = true
private set
override fun close() {
if (!isValid)
return
cleanable.clean()
texture?.close()
isValid = false
}
} }

View File

@ -29,7 +29,7 @@ private class GLTexturePropertyTracker(private val flag: Int, private var value:
} }
@Suppress("SameParameterValue") @Suppress("SameParameterValue")
class GLTexture2D(val state: GLStateTracker, val name: String = "<unknown>") : AutoCloseable { class GLTexture2D(val state: GLStateTracker, val name: String = "<unknown>") {
init { init {
state.ensureSameThread() state.ensureSameThread()
} }
@ -38,10 +38,9 @@ class GLTexture2D(val state: GLStateTracker, val name: String = "<unknown>") : A
init { init {
checkForGLError() checkForGLError()
state.registerCleanable(this, ::glDeleteTextures, pointer)
} }
private val cleanable = state.registerCleanable(this, ::glDeleteTextures, pointer)
var width = 0 var width = 0
private set private set
@ -269,23 +268,6 @@ class GLTexture2D(val state: GLStateTracker, val name: String = "<unknown>") : A
return this return this
} }
var isValid = true
private set
override fun close() {
state.ensureSameThread()
if (!isValid)
return
if (state.texture2D == this) {
state.texture2D = null
}
cleanable.clean()
isValid = false
}
companion object { companion object {
private val LOGGER = LogManager.getLogger() private val LOGGER = LogManager.getLogger()
} }

View File

@ -1,29 +1,24 @@
package ru.dbotthepony.kstarbound.client.gl package ru.dbotthepony.kstarbound.client.gl
import org.lwjgl.opengl.GL46.* import org.lwjgl.opengl.GL46.*
import java.io.Closeable
class VertexArrayObject(val state: GLStateTracker) : Closeable { class VertexArrayObject(val state: GLStateTracker) {
val pointer = glGenVertexArrays() val pointer = glGenVertexArrays()
init { init {
checkForGLError() checkForGLError()
state.registerCleanable(this, ::glDeleteVertexArrays, pointer)
} }
private val cleanable = state.registerCleanable(this, ::glDeleteVertexArrays, pointer)
fun bind(): VertexArrayObject { fun bind(): VertexArrayObject {
check(isValid) { "Tried to use NULL GLVertexArrayObject" }
return state.bind(this) return state.bind(this)
} }
fun unbind(): VertexArrayObject { fun unbind(): VertexArrayObject {
check(isValid) { "Tried to use NULL GLVertexArrayObject" }
return state.unbind(this) return state.unbind(this)
} }
fun attribute(position: Int, size: Int, type: Int, normalize: Boolean, stride: Int, offset: Long = 0L): VertexArrayObject { fun attribute(position: Int, size: Int, type: Int, normalize: Boolean, stride: Int, offset: Long = 0L): VertexArrayObject {
check(isValid) { "Tried to use NULL GLVertexArrayObject" }
state.ensureSameThread() state.ensureSameThread()
glVertexAttribPointer(position, size, type, normalize, stride, offset) glVertexAttribPointer(position, size, type, normalize, stride, offset)
checkForGLError() checkForGLError()
@ -31,27 +26,10 @@ class VertexArrayObject(val state: GLStateTracker) : Closeable {
} }
fun enableAttribute(position: Int): VertexArrayObject { fun enableAttribute(position: Int): VertexArrayObject {
check(isValid) { "Tried to use NULL GLVertexArrayObject" }
state.ensureSameThread() state.ensureSameThread()
glEnableVertexArrayAttrib(pointer, position) glEnableVertexArrayAttrib(pointer, position)
//glEnableVertexAttribArray(position) //glEnableVertexAttribArray(position)
checkForGLError() checkForGLError()
return this return this
} }
var isValid = true
private set
override fun close() {
state.ensureSameThread()
if (!isValid) return
if (state.VAO == this) {
state.VAO = null
}
cleanable.clean()
isValid = false
}
} }

View File

@ -2,7 +2,6 @@ package ru.dbotthepony.kstarbound.client.gl
import org.lwjgl.opengl.GL46.* import org.lwjgl.opengl.GL46.*
import org.lwjgl.system.MemoryUtil import org.lwjgl.system.MemoryUtil
import java.io.Closeable
import java.nio.ByteBuffer import java.nio.ByteBuffer
enum class VBOType(val glType: Int) { enum class VBOType(val glType: Int) {
@ -10,32 +9,28 @@ enum class VBOType(val glType: Int) {
ELEMENT_ARRAY(GL_ELEMENT_ARRAY_BUFFER), ELEMENT_ARRAY(GL_ELEMENT_ARRAY_BUFFER),
} }
class VertexBufferObject(val state: GLStateTracker, val type: VBOType = VBOType.ARRAY) : Closeable { class VertexBufferObject(val state: GLStateTracker, val type: VBOType = VBOType.ARRAY) {
val pointer = glGenBuffers() val pointer = glGenBuffers()
init { init {
checkForGLError("Creating Vertex Buffer Object") checkForGLError("Creating Vertex Buffer Object")
state.registerCleanable(this, ::glDeleteBuffers, pointer)
} }
private val cleanable = state.registerCleanable(this, ::glDeleteBuffers, pointer)
val isArray get() = type == VBOType.ARRAY val isArray get() = type == VBOType.ARRAY
val isElementArray get() = type == VBOType.ELEMENT_ARRAY val isElementArray get() = type == VBOType.ELEMENT_ARRAY
fun bind(): VertexBufferObject { fun bind(): VertexBufferObject {
check(isValid) { "Tried to use NULL GLVertexBufferObject" }
state.bind(this) state.bind(this)
return this return this
} }
fun unbind(): VertexBufferObject { fun unbind(): VertexBufferObject {
check(isValid) { "Tried to use NULL GLVertexBufferObject" }
state.unbind(this) state.unbind(this)
return this return this
} }
fun bufferData(data: ByteBuffer, usage: Int): VertexBufferObject { fun bufferData(data: ByteBuffer, usage: Int): VertexBufferObject {
check(isValid) { "Tried to use NULL GLVertexBufferObject" }
state.ensureSameThread() state.ensureSameThread()
glNamedBufferData(pointer, data, usage) glNamedBufferData(pointer, data, usage)
checkForGLError() checkForGLError()
@ -43,7 +38,6 @@ class VertexBufferObject(val state: GLStateTracker, val type: VBOType = VBOType.
} }
fun bufferData(data: ByteBuffer, usage: Int, length: Long): VertexBufferObject { fun bufferData(data: ByteBuffer, usage: Int, length: Long): VertexBufferObject {
check(isValid) { "Tried to use NULL GLVertexBufferObject" }
state.ensureSameThread() state.ensureSameThread()
if (length > data.remaining().toLong()) { if (length > data.remaining().toLong()) {
@ -57,7 +51,6 @@ class VertexBufferObject(val state: GLStateTracker, val type: VBOType = VBOType.
} }
fun bufferData(data: IntArray, usage: Int): VertexBufferObject { fun bufferData(data: IntArray, usage: Int): VertexBufferObject {
check(isValid) { "Tried to use NULL GLVertexBufferObject" }
state.ensureSameThread() state.ensureSameThread()
glNamedBufferData(pointer, data, usage) glNamedBufferData(pointer, data, usage)
checkForGLError() checkForGLError()
@ -65,7 +58,6 @@ class VertexBufferObject(val state: GLStateTracker, val type: VBOType = VBOType.
} }
fun bufferData(data: FloatArray, usage: Int): VertexBufferObject { fun bufferData(data: FloatArray, usage: Int): VertexBufferObject {
check(isValid) { "Tried to use NULL GLVertexBufferObject" }
state.ensureSameThread() state.ensureSameThread()
glNamedBufferData(pointer, data, usage) glNamedBufferData(pointer, data, usage)
checkForGLError() checkForGLError()
@ -73,7 +65,6 @@ class VertexBufferObject(val state: GLStateTracker, val type: VBOType = VBOType.
} }
fun bufferData(data: DoubleArray, usage: Int): VertexBufferObject { fun bufferData(data: DoubleArray, usage: Int): VertexBufferObject {
check(isValid) { "Tried to use NULL GLVertexBufferObject" }
state.ensureSameThread() state.ensureSameThread()
glNamedBufferData(pointer, data, usage) glNamedBufferData(pointer, data, usage)
checkForGLError() checkForGLError()
@ -81,27 +72,9 @@ class VertexBufferObject(val state: GLStateTracker, val type: VBOType = VBOType.
} }
fun bufferData(data: LongArray, usage: Int): VertexBufferObject { fun bufferData(data: LongArray, usage: Int): VertexBufferObject {
check(isValid) { "Tried to use NULL GLVertexBufferObject" }
state.ensureSameThread() state.ensureSameThread()
glNamedBufferData(pointer, data, usage) glNamedBufferData(pointer, data, usage)
checkForGLError() checkForGLError()
return this return this
} }
var isValid = true
private set
override fun close() {
state.ensureSameThread()
if (!isValid) return
if (state.VBO == this) {
state.VBO = null
}
cleanable.clean()
isValid = false
}
} }

View File

@ -7,6 +7,7 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
import org.lwjgl.opengl.GL46.* import org.lwjgl.opengl.GL46.*
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
import ru.dbotthepony.kstarbound.client.gl.checkForGLError import ru.dbotthepony.kstarbound.client.gl.checkForGLError
import ru.dbotthepony.kstarbound.client.gl.vertex.GLAttributeList
import ru.dbotthepony.kvector.api.IStruct2f import ru.dbotthepony.kvector.api.IStruct2f
import ru.dbotthepony.kvector.api.IStruct3f import ru.dbotthepony.kvector.api.IStruct3f
import ru.dbotthepony.kvector.api.IStruct4f import ru.dbotthepony.kvector.api.IStruct4f
@ -22,7 +23,11 @@ import kotlin.NoSuchElementException
import kotlin.properties.ReadWriteProperty import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
open class GLShaderProgram(val state: GLStateTracker, shaders: Iterable<GLStateTracker.Shader>) { open class GLShaderProgram(
val state: GLStateTracker,
shaders: Iterable<GLStateTracker.Shader>,
val attributes: GLAttributeList
) {
init { init {
state.ensureSameThread() state.ensureSameThread()
} }

View File

@ -22,7 +22,7 @@ private fun GLStateTracker.gshaders(name: String): List<GLStateTracker.Shader> {
) )
} }
class GLLiquidProgram(state: GLStateTracker) : GLShaderProgram(state, state.shaders("liquid")) { class GLLiquidProgram(state: GLStateTracker) : GLShaderProgram(state, state.shaders("liquid"), FORMAT) {
var baselineColor by F4Uniform("baselineColor") var baselineColor by F4Uniform("baselineColor")
var transform by F4x4Uniform("transform") var transform by F4x4Uniform("transform")
@ -35,7 +35,7 @@ class GLLiquidProgram(state: GLStateTracker) : GLShaderProgram(state, state.shad
} }
} }
class GLLightProgram(state: GLStateTracker) : GLShaderProgram(state, state.shaders("light")) { class GLLightProgram(state: GLStateTracker) : GLShaderProgram(state, state.shaders("light"), FORMAT) {
var baselineColor by F4Uniform("baselineColor") var baselineColor by F4Uniform("baselineColor")
var transform by F4x4Uniform("transform") var transform by F4x4Uniform("transform")
@ -48,7 +48,7 @@ class GLLightProgram(state: GLStateTracker) : GLShaderProgram(state, state.shade
} }
} }
class GLColorQuadProgram(state: GLStateTracker) : GLShaderProgram(state, state.shaders("screen_quad")) { class GLColorQuadProgram(state: GLStateTracker) : GLShaderProgram(state, state.shaders("screen_quad"), FORMAT) {
var color by F4Uniform("color") var color by F4Uniform("color")
private val builder by lazy { private val builder by lazy {
@ -94,7 +94,7 @@ class GLColorQuadProgram(state: GLStateTracker) : GLShaderProgram(state, state.s
} }
} }
class GLTextureQuadProgram(state: GLStateTracker) : GLShaderProgram(state, state.shaders("screen_quad_tex")) { class GLTextureQuadProgram(state: GLStateTracker) : GLShaderProgram(state, state.shaders("screen_quad_tex"), FORMAT) {
var texture by IUniform("texture0") var texture by IUniform("texture0")
private val builder by lazy { private val builder by lazy {
@ -118,7 +118,7 @@ class GLTextureQuadProgram(state: GLStateTracker) : GLShaderProgram(state, state
} }
} }
class GLTextureBlurredQuadProgram(state: GLStateTracker) : GLShaderProgram(state, state.shaders("screen_quad_tex_blur")) { class GLTextureBlurredQuadProgram(state: GLStateTracker) : GLShaderProgram(state, state.shaders("screen_quad_tex_blur"), FORMAT) {
var texture by IUniform("texture0") var texture by IUniform("texture0")
private val builder by lazy { private val builder by lazy {
@ -142,7 +142,7 @@ class GLTextureBlurredQuadProgram(state: GLStateTracker) : GLShaderProgram(state
} }
} }
class GLFlatColorProgram(state: GLStateTracker) : GLShaderProgram(state, state.shaders("flat_color")) { class GLFlatColorProgram(state: GLStateTracker) : GLShaderProgram(state, state.shaders("flat_color"), FORMAT) {
var transform by F4x4Uniform("transform") var transform by F4x4Uniform("transform")
val builder by lazy { val builder by lazy {
@ -154,7 +154,22 @@ class GLFlatColorProgram(state: GLStateTracker) : GLShaderProgram(state, state.s
} }
} }
class GLTileProgram(state: GLStateTracker) : GLShaderProgram(state, state.shaders("tile")) { class GLTileProgram(state: GLStateTracker) : GLShaderProgram(state, state.shaders("tile"), FORMAT) {
var transform by F4x4Uniform("transform")
var color by F4Uniform("color")
var texture by IUniform("texture0")
init {
transform = Matrix4f.identity()
color = RGBAColor.WHITE
}
companion object {
val FORMAT = GLAttributeList.Builder().push(GLType.VEC3F, GLType.VEC2F, GLType.FLOAT).build()
}
}
class GLFontProgram(state: GLStateTracker) : GLShaderProgram(state, state.shaders("font"), GLAttributeList.VERTEX_2D_TEXTURE) {
var transform by F4x4Uniform("transform") var transform by F4x4Uniform("transform")
var color by F4Uniform("color") var color by F4Uniform("color")
var texture by IUniform("texture0") var texture by IUniform("texture0")
@ -165,18 +180,7 @@ class GLTileProgram(state: GLStateTracker) : GLShaderProgram(state, state.shader
} }
} }
class GLFontProgram(state: GLStateTracker) : GLShaderProgram(state, state.shaders("font")) { class GLFlatProgram(state: GLStateTracker) : GLShaderProgram(state, state.shaders("flat"), GLAttributeList.VEC2F) {
var transform by F4x4Uniform("transform")
var color by F4Uniform("color")
var texture by IUniform("texture0")
init {
transform = Matrix4f.identity()
color = RGBAColor.WHITE
}
}
class GLFlatProgram(state: GLStateTracker) : GLShaderProgram(state, state.shaders("flat")) {
var transform by F4x4Uniform("transform") var transform by F4x4Uniform("transform")
var color by F4Uniform("color") var color by F4Uniform("color")
@ -185,7 +189,7 @@ class GLFlatProgram(state: GLStateTracker) : GLShaderProgram(state, state.shader
} }
} }
class GLTexturedProgram(state: GLStateTracker) : GLShaderProgram(state, listOf(state.internalVertex("shaders/vertex/texture.glsl"), state.internalFragment("shaders/fragment/texture.glsl"))) { class GLTexturedProgram(state: GLStateTracker) : GLShaderProgram(state, listOf(state.internalVertex("shaders/vertex/texture.glsl"), state.internalFragment("shaders/fragment/texture.glsl")), GLAttributeList.VERTEX_TEXTURE) {
var transform by F4x4Uniform("transform") var transform by F4x4Uniform("transform")
var texture by IUniform("texture0") var texture by IUniform("texture0")
@ -194,7 +198,7 @@ class GLTexturedProgram(state: GLStateTracker) : GLShaderProgram(state, listOf(s
} }
} }
class GLTexturedColoredProgram(state: GLStateTracker) : GLShaderProgram(state, listOf(state.internalVertex("shaders/vertex/texture.glsl"), state.internalFragment("shaders/fragment/texture_color.glsl"))) { class GLTexturedColoredProgram(state: GLStateTracker) : GLShaderProgram(state, listOf(state.internalVertex("shaders/vertex/texture.glsl"), state.internalFragment("shaders/fragment/texture_color.glsl")), GLAttributeList.VERTEX_TEXTURE) {
var transform by F4x4Uniform("transform") var transform by F4x4Uniform("transform")
var texture by IUniform("texture0") var texture by IUniform("texture0")
var color by F4Uniform("color") var color by F4Uniform("color")

View File

@ -83,12 +83,7 @@ class GLAttributeList(builder: Builder) {
companion object { companion object {
val VEC2F = Builder().push(GLType.VEC2F).build() val VEC2F = Builder().push(GLType.VEC2F).build()
val VEC3F = Builder().push(GLType.VEC3F).build()
val VERTEX_TEXTURE = Builder().push(GLType.VEC3F).push(GLType.VEC2F).build() val VERTEX_TEXTURE = Builder().push(GLType.VEC3F).push(GLType.VEC2F).build()
val VERTEX_2D_TEXTURE = Builder().push(GLType.VEC2F).push(GLType.VEC2F).build() val VERTEX_2D_TEXTURE = Builder().push(GLType.VEC2F).push(GLType.VEC2F).build()
val TILE = Builder().push(GLType.VEC3F, GLType.VEC2F, GLType.FLOAT).build()
} }
} }

View File

@ -3,7 +3,6 @@ package ru.dbotthepony.kstarbound.client.gl.vertex
import org.lwjgl.opengl.GL46 import org.lwjgl.opengl.GL46
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
import ru.dbotthepony.kstarbound.client.gl.checkForGLError import ru.dbotthepony.kstarbound.client.gl.checkForGLError
import java.io.Closeable
/** /**
* Быстрое наполнение буфера вершинами, загрузка в память видеокарты, и отрисовка * Быстрое наполнение буфера вершинами, загрузка в память видеокарты, и отрисовка
@ -13,7 +12,7 @@ class StreamVertexBuilder(
attributes: GLAttributeList, attributes: GLAttributeList,
type: GeometryType, type: GeometryType,
initialCapacity: Int = 64, initialCapacity: Int = 64,
) : Closeable { ) {
val builder = VertexBuilder(attributes, type, initialCapacity) val builder = VertexBuilder(attributes, type, initialCapacity)
private val vao = state.newVAO() private val vao = state.newVAO()
private val vbo = state.newVBO() private val vbo = state.newVBO()
@ -44,12 +43,6 @@ class StreamVertexBuilder(
checkForGLError() checkForGLError()
} }
override fun close() {
vao.close()
vbo.close()
ebo.close()
}
fun singleSprite(x: Float, y: Float, width: Float, height: Float, z: Float = 5f, angle: Double = 0.0, transformer: QuadVertexTransformer) { fun singleSprite(x: Float, y: Float, width: Float, height: Float, z: Float = 5f, angle: Double = 0.0, transformer: QuadVertexTransformer) {
builder.begin() builder.begin()

View File

@ -1,99 +0,0 @@
package ru.dbotthepony.kstarbound.client.render
import org.lwjgl.opengl.GL46.*
import ru.dbotthepony.kstarbound.client.gl.shader.GLShaderProgram
import ru.dbotthepony.kstarbound.client.gl.VertexArrayObject
import ru.dbotthepony.kstarbound.client.gl.checkForGLError
import ru.dbotthepony.kstarbound.client.gl.vertex.VertexBuilder
import ru.dbotthepony.kvector.arrays.Matrix4f
import ru.dbotthepony.kvector.arrays.Matrix4fStack
/**
* Служит для быстрой настройки состояния для будущей отрисовки
*
* Установка текстурных блоков, программы, самих текстур и загрузка юниформ должна осуществляться тут
*
* Класс обязан быть наследован для осмысленных результатов
*
* Ожидается, что состояние будет выставлено ПОЛНОСТЬЮ, т.е. НИКАКОЙ предыдущий код НЕ МОЖЕТ повлиять на результат выполнения
* шейдерной программы, которая связанна с этим объектом (за исключением не вызова [setTransform] внешним кодом)
*/
open class ConfiguredShaderProgram<T : GLShaderProgram>(
val program: T,
) {
private val transformLocation = program.getUniform("transform") as? GLShaderProgram.F4x4Uniform
open fun setTransform(value: Matrix4f) {
transformLocation?.value = value
}
/**
* Вызывается перед началом отрисовки
*/
open fun setup() {
program.use()
}
}
/**
* Запечённый статичный меш, позволяет быстро отрисовать меш со всеми параметрами
* с заданной матрицей трансформации
*/
class ConfiguredStaticMesh(
val programState: ConfiguredShaderProgram<*>,
val indexCount: Int,
val vao: VertexArrayObject,
val elementIndexType: Int,
) : AutoCloseable {
private var onClose = {}
constructor(programState: ConfiguredShaderProgram<*>, builder: VertexBuilder) : this(
programState,
builder.indexCount,
programState.program.state.newVAO(),
builder.indexType,
) {
val vbo = programState.program.state.newVBO()
val ebo = programState.program.state.newEBO()
onClose = {
vbo.close()
ebo.close()
}
vao.bind()
vbo.bind()
ebo.bind()
builder.upload(vbo, ebo, GL_STATIC_DRAW)
builder.attributes.apply(vao, true)
vao.unbind()
vbo.unbind()
ebo.unbind()
}
fun render(transform: Matrix4f? = null) {
check(isValid) { "$this is no longer valid" }
programState.setup()
if (transform != null) {
programState.setTransform(transform)
}
vao.bind()
glDrawElements(GL_TRIANGLES, indexCount, elementIndexType, 0L)
checkForGLError()
}
fun renderStacked(transform: Matrix4fStack) = render(transform.last())
var isValid = true
private set
override fun close() {
vao.close()
onClose.invoke()
isValid = false
}
}

View File

@ -244,7 +244,7 @@ class Font(
return size(breakLines(text)) return size(breakLines(text))
} }
private inner class Glyph(val char: Char) : AutoCloseable { private inner class Glyph(val char: Char) {
private val texture: GLTexture2D? private val texture: GLTexture2D?
val isEmpty: Boolean val isEmpty: Boolean
@ -349,13 +349,5 @@ class Font(
stack.last().translateWithMultiplication(advanceX - bearingX, bearingY) stack.last().translateWithMultiplication(advanceX - bearingX, bearingY)
} }
override fun close() {
vao?.close()
ebo?.close()
vbo?.close()
texture?.close()
}
} }
} }

View File

@ -3,7 +3,9 @@ package ru.dbotthepony.kstarbound.client.render
import org.lwjgl.opengl.GL46 import org.lwjgl.opengl.GL46
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
import ru.dbotthepony.kstarbound.client.gl.checkForGLError import ru.dbotthepony.kstarbound.client.gl.checkForGLError
import ru.dbotthepony.kstarbound.client.gl.shader.GLShaderProgram
import ru.dbotthepony.kstarbound.client.gl.vertex.VertexBuilder import ru.dbotthepony.kstarbound.client.gl.vertex.VertexBuilder
import ru.dbotthepony.kvector.arrays.Matrix4f
class Mesh(state: GLStateTracker) { class Mesh(state: GLStateTracker) {
constructor(state: GLStateTracker, builder: VertexBuilder) : this(state) { constructor(state: GLStateTracker, builder: VertexBuilder) : this(state) {
@ -39,5 +41,14 @@ class Mesh(state: GLStateTracker) {
vao.bind() vao.bind()
GL46.glDrawElements(GL46.GL_TRIANGLES, indexCount, indexType, 0L) GL46.glDrawElements(GL46.GL_TRIANGLES, indexCount, indexType, 0L)
checkForGLError() checkForGLError()
vao.unbind()
}
}
data class ConfiguredMesh<T : GLShaderProgram>(val config: RenderConfig<T>, val mesh: Mesh = Mesh(config.state)) {
fun render(transform: Matrix4f = config.state.matrixStack.last()) {
config.setup(transform)
mesh.render()
config.uninstall()
} }
} }

View File

@ -0,0 +1,29 @@
package ru.dbotthepony.kstarbound.client.render
import it.unimi.dsi.fastutil.ints.Int2ObjectFunction
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
import it.unimi.dsi.fastutil.objects.Reference2ObjectFunction
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
import ru.dbotthepony.kstarbound.client.gl.vertex.VertexBuilder
import java.util.stream.Stream
class MultiMeshBuilder {
data class Entry(val config: RenderConfig<*>, val builder: VertexBuilder, val layer: Int)
private val meshes = Reference2ObjectOpenHashMap<RenderConfig<*>, Int2ObjectOpenHashMap<Entry>>()
fun get(config: RenderConfig<*>, layer: Int): VertexBuilder {
return meshes.computeIfAbsent(config, Reference2ObjectFunction {
Int2ObjectOpenHashMap()
}).computeIfAbsent(layer, Int2ObjectFunction { Entry(config, VertexBuilder(config.program.attributes, GeometryType.QUADS), layer) }).builder
}
fun clear() = meshes.clear()
fun isEmpty() = meshes.isEmpty()
fun isNotEmpty() = meshes.isNotEmpty()
fun meshes(): Stream<Entry> {
return meshes.values.stream().flatMap { it.values.stream() }
}
}

View File

@ -0,0 +1,13 @@
package ru.dbotthepony.kstarbound.client.render
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
import ru.dbotthepony.kstarbound.client.gl.shader.GLShaderProgram
import ru.dbotthepony.kvector.arrays.Matrix4f
abstract class RenderConfig<out T : GLShaderProgram>(val state: GLStateTracker, val program: T) {
open fun setup(transform: Matrix4f = state.matrixStack.last()) {
program.use()
}
open fun uninstall() {}
}

View File

@ -1,54 +1,21 @@
package ru.dbotthepony.kstarbound.client.render package ru.dbotthepony.kstarbound.client.render
import it.unimi.dsi.fastutil.ints.Int2ObjectFunction
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import org.lwjgl.opengl.GL46.* import org.lwjgl.opengl.GL46.*
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
import ru.dbotthepony.kstarbound.client.StarboundClient import ru.dbotthepony.kstarbound.client.StarboundClient
import ru.dbotthepony.kstarbound.client.gl.* import ru.dbotthepony.kstarbound.client.gl.*
import ru.dbotthepony.kstarbound.client.gl.shader.GLTileProgram import ru.dbotthepony.kstarbound.client.gl.shader.GLTileProgram
import ru.dbotthepony.kstarbound.client.gl.vertex.GLAttributeList
import ru.dbotthepony.kstarbound.client.gl.vertex.* import ru.dbotthepony.kstarbound.client.gl.vertex.*
import ru.dbotthepony.kstarbound.defs.tile.* import ru.dbotthepony.kstarbound.defs.tile.*
import ru.dbotthepony.kstarbound.world.api.ITileAccess import ru.dbotthepony.kstarbound.world.api.ITileAccess
import ru.dbotthepony.kstarbound.world.api.ITileState import ru.dbotthepony.kstarbound.world.api.ITileState
import ru.dbotthepony.kstarbound.world.api.TileColor import ru.dbotthepony.kstarbound.world.api.TileColor
import ru.dbotthepony.kvector.arrays.Matrix4f
import ru.dbotthepony.kvector.vector.RGBAColor import ru.dbotthepony.kvector.vector.RGBAColor
import ru.dbotthepony.kvector.vector.Vector2i import ru.dbotthepony.kvector.vector.Vector2i
import java.util.stream.Stream
import kotlin.collections.HashMap import kotlin.collections.HashMap
data class TileLayer(
val program: ConfiguredShaderProgram<GLTileProgram>,
val vertices: VertexBuilder,
val zPos: Int
)
class TileLayerList {
private val layers = HashMap<ConfiguredShaderProgram<GLTileProgram>, Int2ObjectOpenHashMap<TileLayer>>()
/**
* Получает геометрию слоя ([DynamicVertexBuilder]), который имеет программу для отрисовки [program] и располагается на [zLevel].
*
* Если такого слоя нет, вызывается [compute] и создаётся новый [TileLayer], затем возвращается результат [compute].
*/
fun computeIfAbsent(program: ConfiguredShaderProgram<GLTileProgram>, zLevel: Int, compute: () -> VertexBuilder): VertexBuilder {
return layers.computeIfAbsent(program) { Int2ObjectOpenHashMap() }.computeIfAbsent(zLevel, Int2ObjectFunction {
return@Int2ObjectFunction TileLayer(program, compute.invoke(), zLevel)
}).vertices
}
fun layers(): Stream<TileLayer> {
return layers.values.stream().flatMap { it.values.stream() }
}
fun clear() = layers.clear()
val isEmpty get() = layers.isEmpty()
val isNotEmpty get() = layers.isNotEmpty()
}
/** /**
* Хранит в себе программы для отрисовки определённых [TileDefinition] * Хранит в себе программы для отрисовки определённых [TileDefinition]
* *
@ -56,28 +23,29 @@ class TileLayerList {
*/ */
class TileRenderers(val client: StarboundClient) { class TileRenderers(val client: StarboundClient) {
val state get() = client.gl val state get() = client.gl
private val foregroundTilePrograms = HashMap<GLTexture2D, ForegroundTileProgram>()
private val backgroundTilePrograms = HashMap<GLTexture2D, BackgroundTileProgram>()
private val tileRenderersCache = HashMap<String, TileRenderer>()
private val modifierRenderersCache = HashMap<String, TileRenderer>()
fun getTileRenderer(defName: String): TileRenderer { private val foreground = HashMap<GLTexture2D, Config>()
return tileRenderersCache.computeIfAbsent(defName) { private val background = HashMap<GLTexture2D, Config>()
private val matCache = HashMap<String, TileRenderer>()
private val modCache = HashMap<String, TileRenderer>()
fun getMaterialRenderer(defName: String): TileRenderer {
return matCache.computeIfAbsent(defName) {
val def = client.starbound.tiles[defName] // TODO: Пустой рендерер val def = client.starbound.tiles[defName] // TODO: Пустой рендерер
return@computeIfAbsent TileRenderer(this, def!!.value) return@computeIfAbsent TileRenderer(this, def!!.value)
} }
} }
fun getModifierRenderer(defName: String): TileRenderer { fun getModifierRenderer(defName: String): TileRenderer {
return modifierRenderersCache.computeIfAbsent(defName) { return modCache.computeIfAbsent(defName) {
val def = client.starbound.tileModifiers[defName] // TODO: Пустой рендерер val def = client.starbound.tileModifiers[defName] // TODO: Пустой рендерер
return@computeIfAbsent TileRenderer(this, def!!.value) return@computeIfAbsent TileRenderer(this, def!!.value)
} }
} }
private inner class ForegroundTileProgram(private val texture: GLTexture2D) : ConfiguredShaderProgram<GLTileProgram>(state.programs.tile) { private inner class Config(private val texture: GLTexture2D, private val color: RGBAColor) : RenderConfig<GLTileProgram>(state, state.programs.tile) {
override fun setup() { override fun setup(transform: Matrix4f) {
super.setup() super.setup(transform)
state.activeTexture = 0 state.activeTexture = 0
state.depthTest = false state.depthTest = false
program.texture = 0 program.texture = 0
@ -85,68 +53,19 @@ class TileRenderers(val client: StarboundClient) {
texture.textureMagFilter = GL_NEAREST texture.textureMagFilter = GL_NEAREST
texture.textureMinFilter = GL_NEAREST texture.textureMinFilter = GL_NEAREST
program.color = FOREGROUND_COLOR program.transform = transform
program.color = color
} }
override fun equals(other: Any?): Boolean { override fun uninstall() {}
if (this === other) {
return true
}
if (other is ForegroundTileProgram) {
return texture == other.texture
}
return super.equals(other)
}
override fun hashCode(): Int {
return texture.hashCode()
}
} }
private inner class BackgroundTileProgram(private val texture: GLTexture2D) : ConfiguredShaderProgram<GLTileProgram>(state.programs.tile) { fun foreground(texture: GLTexture2D): RenderConfig<GLTileProgram> {
override fun setup() { return foreground.computeIfAbsent(texture) { Config(it, FOREGROUND_COLOR) }
super.setup()
state.activeTexture = 0
state.depthTest = false
program.texture = 0
texture.bind()
texture.textureMagFilter = GL_NEAREST
texture.textureMinFilter = GL_NEAREST
program.color = BACKGROUND_COLOR
}
override fun equals(other: Any?): Boolean {
if (this === other) {
return true
}
if (other is BackgroundTileProgram) {
return texture == other.texture
}
return super.equals(other)
}
override fun hashCode(): Int {
return texture.hashCode()
}
} }
/** fun background(texture: GLTexture2D): RenderConfig<GLTileProgram> {
* Возвращает запечённое состояние шейдера shaderVertexTexture с данной текстурой return background.computeIfAbsent(texture) { Config(it, BACKGROUND_COLOR) }
*/
fun foreground(texture: GLTexture2D): ConfiguredShaderProgram<GLTileProgram> {
return foregroundTilePrograms.computeIfAbsent(texture, ::ForegroundTileProgram)
}
/**
* Возвращает запечённое состояние шейдера shaderVertexTextureRGBAColor с данной текстурой
*/
fun background(texture: GLTexture2D): ConfiguredShaderProgram<GLTileProgram> {
return backgroundTilePrograms.computeIfAbsent(texture, ::BackgroundTileProgram)
} }
companion object { companion object {
@ -155,8 +74,6 @@ class TileRenderers(val client: StarboundClient) {
} }
} }
private fun vertexTextureBuilder() = VertexBuilder(GLAttributeList.TILE, GeometryType.QUADS)
private class TileEqualityTester(val definition: TileDefinition) : EqualityRuleTester { private class TileEqualityTester(val definition: TileDefinition) : EqualityRuleTester {
override fun test(thisTile: ITileState?, otherTile: ITileState?): Boolean { override fun test(thisTile: ITileState?, otherTile: ITileState?): Boolean {
return otherTile?.material == definition && thisTile?.hueShift == otherTile.hueShift return otherTile?.material == definition && thisTile?.hueShift == otherTile.hueShift
@ -236,7 +153,7 @@ class TileRenderer(val renderers: TileRenderers, val def: IRenderableTile) {
self: ITileState, self: ITileState,
matchPiece: RenderMatch, matchPiece: RenderMatch,
getter: ITileAccess, getter: ITileAccess,
layers: TileLayerList, meshBuilder: MultiMeshBuilder,
pos: Vector2i, pos: Vector2i,
thisBuilder: VertexBuilder, thisBuilder: VertexBuilder,
background: Boolean, background: Boolean,
@ -251,14 +168,14 @@ class TileRenderer(val renderers: TileRenderers, val def: IRenderableTile) {
renderers.foreground(state.loadTexture(renderPiece.piece.texture!!)) renderers.foreground(state.loadTexture(renderPiece.piece.texture!!))
} }
tesselateAt(self, renderPiece.piece, getter, layers.computeIfAbsent(program, def.renderParameters.zLevel, ::vertexTextureBuilder), pos, renderPiece.offset, isModifier) tesselateAt(self, renderPiece.piece, getter, meshBuilder.get(program, def.renderParameters.zLevel), pos, renderPiece.offset, isModifier)
} else { } else {
tesselateAt(self, renderPiece.piece, getter, thisBuilder, pos, renderPiece.offset, isModifier) tesselateAt(self, renderPiece.piece, getter, thisBuilder, pos, renderPiece.offset, isModifier)
} }
} }
for (subPiece in matchPiece.subMatches) { for (subPiece in matchPiece.subMatches) {
val matched = tesselatePiece(self, subPiece, getter, layers, pos, thisBuilder, background, isModifier) val matched = tesselatePiece(self, subPiece, getter, meshBuilder, pos, thisBuilder, background, isModifier)
if (matched == TestResult.HALT || matched == TestResult.CONTINUE && matchPiece.haltOnSubMatch) { if (matched == TestResult.HALT || matched == TestResult.CONTINUE && matchPiece.haltOnSubMatch) {
return TestResult.HALT return TestResult.HALT
@ -280,20 +197,20 @@ class TileRenderer(val renderers: TileRenderers, val def: IRenderableTile) {
* *
* [getter] Нужен для получения информации о ближайших блоках * [getter] Нужен для получения информации о ближайших блоках
* *
* [layers] содержит текущие программы и их билдеры и их zPos * [meshBuilder] содержит текущие программы и их билдеры и их zPos
* *
* Тесселирует тайлы в нужный VertexBuilder с масштабом согласно константе [PIXELS_IN_STARBOUND_UNITf] * Тесселирует тайлы в нужный VertexBuilder с масштабом согласно константе [PIXELS_IN_STARBOUND_UNITf]
*/ */
fun tesselate(self: ITileState, getter: ITileAccess, layers: TileLayerList, pos: Vector2i, background: Boolean = false, isModifier: Boolean = false) { fun tesselate(self: ITileState, getter: ITileAccess, meshBuilder: MultiMeshBuilder, pos: Vector2i, background: Boolean = false, isModifier: Boolean = false) {
// если у нас нет renderTemplate // если у нас нет renderTemplate
// то мы просто не можем его отрисовать // то мы просто не можем его отрисовать
val template = def.renderTemplate.value ?: return val template = def.renderTemplate.value ?: return
val vertexBuilder = layers.computeIfAbsent(if (background) bakedBackgroundProgramState else bakedProgramState, def.renderParameters.zLevel, ::vertexTextureBuilder) val vertexBuilder = meshBuilder.get(if (background) bakedBackgroundProgramState else bakedProgramState, def.renderParameters.zLevel)
for ((_, matcher) in template.matches) { for ((_, matcher) in template.matches) {
for (matchPiece in matcher) { for (matchPiece in matcher) {
val matched = tesselatePiece(self, matchPiece, getter, layers, pos, vertexBuilder, background, isModifier) val matched = tesselatePiece(self, matchPiece, getter, meshBuilder, pos, vertexBuilder, background, isModifier)
if (matched == TestResult.HALT) { if (matched == TestResult.HALT) {
break break

View File

@ -7,14 +7,13 @@ import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
import ru.dbotthepony.kstarbound.world.entities.Entity import ru.dbotthepony.kstarbound.world.entities.Entity
import ru.dbotthepony.kvector.arrays.Matrix4fStack import ru.dbotthepony.kvector.arrays.Matrix4fStack
import ru.dbotthepony.kvector.vector.Vector2d import ru.dbotthepony.kvector.vector.Vector2d
import java.io.Closeable
/** /**
* Базовый класс, отвечающий за отрисовку определённого ентити в мире * Базовый класс, отвечающий за отрисовку определённого ентити в мире
* *
* Считается, что процесс отрисовки ограничен лишь одним слоем (т.е. отрисовка происходит в один проход) * Считается, что процесс отрисовки ограничен лишь одним слоем (т.е. отрисовка происходит в один проход)
*/ */
open class EntityRenderer(val client: StarboundClient, val entity: Entity, open var chunk: ClientChunk?) : Closeable { open class EntityRenderer(val client: StarboundClient, val entity: Entity, open var chunk: ClientChunk?) {
inline val state: GLStateTracker get() = client.gl inline val state: GLStateTracker get() = client.gl
open val renderPos: Vector2d get() = entity.position open val renderPos: Vector2d get() = entity.position
@ -30,10 +29,6 @@ open class EntityRenderer(val client: StarboundClient, val entity: Entity, open
open val layer: Int get() = Z_LEVEL_ENTITIES open val layer: Int get() = Z_LEVEL_ENTITIES
override fun close() {
}
companion object { companion object {
/** /**
* Pseudo Z position for entities, for them to appear behind tile geometry, * Pseudo Z position for entities, for them to appear behind tile geometry,

View File

@ -2,7 +2,6 @@ package ru.dbotthepony.kstarbound.io
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
import ru.dbotthepony.kstarbound.api.IStarboundFile import ru.dbotthepony.kstarbound.api.IStarboundFile
import ru.dbotthepony.kstarbound.io.json.BinaryJsonReader import ru.dbotthepony.kstarbound.io.json.BinaryJsonReader
import java.io.BufferedInputStream import java.io.BufferedInputStream