Text renderer batching

This commit is contained in:
DBotThePony 2023-09-23 10:57:46 +07:00
parent 4c39ff2069
commit 4a1a26a493
Signed by: DBot
GPG Key ID: DCC23B5715498507
15 changed files with 217 additions and 99 deletions

View File

@ -17,9 +17,8 @@ import ru.dbotthepony.kstarbound.world.entities.PlayerEntity
import ru.dbotthepony.kstarbound.io.json.VersionedJson
import ru.dbotthepony.kstarbound.io.readVarInt
import ru.dbotthepony.kstarbound.util.AssetPathStack
import ru.dbotthepony.kstarbound.world.`object`.WorldObject
import ru.dbotthepony.kstarbound.world.entities.WorldObject
import ru.dbotthepony.kvector.vector.Vector2d
import ru.dbotthepony.kvector.vector.Vector2f
import java.io.BufferedInputStream
import java.io.ByteArrayInputStream
import java.io.DataInputStream

View File

@ -236,7 +236,8 @@ class StarboundClient : Closeable {
putDebugLog("Initialized GLFW window")
}
val maxTextureBlocks = glGetInteger(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS)
val maxTextureBlocks = glGetInteger(GL_MAX_TEXTURE_IMAGE_UNITS)
val maxUserTextureBlocks = maxTextureBlocks - 1 // available textures blocks for generic use
val maxVertexAttribBindPoints = glGetInteger(GL_MAX_VERTEX_ATTRIB_BINDINGS)
init {
@ -375,6 +376,17 @@ class StarboundClient : Closeable {
checkForGLError()
}
val whiteTexture = GLTexture2D("white")
init {
val buffer = ByteBuffer.allocateDirect(3)
buffer.put(0xFF.toByte())
buffer.put(0xFF.toByte())
buffer.put(0xFF.toByte())
buffer.position(0)
whiteTexture.upload(GL_RGB, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, buffer)
}
fun setViewport(x: Int, y: Int, width: Int, height: Int) {
ensureSameThread()

View File

@ -32,7 +32,7 @@ private class GLTexturePropertyTracker(private val flag: Int, private var value:
@Suppress("SameParameterValue")
class GLTexture2D(val name: String = "<unknown>") : GLObject() {
override val client = StarboundClient.current()
override val pointer = glGenTextures()
override val pointer = glCreateTextures(GL_TEXTURE_2D)
init {
checkForGLError()

View File

@ -1,9 +1,13 @@
package ru.dbotthepony.kstarbound.client.gl.shader
import com.google.common.collect.ImmutableList
import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER
import org.lwjgl.opengl.GL20.GL_VERTEX_SHADER
import ru.dbotthepony.kstarbound.client.StarboundClient
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
import ru.dbotthepony.kstarbound.client.gl.vertex.StreamVertexBuilder
import ru.dbotthepony.kstarbound.client.gl.vertex.VertexAttributes
import ru.dbotthepony.kstarbound.client.render.FONT_VERTEX_FORMAT
import ru.dbotthepony.kvector.api.IStruct4f
import ru.dbotthepony.kvector.arrays.Matrix3f
import ru.dbotthepony.kvector.vector.RGBAColor
@ -18,14 +22,40 @@ private fun shaders1(name: String): List<GLShader> {
return listOf(client.internalVertex("shaders/vertex/$name.vsh"), client.internalFragment("shaders/fragment/$name.fsh"))
}
class FontProgram : GLShaderProgram(shaders1("font"), VertexAttributes.POSITION_UV), GLShaderProgram.Regular {
override var viewMatrix: Matrix3f by F3x3Uniform("viewMatrix", true)
override var worldMatrix: Matrix3f by F3x3Uniform("worldMatrix", true)
override var modelMatrix: Matrix3f by F3x3Uniform("modelMatrix", true)
override var colorMultiplier: IStruct4f by F4Uniform("colorMultiplier", true)
var texture by IUniform("texture0")
private fun fontShaders(): List<GLShader> {
val client = StarboundClient.current()
var read = StarboundClient.readInternal("shaders/fragment/font.fsh")
val builder = StreamVertexBuilder(attributes, GeometryType.QUADS)
val textures = ArrayList<String>()
val cases = ArrayList<String>()
val cases2 = ArrayList<String>()
for (i in 0 until client.maxUserTextureBlocks) {
cases.add("\tvec4 colorResult$i = colorMultiplier * texture(texture$i, uvOut).r;")
}
for (i in 0 until client.maxUserTextureBlocks) {
textures.add("layout (binding=$i) uniform sampler2D texture$i;")
cases2.add("if (textureIndexOut < ${i + 0.1f}) { colorResult = colorResult$i; }")
}
cases2.add(" { colorResult = colorMultiplier; }")
read = read.replace("uniform sampler2D texture0;", textures.joinToString("\n")).replace("\tcolorResult = colorMultiplier * texture(texture0, uvOut).r;", cases.joinToString("\n") + cases2.joinToString("\n\telse "))
val fragment = GLShader(read, GL_FRAGMENT_SHADER)
val vertex = GLShader(StarboundClient.readInternal("shaders/vertex/font.vsh"), GL_VERTEX_SHADER)
return listOf(fragment, vertex)
}
class FontProgram : GLShaderProgram(shaders1("font"), FONT_VERTEX_FORMAT), GLShaderProgram.Regular {
override var viewMatrix: Matrix3f by F3x3Uniform("viewMatrix")
override var worldMatrix: Matrix3f by F3x3Uniform("worldMatrix")
override var modelMatrix: Matrix3f by F3x3Uniform("modelMatrix", true)
override var colorMultiplier: IStruct4f by F4Uniform("colorMultiplier")
var texture by IUniform("texture0")
init {
viewMatrix = Matrix3f.identity()

View File

@ -3,7 +3,8 @@ package ru.dbotthepony.kstarbound.client.gl.vertex
import ru.dbotthepony.kstarbound.client.gl.GLType
enum class VertexAttributeType(val type: GLType) {
POSITION(GLType.VEC2F),
POSITION(GLType.VEC3F),
TEXTURE_INDEX(GLType.FLOAT),
COLOR(GLType.VEC4F),
UV(GLType.VEC2F),
HUE_SHIFT(GLType.FLOAT)

View File

@ -7,6 +7,7 @@ import org.lwjgl.opengl.GL45.GL_UNSIGNED_BYTE
import ru.dbotthepony.kstarbound.client.gl.BufferObject
import ru.dbotthepony.kvector.api.IStruct2f
import ru.dbotthepony.kvector.api.IStruct4f
import ru.dbotthepony.kvector.arrays.Matrix3f
import java.nio.ByteBuffer
import java.nio.ByteOrder
@ -191,6 +192,7 @@ class VertexBuilder(
vertexCount = 0
indexCount = 0
elementCount = 0
elementVertices = 0
vertexMemory.position(0)
indexMemory.position(0)
ensureCapacity()
@ -235,11 +237,15 @@ class VertexBuilder(
elementCount++
elementVertices = 0
val indexWriter = indexWriter
val indexMemory = indexMemory
val elementIndexOffset = elementIndexOffset
for (index in mode.indices.indices) {
indexWriter.write(indexMemory, mode.indices.getInt(index) + elementIndexOffset)
}
elementIndexOffset += mode.elements
this.elementIndexOffset += mode.elements
indexCount += mode.indices.size
ensureCapacity()
@ -261,6 +267,12 @@ class VertexBuilder(
return this
}
fun vertex(transform: Matrix3f, x: Float, y: Float): VertexBuilder {
vertex()
position(transform, x, y)
return this
}
private fun pushFloat(attr: VertexAttributes.Attribute, x: Float): VertexBuilder {
vertexMemory.position(vertexCount * attributes.vertexStride + attr.relativeOffset)
vertexMemory.putFloat(x)
@ -269,6 +281,14 @@ class VertexBuilder(
return this
}
private fun pushInt(attr: VertexAttributes.Attribute, x: Int): VertexBuilder {
vertexMemory.position(vertexCount * attributes.vertexStride + attr.relativeOffset)
vertexMemory.putInt(x)
vertexAttributes = vertexAttributes or attr.flag
return this
}
private fun pushFloat2(attr: VertexAttributes.Attribute, x: Float, y: Float): VertexBuilder {
vertexMemory.position(vertexCount * attributes.vertexStride + attr.relativeOffset)
vertexMemory.putFloat(x)
@ -278,6 +298,16 @@ class VertexBuilder(
return this
}
private fun pushFloat3(attr: VertexAttributes.Attribute, x: Float, y: Float, z: Float): VertexBuilder {
vertexMemory.position(vertexCount * attributes.vertexStride + attr.relativeOffset)
vertexMemory.putFloat(x)
vertexMemory.putFloat(y)
vertexMemory.putFloat(z)
vertexAttributes = vertexAttributes or attr.flag
return this
}
private fun pushFloat4(attr: VertexAttributes.Attribute, x: Float, y: Float, z: Float, w: Float): VertexBuilder {
vertexMemory.position(vertexCount * attributes.vertexStride + attr.relativeOffset)
vertexMemory.putFloat(x)
@ -289,25 +319,45 @@ class VertexBuilder(
return this
}
private val position = attributes[VertexAttributeType.POSITION]
private val uv = attributes[VertexAttributeType.UV]
private val color = attributes[VertexAttributeType.COLOR]
private val hueShift = attributes[VertexAttributeType.HUE_SHIFT]
private val textureIndex = attributes[VertexAttributeType.TEXTURE_INDEX]
fun position(x: Float, y: Float): VertexBuilder {
return pushFloat2(requireNotNull(attributes[VertexAttributeType.POSITION]) { "Vertex format does not have position attribute" }, x, y)
return pushFloat3(requireNotNull(position) { "Vertex format does not have position attribute" }, x, y, 1f)
}
fun position(value: IStruct2f) = position(value.component1(), value.component2())
fun position(transform: Matrix3f, x: Float, y: Float): VertexBuilder {
return pushFloat3(
requireNotNull(position) { "Vertex format does not have position attribute" },
x * transform.c00 + y * transform.c10 + transform.c20,
x * transform.c01 + y * transform.c11 + transform.c21,
x * transform.c02 + y * transform.c12 + transform.c22)
}
fun position(transform: Matrix3f, value: IStruct2f) = position(transform, value.component1(), value.component2())
fun uv(x: Float, y: Float): VertexBuilder {
return pushFloat2(requireNotNull(attributes[VertexAttributeType.UV]) { "Vertex format does not have texture UV attribute" }, x, y)
return pushFloat2(requireNotNull(uv) { "Vertex format does not have texture UV attribute" }, x, y)
}
fun uv(value: IStruct2f) = position(value.component1(), value.component2())
fun color(x: Float, y: Float, z: Float, w: Float): VertexBuilder {
return pushFloat4(requireNotNull(attributes[VertexAttributeType.COLOR]) { "Vertex format does not have color attribute" }, x, y, z, w)
return pushFloat4(requireNotNull(color) { "Vertex format does not have color attribute" }, x, y, z, w)
}
fun color(value: IStruct4f) = color(value.component1(), value.component2(), value.component3(), value.component4())
fun hueShift(x: Float): VertexBuilder {
return pushFloat(requireNotNull(attributes[VertexAttributeType.HUE_SHIFT]) { "Vertex format does not have texture UV attribute" }, x)
return pushFloat(requireNotNull(hueShift) { "Vertex format does not have texture UV attribute" }, x)
}
fun textureIndex(x: Int): VertexBuilder {
return pushFloat(requireNotNull(textureIndex) { "Vertex format does not have texture index attribute" }, x.toFloat())
}
}

View File

@ -1,17 +1,30 @@
package ru.dbotthepony.kstarbound.client.render
import it.unimi.dsi.fastutil.chars.Char2ObjectArrayMap
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
import org.lwjgl.opengl.GL45.*
import org.lwjgl.system.MemoryUtil
import ru.dbotthepony.kstarbound.client.StarboundClient
import ru.dbotthepony.kstarbound.client.freetype.LoadFlag
import ru.dbotthepony.kstarbound.client.gl.*
import ru.dbotthepony.kstarbound.client.freetype.struct.FT_Pixel_Mode
import ru.dbotthepony.kstarbound.client.gl.vertex.VertexAttributes
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
import ru.dbotthepony.kstarbound.client.gl.vertex.VertexAttributeType
import ru.dbotthepony.kstarbound.client.gl.vertex.VertexBuilder
import ru.dbotthepony.kstarbound.defs.image.IUVCoordinates
import ru.dbotthepony.kstarbound.math.roundTowardsNegativeInfinity
import ru.dbotthepony.kstarbound.math.roundTowardsPositiveInfinity
import ru.dbotthepony.kvector.arrays.Matrix3f
import ru.dbotthepony.kvector.util2d.AABB
import ru.dbotthepony.kvector.util2d.AABBi
import ru.dbotthepony.kvector.vector.RGBAColor
import ru.dbotthepony.kvector.vector.Vector2d
import ru.dbotthepony.kvector.vector.Vector2i
import ru.dbotthepony.kvector.vector.Vector4f
private fun breakLines(text: String): List<String> {
var nextLineBreak = text.indexOf('\n', 0)
@ -55,12 +68,14 @@ enum class TextAlignY {
TOP, CENTER, BOTTOM
}
val FONT_VERTEX_FORMAT = VertexAttributes.of(VertexAttributeType.POSITION, VertexAttributeType.UV)
class Font(
val font: String = "hobo.ttf",
val size: Int = 48
) {
val state = StarboundClient.current()
val face = state.freeType.Face(font, 0L)
val client = StarboundClient.current()
val face = client.freeType.Face(font, 0L)
init {
face.setSize(0, size)
@ -78,6 +93,37 @@ class Font(
private val descender = face.nativeMemory.descender.toFloat() / ((size / 48f) * 32f)
val lineHeight = ascender - descender
val bbox = AABBi(
Vector2i(roundTowardsNegativeInfinity(face.nativeMemory.bbox.xMin.toInt() / (12.0 * 48.0 / size)), roundTowardsNegativeInfinity(face.nativeMemory.bbox.yMin.toInt() / (12.0 * 48.0 / size))),
Vector2i(roundTowardsPositiveInfinity(face.nativeMemory.bbox.xMax.toInt() / (12.0 * 48.0 / size)), roundTowardsPositiveInfinity(face.nativeMemory.bbox.yMax.toInt() / (12.0 * 48.0 / size))),
)
private val atlas = GLTexture2D()
private val atlasWidth: Int = glGetInternalformati(GL_TEXTURE_2D, GL_RED, GL_MAX_WIDTH).coerceAtMost(4096)
private val atlasHeight: Int = glGetInternalformati(GL_TEXTURE_2D, GL_RED, GL_MAX_HEIGHT).coerceAtMost(4096)
private var nextAtlasX = 0
private var nextAtlasY = 0
init {
glTextureStorage2D(atlas.pointer, 1, GL_R8, atlasWidth, atlasHeight)
checkForGLError()
atlas.textureMinFilter = GL_LINEAR
atlas.textureMagFilter = GL_LINEAR
atlas.textureWrapS = GL_CLAMP_TO_EDGE
atlas.textureWrapT = GL_CLAMP_TO_EDGE
}
private val builder = VertexBuilder(FONT_VERTEX_FORMAT, GeometryType.QUADS)
private val vao = VertexArrayObject()
private val vbo = BufferObject.VBO()
private val ebo = BufferObject.EBO()
init {
vao.elementBuffer = ebo
vao.bindAttributes(vbo, FONT_VERTEX_FORMAT)
}
fun render(
text: List<String>,
@ -111,11 +157,7 @@ class Font(
if (scale != 1f)
model.scale(x = scale, y = scale)
state.programs.font.use()
state.programs.font.colorMultiplier = color
state.programs.font.worldMatrix = state.stack.last()
state.activeTexture = 0
state.programs.font.texture = 0
builder.begin()
val space = getGlyph(' ')
@ -170,7 +212,19 @@ class Font(
model.translate(x = -lineWidth - movedX, y = lineHeight)
}
state.vao = null
client.programs.font.use()
client.programs.font.colorMultiplier = color
client.programs.font.worldMatrix = client.stack.last()
builder.upload(vbo, ebo, GL_STREAM_DRAW)
client.activeTexture = 0
atlas.bind()
client.vao = vao
glDrawElements(GL_TRIANGLES, builder.indexCount, builder.indexType, 0L)
checkForGLError()
client.vao = null
return TextSize(totalX * scale, totalY * scale)
}
@ -207,10 +261,10 @@ class Font(
if (chr == '\t') {
if (lineGlyphs % 4 == 0) {
lineWidth += space.advanceX * 4
state.stack.last().translate(x = space.advanceX * 4)
client.stack.last().translate(x = space.advanceX * 4)
} else {
lineWidth += space.advanceX * (lineGlyphs % 4)
state.stack.last().translate(x = space.advanceX * (lineGlyphs % 4))
client.stack.last().translate(x = space.advanceX * (lineGlyphs % 4))
}
lineGlyphs += lineGlyphs % 4
@ -243,8 +297,6 @@ class Font(
}
private inner class Glyph(val char: Char) {
private val texture: GLTexture2D?
val isEmpty: Boolean
val width: Float
@ -255,13 +307,13 @@ class Font(
val advanceX: Float
val advanceY: Float
private val vao: VertexArrayObject?
private val indexCount: Int
private val elementIndexType: Int
val uv: Vector4f
init {
if (nextAtlasY + bbox.height > atlasHeight) {
throw IllegalStateException("Font atlas is full")
}
face.loadChar(char, LoadFlag.RENDER)
val glyph = face.nativeMemory.glyph ?: throw IllegalStateException("Unable to load glyph data for $char (code ${char.code})")
val bitmap = glyph.bitmap
@ -282,43 +334,26 @@ class Font(
// интересно, а что будет когда буфер будет "вычищен" из памяти? Чо, будет double free?
val buff = bitmap.byteBuffer!!
texture = state.newTexture("$font:$char")
glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
texture.upload(GL_RED, bitmap.width, bitmap.rows, GL_RED, GL_UNSIGNED_BYTE, buff)
texture.generateMips()
texture.textureMinFilter = GL_LINEAR
texture.textureMagFilter = GL_LINEAR
texture.textureWrapS = GL_CLAMP_TO_EDGE
texture.textureWrapT = GL_CLAMP_TO_EDGE
try {
uv = Vector4f(nextAtlasX / atlasWidth.toFloat(), nextAtlasY / atlasHeight.toFloat(), (nextAtlasX + bitmap.width) / atlasWidth.toFloat(), (nextAtlasY + bitmap.rows) / atlasHeight.toFloat())
glPixelStorei(GL_UNPACK_ALIGNMENT, 4)
glTextureSubImage2D(atlas.pointer, 0, nextAtlasX, nextAtlasY, bitmap.width, bitmap.rows, GL_RED, GL_UNSIGNED_BYTE, buff)
checkForGLError("Uploading glyph texture data")
vao = state.newVAO()
val ebo = state.newEBO()
val vbo = state.newVBO()
nextAtlasX += bbox.width
vao.elementBuffer = ebo
vao.bindAttributes(vbo, VertexAttributes.POSITION_UV)
val builder = VertexBuilder(VertexAttributes.POSITION_UV, GeometryType.QUADS)
builder.vertex(0f, 0f).uv(0f, 0f)
builder.vertex(width, 0f).uv(1f, 0f)
builder.vertex(width, height).uv(1f, 1f)
builder.vertex(0f, height).uv(0f, 1f)
builder.upload(vbo, ebo, GL_STATIC_DRAW)
indexCount = builder.indexCount
elementIndexType = builder.indexType
if (nextAtlasX + bbox.width > atlasWidth) {
nextAtlasX = 0
nextAtlasY += bbox.height
}
} finally {
glPixelStorei(GL_UNPACK_ALIGNMENT, 4)
}
} else {
isEmpty = true
indexCount = 0
elementIndexType = 0
vao = null
texture = null
uv = Vector4f.ZERO
}
}
@ -328,14 +363,12 @@ class Font(
return
}
vao!!.bind()
model.translate(bearingX, -bearingY)
texture!!.bind()
state.programs.font.modelMatrix = model
glDrawElements(GL_TRIANGLES, indexCount, elementIndexType, 0L)
checkForGLError()
builder.vertex(model, 0f, 0f).uv(uv.x, uv.y)
builder.vertex(model, width, 0f).uv(uv.z, uv.y)
builder.vertex(model, width, height).uv(uv.z, uv.w)
builder.vertex(model, 0f, height).uv(uv.x, uv.w)
model.translate(advanceX - bearingX, bearingY)
}

View File

@ -270,12 +270,12 @@ class ClientWorld(
if (obj.pos.x in client.viewportCellX .. client.viewportCellX + client.viewportCellWidth && obj.pos.y in client.viewportCellY .. client.viewportCellY + client.viewportCellHeight) {
//layers.add(RenderLayer.Object.index) {
layers.add(obj.orientation?.renderLayer ?: continue) {
client.quadWireframe {
/*client.quadWireframe {
it.vertex(obj.pos.x.toFloat(), obj.pos.y.toFloat())
it.vertex(obj.pos.x.toFloat() + 1f, obj.pos.y.toFloat())
it.vertex(obj.pos.x.toFloat() + 1f, obj.pos.y.toFloat() + 1f)
it.vertex(obj.pos.x.toFloat(), obj.pos.y.toFloat() + 1f)
}
}*/
obj.drawables.forEach {
val (x, y) = obj.imagePosition

View File

@ -84,7 +84,7 @@ sealed class Drawable(val position: Vector2f, val color: RGBAColor, val fullbrig
val texture = client.loadTexture(path.imagePath.value!!)
val program = if (fullbright) client.programs.positionTexture else client.programs.positionTextureLightmap
program.modelMatrix = transform.map({ it }, {
val mat = transform.map({ it }, {
val mat = Matrix3f.identity()
it.scale.map({ mat.scale(it / PIXELS_IN_STARBOUND_UNITf, it / PIXELS_IN_STARBOUND_UNITf) }, { mat.scale(it / PIXELS_IN_STARBOUND_UNITf) })
@ -105,6 +105,9 @@ sealed class Drawable(val position: Vector2f, val color: RGBAColor, val fullbrig
mat
})
//program.modelMatrix = mat
program.modelMatrix = Matrix3f.identity()
program.worldMatrix = client.stack.last()
program.use()
program.texture0 = 0
@ -112,10 +115,10 @@ sealed class Drawable(val position: Vector2f, val color: RGBAColor, val fullbrig
texture.bind()
program.builder.builder.begin(GeometryType.QUADS)
program.builder.builder.vertex(x, y).uv(sprite.u0, sprite.v0)
program.builder.builder.vertex(x + sprite.width, y).uv(sprite.u1, sprite.v0)
program.builder.builder.vertex(x + sprite.width, y + sprite.height).uv(sprite.u1, sprite.v1)
program.builder.builder.vertex(x, y + sprite.height).uv(sprite.u0, sprite.v1)
program.builder.builder.vertex(mat, x, y).uv(sprite.u0, sprite.v0)
program.builder.builder.vertex(mat, x + sprite.width, y).uv(sprite.u1, sprite.v0)
program.builder.builder.vertex(mat, x + sprite.width, y + sprite.height).uv(sprite.u1, sprite.v1)
program.builder.builder.vertex(mat, x, y + sprite.height).uv(sprite.u0, sprite.v1)
program.builder.upload()
program.builder.draw()
}

View File

@ -18,7 +18,7 @@ import ru.dbotthepony.kstarbound.world.api.ICellAccess
import ru.dbotthepony.kstarbound.world.api.IChunkCell
import ru.dbotthepony.kstarbound.world.api.TileView
import ru.dbotthepony.kstarbound.world.entities.Entity
import ru.dbotthepony.kstarbound.world.`object`.WorldObject
import ru.dbotthepony.kstarbound.world.entities.WorldObject
import ru.dbotthepony.kvector.api.IStruct2d
import ru.dbotthepony.kvector.api.IStruct2i
import ru.dbotthepony.kvector.arrays.Object2DArray

View File

@ -4,12 +4,7 @@ import ru.dbotthepony.kstarbound.world.Chunk
import ru.dbotthepony.kstarbound.world.World
import ru.dbotthepony.kvector.vector.Vector2d
abstract class Entity(
/**
* The world this entity in, never changes.
*/
val world: World<*, *>
) {
abstract class Entity(val world: World<*, *>) {
/**
* The chunk this entity currently in, it is automatically updated on each change of [position]
*/
@ -17,13 +12,9 @@ abstract class Entity(
set(value) {
if (!isSpawned) {
throw IllegalStateException("Trying to set chunk this entity belong to before spawning in world")
}
if (isRemoved) {
} else if (isRemoved) {
throw IllegalStateException("This entity was removed")
}
if (value == field) {
} else if (value == field) {
return
}

View File

@ -1,4 +1,4 @@
package ru.dbotthepony.kstarbound.world.`object`
package ru.dbotthepony.kstarbound.world.entities
import com.google.common.collect.ImmutableMap
import com.google.gson.JsonObject

View File

@ -1,7 +1,7 @@
#version 330
#version 450
uniform sampler2D texture0;
layout (binding = 0) uniform sampler2D texture0;
uniform vec4 colorMultiplier;
out vec4 colorResult;

View File

@ -1,5 +1,5 @@
layout (location = 0) in vec2 pos;
layout (location = 0) in vec3 pos;
#ifdef TEXTURE
layout (location = TEXTURE) in vec2 uvIn;
@ -21,7 +21,7 @@ uniform mat3 worldMatrix; // matrix stack
uniform mat3 modelMatrix; // local transformations
void main() {
vec3 result = viewMatrix * worldMatrix * modelMatrix * vec3(pos, 1.0);
vec3 result = viewMatrix * worldMatrix * modelMatrix * pos;
gl_Position = vec4(result.x, result.y, 0.0, result.z);
#ifdef HUE_SHIFT

View File

@ -1,17 +1,16 @@
#version 330
#version 450
layout (location = 0) in vec2 pos;
layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 uvData;
uniform mat3 viewMatrix; // projection (viewport)
uniform mat3 worldMatrix; // world position
uniform mat3 modelMatrix; // mesh/local transformations
out vec2 uvOut;
void main() {
vec3 result = viewMatrix * worldMatrix * modelMatrix * vec3(pos, 1.0);
vec3 result = viewMatrix * worldMatrix * pos;
gl_Position = vec4(result.x, result.y, 0.0, result.z);
uvOut = uvData;