Только один VertexBuilder для их всех
This commit is contained in:
parent
0052adf89a
commit
0fd5fb0be7
@ -6,9 +6,7 @@ import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
|||||||
import ru.dbotthepony.kstarbound.client.gl.program.GLHardLightGeometryProgram
|
import ru.dbotthepony.kstarbound.client.gl.program.GLHardLightGeometryProgram
|
||||||
import ru.dbotthepony.kstarbound.client.gl.program.GLSoftLightGeometryProgram
|
import ru.dbotthepony.kstarbound.client.gl.program.GLSoftLightGeometryProgram
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.StatefulVertexBuilder
|
import ru.dbotthepony.kstarbound.client.gl.vertex.StreamVertexBuilder
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.quad
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.shadowLine
|
|
||||||
import ru.dbotthepony.kstarbound.client.render.ConfiguredStaticMesh
|
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.GPULightRenderer
|
import ru.dbotthepony.kstarbound.client.render.GPULightRenderer
|
||||||
@ -191,13 +189,13 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
|
|||||||
}
|
}
|
||||||
|
|
||||||
private inner class ShadowGeometryTracker(val x: Int, val y: Int) : GPULightRenderer.ShadowGeometryRenderer {
|
private inner class ShadowGeometryTracker(val x: Int, val y: Int) : GPULightRenderer.ShadowGeometryRenderer {
|
||||||
private val hardShadowGeometry by lazy(LazyThreadSafetyMode.NONE) { StatefulVertexBuilder(state, GPULightRenderer.SHADOW_FORMAT, GeometryType.LINES) }
|
private val hardShadowGeometry by lazy(LazyThreadSafetyMode.NONE) { StreamVertexBuilder(state, GPULightRenderer.SHADOW_FORMAT, GeometryType.LINES) }
|
||||||
private var hardShadowGeometryRev = -1
|
private var hardShadowGeometryRev = -1
|
||||||
private val softShadowGeometry by lazy(LazyThreadSafetyMode.NONE) { StatefulVertexBuilder(state, GPULightRenderer.SHADOW_FORMAT_SOFT, GeometryType.QUADS_ALTERNATIVE) }
|
private val softShadowGeometry by lazy(LazyThreadSafetyMode.NONE) { StreamVertexBuilder(state, GPULightRenderer.SHADOW_FORMAT_SOFT, GeometryType.QUADS_ALTERNATIVE) }
|
||||||
private var softShadowGeometryRev = -1
|
private var softShadowGeometryRev = -1
|
||||||
|
|
||||||
private fun buildGeometry(builder: StatefulVertexBuilder, line: (StatefulVertexBuilder, Float, Float, Float, Float) -> Unit) {
|
private fun buildGeometry(builder: StreamVertexBuilder, line: (StreamVertexBuilder, Float, Float, Float, Float) -> Unit) {
|
||||||
builder.begin()
|
builder.builder.begin()
|
||||||
|
|
||||||
for (x in this.x * SHADOW_GEOMETRY_SQUARE_SIZE until (this.x + 1) * SHADOW_GEOMETRY_SQUARE_SIZE) {
|
for (x in this.x * SHADOW_GEOMETRY_SQUARE_SIZE until (this.x + 1) * SHADOW_GEOMETRY_SQUARE_SIZE) {
|
||||||
for (y in this.y * SHADOW_GEOMETRY_SQUARE_SIZE until (this.y + 1) * SHADOW_GEOMETRY_SQUARE_SIZE) {
|
for (y in this.y * SHADOW_GEOMETRY_SQUARE_SIZE until (this.y + 1) * SHADOW_GEOMETRY_SQUARE_SIZE) {
|
||||||
@ -228,14 +226,16 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
|
|||||||
hardShadowGeometryRev = tileChangeset
|
hardShadowGeometryRev = tileChangeset
|
||||||
|
|
||||||
buildGeometry(hardShadowGeometry) { it, x0, y0, x1, y1 ->
|
buildGeometry(hardShadowGeometry) { it, x0, y0, x1, y1 ->
|
||||||
it.vertex().pushVec2f(x0, y0)
|
it.builder.vertex().pushVec2f(x0, y0)
|
||||||
it.vertex().pushVec2f(x1, y1)
|
it.builder.vertex().pushVec2f(x1, y1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun buildSoftGeometry() {
|
fun buildSoftGeometry() {
|
||||||
softShadowGeometryRev = tileChangeset
|
softShadowGeometryRev = tileChangeset
|
||||||
buildGeometry(softShadowGeometry, StatefulVertexBuilder::shadowLine)
|
buildGeometry(softShadowGeometry) { it, x0, y0, x1, y1 ->
|
||||||
|
it.builder.shadowLine(x0, y0, x1, y1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun renderHardGeometry(
|
override fun renderHardGeometry(
|
||||||
@ -398,14 +398,14 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
|
|||||||
val builder = program.builder
|
val builder = program.builder
|
||||||
|
|
||||||
for (type in types) {
|
for (type in types) {
|
||||||
builder.begin()
|
builder.builder.begin()
|
||||||
|
|
||||||
for (x in 0 until CHUNK_SIZE) {
|
for (x in 0 until CHUNK_SIZE) {
|
||||||
for (y in 0 until CHUNK_SIZE) {
|
for (y in 0 until CHUNK_SIZE) {
|
||||||
val state = getLiquid(x, y)
|
val state = getLiquid(x, y)
|
||||||
|
|
||||||
if (state != null && state.def === type) {
|
if (state != null && state.def === type) {
|
||||||
builder.quad(x.toFloat(), y.toFloat(), x + 1f, y + state.level)
|
builder.builder.quad(x.toFloat(), y.toFloat(), x + 1f, y + state.level)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package ru.dbotthepony.kstarbound.client.gl
|
|||||||
import org.apache.logging.log4j.LogManager
|
import org.apache.logging.log4j.LogManager
|
||||||
import org.lwjgl.opengl.GL
|
import org.lwjgl.opengl.GL
|
||||||
import org.lwjgl.opengl.GL46.*
|
import org.lwjgl.opengl.GL46.*
|
||||||
import ru.dbotthepony.kstarbound.Starbound
|
|
||||||
import ru.dbotthepony.kstarbound.api.ISBFileLocator
|
import ru.dbotthepony.kstarbound.api.ISBFileLocator
|
||||||
import ru.dbotthepony.kstarbound.client.freetype.FreeType
|
import ru.dbotthepony.kstarbound.client.freetype.FreeType
|
||||||
import ru.dbotthepony.kstarbound.client.freetype.InvalidArgumentException
|
import ru.dbotthepony.kstarbound.client.freetype.InvalidArgumentException
|
||||||
@ -15,10 +14,9 @@ import ru.dbotthepony.kstarbound.client.gl.shader.GLTransformableProgram
|
|||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GLAttributeList
|
import ru.dbotthepony.kstarbound.client.gl.vertex.GLAttributeList
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.StreamVertexBuilder
|
import ru.dbotthepony.kstarbound.client.gl.vertex.StreamVertexBuilder
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.quad
|
import ru.dbotthepony.kstarbound.client.gl.vertex.VertexBuilder
|
||||||
import ru.dbotthepony.kstarbound.client.render.Box2DRenderer
|
import ru.dbotthepony.kstarbound.client.render.Box2DRenderer
|
||||||
import ru.dbotthepony.kstarbound.client.render.Font
|
import ru.dbotthepony.kstarbound.client.render.Font
|
||||||
import ru.dbotthepony.kstarbound.client.render.TileRenderers
|
|
||||||
import ru.dbotthepony.kvector.api.IStruct4f
|
import ru.dbotthepony.kvector.api.IStruct4f
|
||||||
import ru.dbotthepony.kvector.matrix.Matrix4fStack
|
import ru.dbotthepony.kvector.matrix.Matrix4fStack
|
||||||
import ru.dbotthepony.kvector.util2d.AABB
|
import ru.dbotthepony.kvector.util2d.AABB
|
||||||
@ -565,38 +563,21 @@ class GLStateTracker(val locator: ISBFileLocator) {
|
|||||||
|
|
||||||
val programs = GLPrograms(this)
|
val programs = GLPrograms(this)
|
||||||
|
|
||||||
val flat2DLines = object : GLStreamBuilderList {
|
val flat2DLines by lazy { StreamVertexBuilder(this, GLAttributeList.VEC2F, GeometryType.LINES) }
|
||||||
override val small by lazy {
|
val flat2DTriangles by lazy { StreamVertexBuilder(this, GLAttributeList.VEC2F, GeometryType.TRIANGLES) }
|
||||||
return@lazy StreamVertexBuilder(this@GLStateTracker, GLAttributeList.VEC2F, GeometryType.LINES, 1024)
|
val flat2DTexturedQuads by lazy { StreamVertexBuilder(this, GLAttributeList.VERTEX_TEXTURE, GeometryType.QUADS) }
|
||||||
}
|
val quadWireframe by lazy { StreamVertexBuilder(this, GLAttributeList.VEC2F, GeometryType.QUADS_AS_LINES_WIREFRAME) }
|
||||||
}
|
|
||||||
|
|
||||||
val flat2DTriangles = object : GLStreamBuilderList {
|
|
||||||
override val small by lazy {
|
|
||||||
return@lazy StreamVertexBuilder(this@GLStateTracker, GLAttributeList.VEC2F, GeometryType.TRIANGLES, 1024)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val flat2DTexturedQuads = object : GLStreamBuilderList {
|
|
||||||
override val small by lazy {
|
|
||||||
return@lazy StreamVertexBuilder(this@GLStateTracker, GLAttributeList.VERTEX_TEXTURE, GeometryType.QUADS, 1024)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val quadWireframe by lazy {
|
|
||||||
StreamVertexBuilder(this, GLAttributeList.VEC2F, GeometryType.QUADS_AS_LINES_WIREFRAME, 16384)
|
|
||||||
}
|
|
||||||
|
|
||||||
val matrixStack = Matrix4fStack()
|
val matrixStack = Matrix4fStack()
|
||||||
val freeType = FreeType()
|
val freeType = FreeType()
|
||||||
|
|
||||||
val font = Font(this)
|
val font = Font(this)
|
||||||
|
|
||||||
inline fun quadWireframe(color: Color = Color.WHITE, lambda: (StreamVertexBuilder) -> Unit) {
|
inline fun quadWireframe(color: Color = Color.WHITE, lambda: (VertexBuilder) -> Unit) {
|
||||||
val builder = quadWireframe
|
val builder = quadWireframe
|
||||||
|
|
||||||
builder.begin()
|
builder.builder.begin()
|
||||||
lambda.invoke(builder)
|
lambda.invoke(builder.builder)
|
||||||
builder.upload()
|
builder.upload()
|
||||||
|
|
||||||
programs.flat.use()
|
programs.flat.use()
|
||||||
@ -606,11 +587,11 @@ class GLStateTracker(val locator: ISBFileLocator) {
|
|||||||
builder.draw(GL_LINES)
|
builder.draw(GL_LINES)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun quadColor(lambda: (StreamVertexBuilder) -> Unit) {
|
inline fun quadColor(lambda: (VertexBuilder) -> Unit) {
|
||||||
val builder = programs.flatColor.builder
|
val builder = programs.flatColor.builder
|
||||||
|
|
||||||
builder.begin()
|
builder.builder.begin()
|
||||||
lambda.invoke(builder)
|
lambda.invoke(builder.builder)
|
||||||
builder.upload()
|
builder.upload()
|
||||||
|
|
||||||
programs.flatColor.use()
|
programs.flatColor.use()
|
||||||
@ -619,7 +600,7 @@ class GLStateTracker(val locator: ISBFileLocator) {
|
|||||||
builder.draw(GL_TRIANGLES)
|
builder.draw(GL_TRIANGLES)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun quadWireframe(value: AABB, color: Color = Color.WHITE, chain: (StreamVertexBuilder) -> Unit = {}) {
|
inline fun quadWireframe(value: AABB, color: Color = Color.WHITE, chain: (VertexBuilder) -> Unit = {}) {
|
||||||
quadWireframe(color) {
|
quadWireframe(color) {
|
||||||
it.quad(value.mins.x.toFloat(), value.mins.y.toFloat(), value.maxs.x.toFloat(), value.maxs.y.toFloat())
|
it.quad(value.mins.x.toFloat(), value.mins.y.toFloat(), value.maxs.x.toFloat(), value.maxs.y.toFloat())
|
||||||
chain(it)
|
chain(it)
|
||||||
|
@ -9,7 +9,6 @@ import ru.dbotthepony.kstarbound.client.gl.vertex.GLAttributeList
|
|||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.StreamVertexBuilder
|
import ru.dbotthepony.kstarbound.client.gl.vertex.StreamVertexBuilder
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.quad
|
|
||||||
import ru.dbotthepony.kstarbound.client.render.GPULightRenderer
|
import ru.dbotthepony.kstarbound.client.render.GPULightRenderer
|
||||||
import ru.dbotthepony.kvector.vector.Color
|
import ru.dbotthepony.kvector.vector.Color
|
||||||
import kotlin.properties.ReadOnlyProperty
|
import kotlin.properties.ReadOnlyProperty
|
||||||
@ -123,8 +122,8 @@ class GLColorQuadProgram(state: GLStateTracker) : GLInternalProgram(state, "scre
|
|||||||
private val builder by lazy {
|
private val builder by lazy {
|
||||||
val builder = StreamVertexBuilder(state, FORMAT, GeometryType.QUADS, 1)
|
val builder = StreamVertexBuilder(state, FORMAT, GeometryType.QUADS, 1)
|
||||||
|
|
||||||
builder.begin()
|
builder.builder.begin()
|
||||||
builder.quad(-1f, -1f, 1f, 1f)
|
builder.builder.quad(-1f, -1f, 1f, 1f)
|
||||||
builder.upload()
|
builder.upload()
|
||||||
|
|
||||||
builder
|
builder
|
||||||
@ -173,8 +172,8 @@ class GLTextureQuadProgram(state: GLStateTracker) : GLInternalProgram(state, "sc
|
|||||||
private val builder by lazy {
|
private val builder by lazy {
|
||||||
val builder = StreamVertexBuilder(state, FORMAT, GeometryType.QUADS, 1)
|
val builder = StreamVertexBuilder(state, FORMAT, GeometryType.QUADS, 1)
|
||||||
|
|
||||||
builder.begin()
|
builder.builder.begin()
|
||||||
builder.quad(-1f, -1f, 1f, 1f, QuadTransformers.uv())
|
builder.builder.quad(-1f, -1f, 1f, 1f, QuadTransformers.uv())
|
||||||
builder.upload()
|
builder.upload()
|
||||||
|
|
||||||
builder
|
builder
|
||||||
@ -201,8 +200,8 @@ class GLTextureBlurredQuadProgram(state: GLStateTracker) : GLInternalProgram(sta
|
|||||||
private val builder by lazy {
|
private val builder by lazy {
|
||||||
val builder = StreamVertexBuilder(state, FORMAT, GeometryType.QUADS, 1)
|
val builder = StreamVertexBuilder(state, FORMAT, GeometryType.QUADS, 1)
|
||||||
|
|
||||||
builder.begin()
|
builder.builder.begin()
|
||||||
builder.quad(-1f, -1f, 1f, 1f, QuadTransformers.uv())
|
builder.builder.quad(-1f, -1f, 1f, 1f, QuadTransformers.uv())
|
||||||
builder.upload()
|
builder.upload()
|
||||||
|
|
||||||
builder
|
builder
|
||||||
|
@ -1,308 +0,0 @@
|
|||||||
package ru.dbotthepony.kstarbound.client.gl.vertex
|
|
||||||
|
|
||||||
import org.lwjgl.opengl.GL46
|
|
||||||
import org.lwjgl.opengl.GL46.GL_UNSIGNED_INT
|
|
||||||
import org.lwjgl.opengl.GL46.GL_UNSIGNED_SHORT
|
|
||||||
import org.lwjgl.opengl.GL46.GL_UNSIGNED_BYTE
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.GLType
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.VertexBufferObject
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.checkForGLError
|
|
||||||
import ru.dbotthepony.kstarbound.util.writeLEFloat
|
|
||||||
import ru.dbotthepony.kstarbound.util.writeLEInt
|
|
||||||
import ru.dbotthepony.kstarbound.util.writeLEShort
|
|
||||||
import ru.dbotthepony.kvector.util2d.AABB
|
|
||||||
import java.io.OutputStream
|
|
||||||
import kotlin.math.cos
|
|
||||||
import kotlin.math.sin
|
|
||||||
|
|
||||||
private fun put(type: Int, memory: OutputStream, value: Int) {
|
|
||||||
when (type) {
|
|
||||||
GL_UNSIGNED_SHORT -> memory.writeLEShort(value)
|
|
||||||
GL_UNSIGNED_BYTE -> memory.write(value)
|
|
||||||
else -> memory.writeLEInt(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Класс для построения геометрии для загрузки в память видеокарты.
|
|
||||||
*/
|
|
||||||
@Suppress("unchecked_cast")
|
|
||||||
abstract class AbstractVertexBuilder<out T : AbstractVertexBuilder<T>>(
|
|
||||||
val attributes: GLAttributeList,
|
|
||||||
val type: GeometryType,
|
|
||||||
) {
|
|
||||||
protected abstract val vertexMemory: OutputStream
|
|
||||||
protected abstract val elementMemory: OutputStream
|
|
||||||
|
|
||||||
/**
|
|
||||||
* [GL_UNSIGNED_BYTE], [GL_UNSIGNED_SHORT] или [GL_UNSIGNED_INT]
|
|
||||||
*
|
|
||||||
* Обязана быть статичным числом.
|
|
||||||
*
|
|
||||||
* Если нет, и его надо изменить, то это можно только делать внутри [ensureIndexCapacity].
|
|
||||||
*
|
|
||||||
* Подкласс обязан самостоятельно изменить тип существующих элементов внутри [elementMemory]
|
|
||||||
*/
|
|
||||||
abstract val elementIndexType: Int
|
|
||||||
|
|
||||||
protected abstract fun ensureIndexCapacity()
|
|
||||||
|
|
||||||
protected abstract fun resetMemory()
|
|
||||||
|
|
||||||
fun begin() {
|
|
||||||
inVertex = false
|
|
||||||
attributeIndex = 0
|
|
||||||
elementIndexOffset = 0
|
|
||||||
vertexCount = 0
|
|
||||||
indexCount = 0
|
|
||||||
resetMemory()
|
|
||||||
}
|
|
||||||
|
|
||||||
private var inVertex = false
|
|
||||||
private var attributeIndex = 0
|
|
||||||
protected var elementIndexOffset = 0
|
|
||||||
private set
|
|
||||||
|
|
||||||
var vertexCount = 0
|
|
||||||
private set
|
|
||||||
|
|
||||||
var indexCount = 0
|
|
||||||
private set
|
|
||||||
|
|
||||||
protected fun checkBounds() {
|
|
||||||
if (attributeIndex >= attributes.size) {
|
|
||||||
throw IndexOutOfBoundsException("Tried to add new attribute when already added all attributes")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun expect(type: GLType) {
|
|
||||||
checkBounds()
|
|
||||||
|
|
||||||
if (attributes[attributeIndex].glType != type) {
|
|
||||||
throw IllegalStateException("Expected attribute type $type, got ${attributes[attributeIndex].name}[${attributes[attributeIndex].glType}] (at position $attributeIndex)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun expect(name: String) {
|
|
||||||
checkBounds()
|
|
||||||
|
|
||||||
if (attributes[attributeIndex].name != name) {
|
|
||||||
throw IllegalStateException("Expected attribute name $name, got ${attributes[attributeIndex].name}[${attributes[attributeIndex].glType}] (at position $attributeIndex)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract fun doUpload(vbo: VertexBufferObject, ebo: VertexBufferObject, drawType: Int)
|
|
||||||
|
|
||||||
fun upload(vbo: VertexBufferObject, ebo: VertexBufferObject, drawType: Int = GL46.GL_DYNAMIC_DRAW) {
|
|
||||||
require(vbo.isArray) { "$vbo is not an array" }
|
|
||||||
require(ebo.isElementArray) { "$vbo is not an element array" }
|
|
||||||
|
|
||||||
end()
|
|
||||||
|
|
||||||
check(elementVertices == 0) { "Not fully built vertex element ($type requires ${type.elements} vertex points to be present, yet last strip has only $elementVertices elements)" }
|
|
||||||
|
|
||||||
doUpload(vbo, ebo, drawType)
|
|
||||||
checkForGLError()
|
|
||||||
}
|
|
||||||
|
|
||||||
private var elementVertices = 0
|
|
||||||
|
|
||||||
fun end() {
|
|
||||||
if (inVertex) {
|
|
||||||
inVertex = false
|
|
||||||
|
|
||||||
if (attributeIndex != attributes.size) {
|
|
||||||
throw IllegalStateException("Unfinished vertex, we are at $attributeIndex, while we have ${attributes.size} attributes")
|
|
||||||
}
|
|
||||||
|
|
||||||
vertexCount++
|
|
||||||
elementVertices++
|
|
||||||
|
|
||||||
if (elementVertices == type.elements) {
|
|
||||||
ensureIndexCapacity()
|
|
||||||
|
|
||||||
elementVertices = 0
|
|
||||||
val elementMemory = elementMemory
|
|
||||||
val elementIndexType = elementIndexType
|
|
||||||
|
|
||||||
for (index in type.indices) {
|
|
||||||
put(elementIndexType, elementMemory, index + elementIndexOffset)
|
|
||||||
}
|
|
||||||
|
|
||||||
elementIndexOffset += type.elements
|
|
||||||
indexCount += type.indices.size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun vertex(): T {
|
|
||||||
end()
|
|
||||||
inVertex = true
|
|
||||||
attributeIndex = 0
|
|
||||||
return this as T
|
|
||||||
}
|
|
||||||
|
|
||||||
fun pushVec4f(x: Float, y: Float, z: Float, w: Float): T {
|
|
||||||
expect(GLType.VEC4F)
|
|
||||||
val memory = vertexMemory
|
|
||||||
memory.writeLEFloat(x)
|
|
||||||
memory.writeLEFloat(y)
|
|
||||||
memory.writeLEFloat(z)
|
|
||||||
memory.writeLEFloat(w)
|
|
||||||
attributeIndex++
|
|
||||||
return this as T
|
|
||||||
}
|
|
||||||
|
|
||||||
fun pushVec3f(x: Float, y: Float, z: Float): T {
|
|
||||||
expect(GLType.VEC3F)
|
|
||||||
val memory = vertexMemory
|
|
||||||
memory.writeLEFloat(x)
|
|
||||||
memory.writeLEFloat(y)
|
|
||||||
memory.writeLEFloat(z)
|
|
||||||
attributeIndex++
|
|
||||||
return this as T
|
|
||||||
}
|
|
||||||
|
|
||||||
fun pushVec2f(x: Float, y: Float): T {
|
|
||||||
expect(GLType.VEC2F)
|
|
||||||
val memory = vertexMemory
|
|
||||||
memory.writeLEFloat(x)
|
|
||||||
memory.writeLEFloat(y)
|
|
||||||
attributeIndex++
|
|
||||||
return this as T
|
|
||||||
}
|
|
||||||
|
|
||||||
fun push(value: Float): T {
|
|
||||||
expect(GLType.FLOAT)
|
|
||||||
vertexMemory.writeLEFloat(value)
|
|
||||||
attributeIndex++
|
|
||||||
return this as T
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T : AbstractVertexBuilder<T>> T.shadowLine(x0: Float, y0: Float, x1: Float, y1: Float): T {
|
|
||||||
vertex()
|
|
||||||
pushVec4f(x0, y0, x1, y1)
|
|
||||||
pushVec2f(0f, 0f)
|
|
||||||
|
|
||||||
vertex()
|
|
||||||
pushVec4f(x0, y0, x1, y1)
|
|
||||||
pushVec2f(0f, 1f)
|
|
||||||
|
|
||||||
vertex()
|
|
||||||
pushVec4f(x0, y0, x1, y1)
|
|
||||||
pushVec2f(1f, 1f)
|
|
||||||
|
|
||||||
vertex()
|
|
||||||
pushVec4f(x0, y0, x1, y1)
|
|
||||||
pushVec2f(1f, 0f)
|
|
||||||
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T : AbstractVertexBuilder<T>> T.dfShadowLine(x0: Float, y0: Float, x1: Float, y1: Float): T {
|
|
||||||
shadowLine(x0, y0, x1, y1)
|
|
||||||
shadowLine(x1, y1, x0, y0)
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T : AbstractVertexBuilder<T>> T.shadowQuad(x0: Float, y0: Float, x1: Float, y1: Float): T {
|
|
||||||
shadowLine(x0, y0, x1, y0)
|
|
||||||
shadowLine(x1, y0, x1, y1)
|
|
||||||
shadowLine(x1, y1, x0, y1)
|
|
||||||
shadowLine(x0, y1, x0, y0)
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
// Помощники
|
|
||||||
fun <T : AbstractVertexBuilder<T>> T.quad(
|
|
||||||
x0: Float,
|
|
||||||
y0: Float,
|
|
||||||
x1: Float,
|
|
||||||
y1: Float,
|
|
||||||
lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM
|
|
||||||
): T {
|
|
||||||
check(type.elements == 4) { "Currently building $type" }
|
|
||||||
|
|
||||||
lambda(vertex().pushVec2f(x0, y0), 0).end()
|
|
||||||
lambda(vertex().pushVec2f(x1, y0), 1).end()
|
|
||||||
lambda(vertex().pushVec2f(x0, y1), 2).end()
|
|
||||||
lambda(vertex().pushVec2f(x1, y1), 3).end()
|
|
||||||
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T : AbstractVertexBuilder<T>> T.quadRotated(
|
|
||||||
x0: Float,
|
|
||||||
y0: Float,
|
|
||||||
x1: Float,
|
|
||||||
y1: Float,
|
|
||||||
x: Float,
|
|
||||||
y: Float,
|
|
||||||
angle: Double,
|
|
||||||
lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM
|
|
||||||
): T {
|
|
||||||
check(type.elements == 4) { "Currently building $type" }
|
|
||||||
|
|
||||||
val s = sin(angle).toFloat()
|
|
||||||
val c = cos(angle).toFloat()
|
|
||||||
|
|
||||||
lambda(vertex().pushVec2f(x + x0 * c - s * y0, y + s * x0 + c * y0), 0).end()
|
|
||||||
lambda(vertex().pushVec2f(x + x1 * c - s * y0, y + s * x1 + c * y0), 1).end()
|
|
||||||
lambda(vertex().pushVec2f(x + x0 * c - s * y1, y + s * x0 + c * y1), 2).end()
|
|
||||||
lambda(vertex().pushVec2f(x + x1 * c - s * y1, y + s * x1 + c * y1), 3).end()
|
|
||||||
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T : AbstractVertexBuilder<T>> T.quad(aabb: AABB, lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM): T {
|
|
||||||
return quad(
|
|
||||||
aabb.mins.x.toFloat(),
|
|
||||||
aabb.mins.y.toFloat(),
|
|
||||||
aabb.maxs.x.toFloat(),
|
|
||||||
aabb.maxs.y.toFloat(),
|
|
||||||
lambda
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T : AbstractVertexBuilder<T>> T.quadZ(
|
|
||||||
x0: Float,
|
|
||||||
y0: Float,
|
|
||||||
x1: Float,
|
|
||||||
y1: Float,
|
|
||||||
z: Float,
|
|
||||||
lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM
|
|
||||||
): T {
|
|
||||||
check(type.elements == 4) { "Currently building $type" }
|
|
||||||
|
|
||||||
lambda(vertex().pushVec3f(x0, y0, z), 0).end()
|
|
||||||
lambda(vertex().pushVec3f(x1, y0, z), 1).end()
|
|
||||||
lambda(vertex().pushVec3f(x0, y1, z), 2).end()
|
|
||||||
lambda(vertex().pushVec3f(x1, y1, z), 3).end()
|
|
||||||
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T : AbstractVertexBuilder<T>> T.quadRotatedZ(
|
|
||||||
x0: Float,
|
|
||||||
y0: Float,
|
|
||||||
x1: Float,
|
|
||||||
y1: Float,
|
|
||||||
z: Float,
|
|
||||||
x: Float,
|
|
||||||
y: Float,
|
|
||||||
angle: Double,
|
|
||||||
lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM
|
|
||||||
): T {
|
|
||||||
check(type.elements == 4) { "Currently building $type" }
|
|
||||||
|
|
||||||
val s = sin(angle).toFloat()
|
|
||||||
val c = cos(angle).toFloat()
|
|
||||||
|
|
||||||
lambda(vertex().pushVec3f(x + x0 * c - s * y0, y + s * x0 + c * y0, z), 0).end()
|
|
||||||
lambda(vertex().pushVec3f(x + x1 * c - s * y0, y + s * x1 + c * y0, z), 1).end()
|
|
||||||
lambda(vertex().pushVec3f(x + x0 * c - s * y1, y + s * x0 + c * y1, z), 2).end()
|
|
||||||
lambda(vertex().pushVec3f(x + x1 * c - s * y1, y + s * x1 + c * y1, z), 3).end()
|
|
||||||
|
|
||||||
return this
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
package ru.dbotthepony.kstarbound.client.gl.vertex
|
|
||||||
|
|
||||||
import org.lwjgl.opengl.GL46
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.VertexBufferObject
|
|
||||||
import ru.dbotthepony.kstarbound.util.ByteBufferOutputStream
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Создаёт буфер для данных вне кучи, записывает данные напрямую в него,
|
|
||||||
* при [upload] загружает данные из буфера напрямую в память видеокарты.
|
|
||||||
*/
|
|
||||||
open class DirectVertexBuilder<T : DirectVertexBuilder<T>>(
|
|
||||||
attributes: GLAttributeList,
|
|
||||||
type: GeometryType,
|
|
||||||
val maxElements: Int,
|
|
||||||
) : AbstractVertexBuilder<DirectVertexBuilder<T>>(attributes, type) {
|
|
||||||
val maxIndexCount = maxElements * type.indices.size
|
|
||||||
val maxVertexCount = maxElements * type.elements
|
|
||||||
|
|
||||||
final override val elementIndexType: Int = when (maxIndexCount) {
|
|
||||||
// api performance issue 102: glDrawElements uses element index type 'GL_UNSIGNED_BYTE' that is not optimal for the current hardware configuration; consider using 'GL_UNSIGNED_SHORT' instead
|
|
||||||
// in 0 .. 255 -> GL_UNSIGNED_BYTE
|
|
||||||
in 0 .. 65535 -> GL46.GL_UNSIGNED_SHORT
|
|
||||||
else -> GL46.GL_UNSIGNED_INT
|
|
||||||
}
|
|
||||||
|
|
||||||
final override val vertexMemory = ByteBufferOutputStream.directLE(maxVertexCount * attributes.stride)
|
|
||||||
final override val elementMemory = ByteBufferOutputStream.directLE(maxIndexCount * (if (elementIndexType == GL46.GL_UNSIGNED_SHORT) 2 else 4))
|
|
||||||
|
|
||||||
override fun ensureIndexCapacity() {
|
|
||||||
if (vertexCount > maxVertexCount) {
|
|
||||||
throw IndexOutOfBoundsException("Vertex count overflow (can hold max of $maxElements elements, that's $maxVertexCount vertexes)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun resetMemory() {
|
|
||||||
vertexMemory.position = 0
|
|
||||||
elementMemory.position = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun doUpload(vbo: VertexBufferObject, ebo: VertexBufferObject, drawType: Int) {
|
|
||||||
val vertexPos = vertexMemory.position
|
|
||||||
val elementPos = elementMemory.position
|
|
||||||
|
|
||||||
vertexMemory.position = 0
|
|
||||||
elementMemory.position = 0
|
|
||||||
|
|
||||||
vbo.bufferData(vertexMemory.buffer, drawType, length = vertexPos.toLong())
|
|
||||||
ebo.bufferData(elementMemory.buffer, drawType, length = elementPos.toLong())
|
|
||||||
|
|
||||||
vertexMemory.position = vertexPos
|
|
||||||
elementMemory.position = elementPos
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,16 @@
|
|||||||
package ru.dbotthepony.kstarbound.client.gl.vertex
|
package ru.dbotthepony.kstarbound.client.gl.vertex
|
||||||
|
|
||||||
enum class GeometryType(val elements: Int, val indices: IntArray) {
|
enum class GeometryType(
|
||||||
|
/**
|
||||||
|
* Число вершин у одного элемента
|
||||||
|
*/
|
||||||
|
val elements: Int,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Индекс вершин одного элемента
|
||||||
|
*/
|
||||||
|
val indices: IntArray
|
||||||
|
) {
|
||||||
AS_IS(1, intArrayOf(0)),
|
AS_IS(1, intArrayOf(0)),
|
||||||
LINES(2, intArrayOf(0, 1)),
|
LINES(2, intArrayOf(0, 1)),
|
||||||
TRIANGLES(3, intArrayOf(0, 1, 2)),
|
TRIANGLES(3, intArrayOf(0, 1, 2)),
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
package ru.dbotthepony.kstarbound.client.gl.vertex
|
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.io.FastByteArrayInputStream
|
|
||||||
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
|
|
||||||
import org.lwjgl.opengl.GL11.GL_UNSIGNED_INT
|
|
||||||
import org.lwjgl.opengl.GL11.GL_UNSIGNED_SHORT
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.VertexBufferObject
|
|
||||||
import ru.dbotthepony.kstarbound.util.readLEShort
|
|
||||||
import ru.dbotthepony.kstarbound.util.writeLEInt
|
|
||||||
import java.nio.ByteBuffer
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Vertex Builder который хранит все данные на куче, при [upload] создаётся [ByteBuffer] вне кучи,
|
|
||||||
* в него записываются данные из кучи, данные загружаются на видеокарту.
|
|
||||||
*
|
|
||||||
* Полезен в случаях, когда размер данных для загрузки заранее не известен.
|
|
||||||
*/
|
|
||||||
open class HeapVertexBuilder<T : HeapVertexBuilder<T>>(
|
|
||||||
attributes: GLAttributeList,
|
|
||||||
type: GeometryType,
|
|
||||||
) : AbstractVertexBuilder<T>(attributes, type) {
|
|
||||||
final override val vertexMemory = FastByteArrayOutputStream()
|
|
||||||
final override val elementMemory = FastByteArrayOutputStream()
|
|
||||||
|
|
||||||
final override var elementIndexType: Int = GL_UNSIGNED_SHORT
|
|
||||||
private set
|
|
||||||
|
|
||||||
final override fun ensureIndexCapacity() {
|
|
||||||
if (elementIndexType == GL_UNSIGNED_SHORT && elementMemory.length / 2 + type.indices.size >= 30000) {
|
|
||||||
val backing = elementMemory.array
|
|
||||||
val copy = FastByteArrayInputStream(ByteArray(elementMemory.length) { backing[it] })
|
|
||||||
|
|
||||||
elementIndexType = GL_UNSIGNED_INT
|
|
||||||
val elementMemory = elementMemory
|
|
||||||
elementMemory.reset()
|
|
||||||
|
|
||||||
for (i in 0 until (copy.length / 2)) {
|
|
||||||
elementMemory.writeLEInt(copy.readLEShort())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final override fun resetMemory() {
|
|
||||||
vertexMemory.reset()
|
|
||||||
elementMemory.reset()
|
|
||||||
}
|
|
||||||
|
|
||||||
final override fun doUpload(vbo: VertexBufferObject, ebo: VertexBufferObject, drawType: Int) {
|
|
||||||
val vboMemory = ByteBuffer.allocateDirect(vertexMemory.length)
|
|
||||||
vboMemory.put(vertexMemory.array, 0, vertexMemory.length)
|
|
||||||
|
|
||||||
val eboMemory = ByteBuffer.allocateDirect(elementMemory.length)
|
|
||||||
eboMemory.put(elementMemory.array, 0, elementMemory.length)
|
|
||||||
|
|
||||||
vboMemory.position(0)
|
|
||||||
eboMemory.position(0)
|
|
||||||
|
|
||||||
vbo.bufferData(vboMemory, drawType)
|
|
||||||
ebo.bufferData(eboMemory, drawType)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
package ru.dbotthepony.kstarbound.client.gl.vertex
|
package ru.dbotthepony.kstarbound.client.gl.vertex
|
||||||
|
|
||||||
typealias QuadVertexTransformer = (AbstractVertexBuilder<*>, Int) -> AbstractVertexBuilder<*>
|
typealias QuadVertexTransformer = (VertexBuilder, Int) -> VertexBuilder
|
||||||
|
|
||||||
val EMPTY_VERTEX_TRANSFORM: QuadVertexTransformer = { it, _ -> it }
|
val EMPTY_VERTEX_TRANSFORM: QuadVertexTransformer = { it, _ -> it }
|
||||||
|
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
package ru.dbotthepony.kstarbound.client.gl.vertex
|
|
||||||
|
|
||||||
import org.lwjgl.opengl.GL46
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.checkForGLError
|
|
||||||
import java.io.Closeable
|
|
||||||
|
|
||||||
class StatefulVertexBuilder(
|
|
||||||
val state: GLStateTracker,
|
|
||||||
attributes: GLAttributeList,
|
|
||||||
type: GeometryType,
|
|
||||||
) : HeapVertexBuilder<StatefulVertexBuilder>(attributes, type), Closeable {
|
|
||||||
private val vao = state.newVAO()
|
|
||||||
private val vbo = state.newVBO()
|
|
||||||
private val ebo = state.newEBO()
|
|
||||||
|
|
||||||
init {
|
|
||||||
vao.bind()
|
|
||||||
vbo.bind()
|
|
||||||
ebo.bind()
|
|
||||||
|
|
||||||
attributes.apply(vao, true)
|
|
||||||
|
|
||||||
vao.unbind()
|
|
||||||
vbo.unbind()
|
|
||||||
ebo.unbind()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun upload(drawType: Int = GL46.GL_STATIC_DRAW) {
|
|
||||||
upload(vbo, ebo, drawType)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun bind() = vao.bind()
|
|
||||||
fun unbind() = vao.unbind()
|
|
||||||
|
|
||||||
fun draw(primitives: Int = GL46.GL_TRIANGLES) {
|
|
||||||
bind()
|
|
||||||
GL46.glDrawElements(primitives, indexCount, elementIndexType, 0L)
|
|
||||||
checkForGLError()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun close() {
|
|
||||||
vao.close()
|
|
||||||
vbo.close()
|
|
||||||
ebo.close()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,21 +1,20 @@
|
|||||||
package ru.dbotthepony.kstarbound.client.gl.vertex
|
package ru.dbotthepony.kstarbound.client.gl.vertex
|
||||||
|
|
||||||
import org.lwjgl.opengl.GL46
|
import org.lwjgl.opengl.GL46
|
||||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
||||||
import ru.dbotthepony.kstarbound.client.gl.GLTexture2D
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.checkForGLError
|
import ru.dbotthepony.kstarbound.client.gl.checkForGLError
|
||||||
import java.io.Closeable
|
import java.io.Closeable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Класс-помощник для быстрого построения, загрузки и отрисовки геометрии
|
* Быстрое наполнение буфера вершинами, загрузка в память видеокарты, и отрисовка
|
||||||
*/
|
*/
|
||||||
class StreamVertexBuilder(
|
class StreamVertexBuilder(
|
||||||
val state: GLStateTracker,
|
val state: GLStateTracker,
|
||||||
attributes: GLAttributeList,
|
attributes: GLAttributeList,
|
||||||
type: GeometryType,
|
type: GeometryType,
|
||||||
maxElements: Int,
|
initialCapacity: Int = 64,
|
||||||
) : DirectVertexBuilder<StreamVertexBuilder>(attributes, type, maxElements), Closeable {
|
) : Closeable {
|
||||||
|
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()
|
||||||
private val ebo = state.newEBO()
|
private val ebo = state.newEBO()
|
||||||
@ -33,7 +32,7 @@ class StreamVertexBuilder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun upload(drawType: Int = GL46.GL_DYNAMIC_DRAW) {
|
fun upload(drawType: Int = GL46.GL_DYNAMIC_DRAW) {
|
||||||
upload(vbo, ebo, drawType)
|
builder.upload(vbo, ebo, drawType)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun bind() = vao.bind()
|
fun bind() = vao.bind()
|
||||||
@ -41,7 +40,7 @@ class StreamVertexBuilder(
|
|||||||
|
|
||||||
fun draw(primitives: Int = GL46.GL_TRIANGLES) {
|
fun draw(primitives: Int = GL46.GL_TRIANGLES) {
|
||||||
bind()
|
bind()
|
||||||
GL46.glDrawElements(primitives, indexCount, elementIndexType, 0L)
|
GL46.glDrawElements(primitives, builder.indexCount, builder.indexType, 0L)
|
||||||
checkForGLError()
|
checkForGLError()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,9 +51,9 @@ class StreamVertexBuilder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
begin()
|
builder.begin()
|
||||||
|
|
||||||
quadRotatedZ(x, y, width, height, z, 0f, 0f, angle, transformer)
|
builder.quadRotatedZ(x, y, width, height, z, 0f, 0f, angle, transformer)
|
||||||
|
|
||||||
upload()
|
upload()
|
||||||
draw()
|
draw()
|
||||||
|
@ -0,0 +1,407 @@
|
|||||||
|
package ru.dbotthepony.kstarbound.client.gl.vertex
|
||||||
|
|
||||||
|
import org.lwjgl.opengl.GL46
|
||||||
|
import org.lwjgl.opengl.GL46.GL_UNSIGNED_INT
|
||||||
|
import org.lwjgl.opengl.GL46.GL_UNSIGNED_SHORT
|
||||||
|
import org.lwjgl.opengl.GL46.GL_UNSIGNED_BYTE
|
||||||
|
import ru.dbotthepony.kstarbound.client.gl.GLType
|
||||||
|
import ru.dbotthepony.kstarbound.client.gl.VertexBufferObject
|
||||||
|
import ru.dbotthepony.kvector.util2d.AABB
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import java.nio.ByteOrder
|
||||||
|
import kotlin.math.cos
|
||||||
|
import kotlin.math.sin
|
||||||
|
|
||||||
|
private fun interface IndexWriter {
|
||||||
|
fun write(buffer: ByteBuffer, value: Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun writer(type: Int): IndexWriter {
|
||||||
|
return when (type) {
|
||||||
|
GL_UNSIGNED_SHORT -> IndexWriter { it, value -> it.putShort(value.toShort()) }
|
||||||
|
GL_UNSIGNED_BYTE -> IndexWriter { it, value -> it.put(value.toByte()) }
|
||||||
|
else -> IndexWriter { it, value -> it.putInt(value) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun chooseIndexType(capacity: Int): Int {
|
||||||
|
return when (capacity) {
|
||||||
|
// api performance issue 102: glDrawElements uses element index type 'GL_UNSIGNED_BYTE' that is not optimal for the current hardware configuration; consider using 'GL_UNSIGNED_SHORT' instead
|
||||||
|
// in 0 .. 255 -> GL_UNSIGNED_BYTE
|
||||||
|
in 0 .. 65535 -> GL_UNSIGNED_SHORT
|
||||||
|
else -> GL_UNSIGNED_INT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun indexSize(type: Int): Int {
|
||||||
|
return when (type) {
|
||||||
|
GL_UNSIGNED_BYTE -> 1
|
||||||
|
GL_UNSIGNED_SHORT -> 2
|
||||||
|
GL_UNSIGNED_INT -> 4
|
||||||
|
else -> throw IllegalStateException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Создаёт буферы вне кучи для загрузки геометрии в них, с набором аттрибутов [attributes], типом [type] и указанным начальным размером.
|
||||||
|
*
|
||||||
|
* По мере необходимости, буферы могут быть увеличены в размерах.
|
||||||
|
*
|
||||||
|
* Загрузка в память видеокарты происходит напрямую из буферов, через метод [upload]
|
||||||
|
*/
|
||||||
|
@Suppress("unchecked_cast")
|
||||||
|
class VertexBuilder(
|
||||||
|
val attributes: GLAttributeList,
|
||||||
|
val type: GeometryType,
|
||||||
|
initialCapacity: Int = 64
|
||||||
|
) {
|
||||||
|
/**
|
||||||
|
* [GL_UNSIGNED_BYTE], [GL_UNSIGNED_SHORT] или [GL_UNSIGNED_INT]
|
||||||
|
*/
|
||||||
|
var indexType: Int = chooseIndexType(initialCapacity)
|
||||||
|
private set
|
||||||
|
var indexSize: Int = indexSize(indexType)
|
||||||
|
private set
|
||||||
|
|
||||||
|
/**
|
||||||
|
* В элементах, не вершинах
|
||||||
|
*/
|
||||||
|
private var capacity = initialCapacity
|
||||||
|
private var vertexMemory = ByteBuffer.allocateDirect(capacity * attributes.stride * type.elements).also { it.order(ByteOrder.LITTLE_ENDIAN) }
|
||||||
|
private var indexMemory = ByteBuffer.allocateDirect(capacity * indexSize * type.indices.size).also { it.order(ByteOrder.LITTLE_ENDIAN) }
|
||||||
|
private var indexWriter = writer(indexType)
|
||||||
|
|
||||||
|
private var inVertex = false
|
||||||
|
private var attributeIndex = 0
|
||||||
|
private var elementIndexOffset = 0
|
||||||
|
|
||||||
|
private var elementVertices = 0
|
||||||
|
|
||||||
|
var vertexCount = 0
|
||||||
|
private set
|
||||||
|
|
||||||
|
var indexCount = 0
|
||||||
|
private set
|
||||||
|
|
||||||
|
var elementCount = 0
|
||||||
|
private set
|
||||||
|
|
||||||
|
fun begin() {
|
||||||
|
inVertex = false
|
||||||
|
attributeIndex = 0
|
||||||
|
elementIndexOffset = 0
|
||||||
|
vertexCount = 0
|
||||||
|
indexCount = 0
|
||||||
|
elementCount = 0
|
||||||
|
vertexMemory.position(0)
|
||||||
|
indexMemory.position(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkBounds() {
|
||||||
|
if (attributeIndex >= attributes.size) {
|
||||||
|
throw IndexOutOfBoundsException("Tried to add new attribute when already added all attributes")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun expect(type: GLType) {
|
||||||
|
checkBounds()
|
||||||
|
|
||||||
|
if (attributes[attributeIndex].glType != type) {
|
||||||
|
throw IllegalStateException("Expected attribute type $type, got ${attributes[attributeIndex].name}[${attributes[attributeIndex].glType}] (at position $attributeIndex)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun expect(name: String) {
|
||||||
|
checkBounds()
|
||||||
|
|
||||||
|
if (attributes[attributeIndex].name != name) {
|
||||||
|
throw IllegalStateException("Expected attribute name $name, got ${attributes[attributeIndex].name}[${attributes[attributeIndex].glType}] (at position $attributeIndex)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun upload(vbo: VertexBufferObject, ebo: VertexBufferObject, drawType: Int = GL46.GL_DYNAMIC_DRAW) {
|
||||||
|
require(vbo.isArray) { "$vbo is not an array" }
|
||||||
|
require(ebo.isElementArray) { "$ebo is not an element array" }
|
||||||
|
|
||||||
|
end()
|
||||||
|
|
||||||
|
check(elementVertices == 0) { "Not fully built vertex element ($type requires ${type.elements} vertex points to be present, yet last strip has only $elementVertices elements)" }
|
||||||
|
|
||||||
|
val vertexPos = vertexMemory.position()
|
||||||
|
val elementPos = indexMemory.position()
|
||||||
|
|
||||||
|
vertexMemory.position(0)
|
||||||
|
indexMemory.position(0)
|
||||||
|
|
||||||
|
vbo.bufferData(vertexMemory, drawType, length = vertexPos.toLong())
|
||||||
|
ebo.bufferData(indexMemory, drawType, length = elementPos.toLong())
|
||||||
|
|
||||||
|
vertexMemory.position(vertexPos)
|
||||||
|
indexMemory.position(elementPos)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun end() {
|
||||||
|
if (inVertex) {
|
||||||
|
inVertex = false
|
||||||
|
|
||||||
|
if (attributeIndex != attributes.size) {
|
||||||
|
throw IllegalStateException("Unfinished vertex, we are at $attributeIndex, while we have ${attributes.size} attributes")
|
||||||
|
}
|
||||||
|
|
||||||
|
vertexCount++
|
||||||
|
elementVertices++
|
||||||
|
|
||||||
|
if (elementVertices == type.elements) {
|
||||||
|
elementCount++
|
||||||
|
elementVertices = 0
|
||||||
|
|
||||||
|
for (index in type.indices) {
|
||||||
|
indexWriter.write(indexMemory, index + elementIndexOffset)
|
||||||
|
}
|
||||||
|
|
||||||
|
elementIndexOffset += type.elements
|
||||||
|
indexCount += type.indices.size
|
||||||
|
|
||||||
|
if (capacity <= elementCount) {
|
||||||
|
check(this.vertexMemory.position() == this.vertexMemory.capacity()) { "${this.vertexMemory.position()} != ${this.vertexMemory.capacity()}" }
|
||||||
|
check(this.indexMemory.position() == this.indexMemory.capacity()) { "${this.indexMemory.position()} != ${this.indexMemory.capacity()}" }
|
||||||
|
|
||||||
|
val capacity = capacity * 2
|
||||||
|
val indexType = chooseIndexType(capacity)
|
||||||
|
val indexSize = indexSize(indexType)
|
||||||
|
|
||||||
|
val vertexMemory = ByteBuffer.allocateDirect(capacity * attributes.stride * type.elements)
|
||||||
|
vertexMemory.order(ByteOrder.LITTLE_ENDIAN)
|
||||||
|
|
||||||
|
this.vertexMemory.position(0)
|
||||||
|
vertexMemory.put(this.vertexMemory)
|
||||||
|
|
||||||
|
val indexMemory = ByteBuffer.allocateDirect(capacity * indexSize * type.indices.size)
|
||||||
|
indexMemory.order(ByteOrder.LITTLE_ENDIAN)
|
||||||
|
|
||||||
|
if (indexType != this.indexType) {
|
||||||
|
when (this.indexType) {
|
||||||
|
GL_UNSIGNED_BYTE -> {
|
||||||
|
when (indexType) {
|
||||||
|
GL_UNSIGNED_BYTE -> throw IllegalArgumentException()
|
||||||
|
GL_UNSIGNED_SHORT -> {
|
||||||
|
this.indexMemory.position(0)
|
||||||
|
|
||||||
|
for (i in 0 until this.capacity) {
|
||||||
|
indexMemory.putShort(this.indexMemory.get().toShort())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GL_UNSIGNED_INT -> {
|
||||||
|
this.indexMemory.position(0)
|
||||||
|
|
||||||
|
for (i in 0 until this.capacity) {
|
||||||
|
indexMemory.putInt(this.indexMemory.get().toInt())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GL_UNSIGNED_SHORT -> {
|
||||||
|
when (indexType) {
|
||||||
|
GL_UNSIGNED_BYTE -> throw IllegalArgumentException()
|
||||||
|
GL_UNSIGNED_SHORT -> throw IllegalArgumentException()
|
||||||
|
GL_UNSIGNED_INT -> {
|
||||||
|
this.indexMemory.position(0)
|
||||||
|
|
||||||
|
for (i in 0 until this.capacity) {
|
||||||
|
indexMemory.putInt(this.indexMemory.getShort().toInt())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> throw IllegalArgumentException()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.indexMemory.position(0)
|
||||||
|
indexMemory.put(this.indexMemory)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.capacity = capacity
|
||||||
|
this.vertexMemory = vertexMemory
|
||||||
|
this.indexMemory = indexMemory
|
||||||
|
this.indexType = indexType
|
||||||
|
this.indexSize = indexSize
|
||||||
|
this.indexWriter = writer(indexType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun vertex(): VertexBuilder {
|
||||||
|
end()
|
||||||
|
|
||||||
|
inVertex = true
|
||||||
|
attributeIndex = 0
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun pushVec4f(x: Float, y: Float, z: Float, w: Float): VertexBuilder {
|
||||||
|
expect(GLType.VEC4F)
|
||||||
|
val memory = vertexMemory
|
||||||
|
memory.putFloat(x)
|
||||||
|
memory.putFloat(y)
|
||||||
|
memory.putFloat(z)
|
||||||
|
memory.putFloat(w)
|
||||||
|
attributeIndex++
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun pushVec3f(x: Float, y: Float, z: Float): VertexBuilder {
|
||||||
|
expect(GLType.VEC3F)
|
||||||
|
val memory = vertexMemory
|
||||||
|
memory.putFloat(x)
|
||||||
|
memory.putFloat(y)
|
||||||
|
memory.putFloat(z)
|
||||||
|
attributeIndex++
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun pushVec2f(x: Float, y: Float): VertexBuilder {
|
||||||
|
expect(GLType.VEC2F)
|
||||||
|
val memory = vertexMemory
|
||||||
|
memory.putFloat(x)
|
||||||
|
memory.putFloat(y)
|
||||||
|
attributeIndex++
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun push(value: Float): VertexBuilder {
|
||||||
|
expect(GLType.FLOAT)
|
||||||
|
vertexMemory.putFloat(value)
|
||||||
|
attributeIndex++
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun shadowLine(x0: Float, y0: Float, x1: Float, y1: Float): VertexBuilder {
|
||||||
|
vertex()
|
||||||
|
pushVec4f(x0, y0, x1, y1)
|
||||||
|
pushVec2f(0f, 0f)
|
||||||
|
|
||||||
|
vertex()
|
||||||
|
pushVec4f(x0, y0, x1, y1)
|
||||||
|
pushVec2f(0f, 1f)
|
||||||
|
|
||||||
|
vertex()
|
||||||
|
pushVec4f(x0, y0, x1, y1)
|
||||||
|
pushVec2f(1f, 1f)
|
||||||
|
|
||||||
|
vertex()
|
||||||
|
pushVec4f(x0, y0, x1, y1)
|
||||||
|
pushVec2f(1f, 0f)
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun dfShadowLine(x0: Float, y0: Float, x1: Float, y1: Float): VertexBuilder {
|
||||||
|
shadowLine(x0, y0, x1, y1)
|
||||||
|
shadowLine(x1, y1, x0, y0)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun shadowQuad(x0: Float, y0: Float, x1: Float, y1: Float): VertexBuilder {
|
||||||
|
shadowLine(x0, y0, x1, y0)
|
||||||
|
shadowLine(x1, y0, x1, y1)
|
||||||
|
shadowLine(x1, y1, x0, y1)
|
||||||
|
shadowLine(x0, y1, x0, y0)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
// Помощники
|
||||||
|
fun quad(
|
||||||
|
x0: Float,
|
||||||
|
y0: Float,
|
||||||
|
x1: Float,
|
||||||
|
y1: Float,
|
||||||
|
lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM
|
||||||
|
): VertexBuilder {
|
||||||
|
check(type.elements == 4) { "Currently building $type" }
|
||||||
|
|
||||||
|
lambda(vertex().pushVec2f(x0, y0), 0).end()
|
||||||
|
lambda(vertex().pushVec2f(x1, y0), 1).end()
|
||||||
|
lambda(vertex().pushVec2f(x0, y1), 2).end()
|
||||||
|
lambda(vertex().pushVec2f(x1, y1), 3).end()
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun quadRotated(
|
||||||
|
x0: Float,
|
||||||
|
y0: Float,
|
||||||
|
x1: Float,
|
||||||
|
y1: Float,
|
||||||
|
x: Float,
|
||||||
|
y: Float,
|
||||||
|
angle: Double,
|
||||||
|
lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM
|
||||||
|
): VertexBuilder {
|
||||||
|
check(type.elements == 4) { "Currently building $type" }
|
||||||
|
|
||||||
|
val s = sin(angle).toFloat()
|
||||||
|
val c = cos(angle).toFloat()
|
||||||
|
|
||||||
|
lambda(vertex().pushVec2f(x + x0 * c - s * y0, y + s * x0 + c * y0), 0).end()
|
||||||
|
lambda(vertex().pushVec2f(x + x1 * c - s * y0, y + s * x1 + c * y0), 1).end()
|
||||||
|
lambda(vertex().pushVec2f(x + x0 * c - s * y1, y + s * x0 + c * y1), 2).end()
|
||||||
|
lambda(vertex().pushVec2f(x + x1 * c - s * y1, y + s * x1 + c * y1), 3).end()
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun quad(aabb: AABB, lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM): VertexBuilder {
|
||||||
|
return quad(
|
||||||
|
aabb.mins.x.toFloat(),
|
||||||
|
aabb.mins.y.toFloat(),
|
||||||
|
aabb.maxs.x.toFloat(),
|
||||||
|
aabb.maxs.y.toFloat(),
|
||||||
|
lambda
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun quadZ(
|
||||||
|
x0: Float,
|
||||||
|
y0: Float,
|
||||||
|
x1: Float,
|
||||||
|
y1: Float,
|
||||||
|
z: Float,
|
||||||
|
lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM
|
||||||
|
): VertexBuilder {
|
||||||
|
check(type.elements == 4) { "Currently building $type" }
|
||||||
|
|
||||||
|
lambda(vertex().pushVec3f(x0, y0, z), 0).end()
|
||||||
|
lambda(vertex().pushVec3f(x1, y0, z), 1).end()
|
||||||
|
lambda(vertex().pushVec3f(x0, y1, z), 2).end()
|
||||||
|
lambda(vertex().pushVec3f(x1, y1, z), 3).end()
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun quadRotatedZ(
|
||||||
|
x0: Float,
|
||||||
|
y0: Float,
|
||||||
|
x1: Float,
|
||||||
|
y1: Float,
|
||||||
|
z: Float,
|
||||||
|
x: Float,
|
||||||
|
y: Float,
|
||||||
|
angle: Double,
|
||||||
|
lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM
|
||||||
|
): VertexBuilder {
|
||||||
|
check(type.elements == 4) { "Currently building $type" }
|
||||||
|
|
||||||
|
val s = sin(angle).toFloat()
|
||||||
|
val c = cos(angle).toFloat()
|
||||||
|
|
||||||
|
lambda(vertex().pushVec3f(x + x0 * c - s * y0, y + s * x0 + c * y0, z), 0).end()
|
||||||
|
lambda(vertex().pushVec3f(x + x1 * c - s * y0, y + s * x1 + c * y0, z), 1).end()
|
||||||
|
lambda(vertex().pushVec3f(x + x0 * c - s * y1, y + s * x0 + c * y1, z), 2).end()
|
||||||
|
lambda(vertex().pushVec3f(x + x1 * c - s * y1, y + s * x1 + c * y1, z), 3).end()
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
@ -20,15 +20,15 @@ class Box2DRenderer(val state: GLStateTracker) : IDebugDraw {
|
|||||||
override fun drawPolygon(vertices: List<Vector2d>, color: Color) {
|
override fun drawPolygon(vertices: List<Vector2d>, color: Color) {
|
||||||
require(vertices.size > 1) { "Vertex list had only ${vertices.size} namings in it" }
|
require(vertices.size > 1) { "Vertex list had only ${vertices.size} namings in it" }
|
||||||
|
|
||||||
val builder = state.flat2DLines.small
|
val builder = state.flat2DLines
|
||||||
|
|
||||||
builder.begin()
|
builder.builder.begin()
|
||||||
|
|
||||||
for (i in vertices.indices) {
|
for (i in vertices.indices) {
|
||||||
val current = vertices[i]
|
val current = vertices[i]
|
||||||
val next = vertices[(i + 1) % vertices.size]
|
val next = vertices[(i + 1) % vertices.size]
|
||||||
builder.vertex().pushVec2f(current.x.toFloat(), current.y.toFloat())
|
builder.builder.vertex().pushVec2f(current.x.toFloat(), current.y.toFloat())
|
||||||
builder.vertex().pushVec2f(next.x.toFloat(), next.y.toFloat())
|
builder.builder.vertex().pushVec2f(next.x.toFloat(), next.y.toFloat())
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.upload()
|
builder.upload()
|
||||||
@ -43,18 +43,18 @@ class Box2DRenderer(val state: GLStateTracker) : IDebugDraw {
|
|||||||
private fun drawSolid(vertices: List<Vector2d>, color: Color) {
|
private fun drawSolid(vertices: List<Vector2d>, color: Color) {
|
||||||
require(vertices.size >= 3) { "Vertex list had only ${vertices.size} namings in it" }
|
require(vertices.size >= 3) { "Vertex list had only ${vertices.size} namings in it" }
|
||||||
|
|
||||||
val builder = state.flat2DTriangles.small
|
val builder = state.flat2DTriangles
|
||||||
|
|
||||||
builder.begin()
|
builder.builder.begin()
|
||||||
|
|
||||||
val zero = vertices[0]
|
val zero = vertices[0]
|
||||||
|
|
||||||
for (i in 1 until vertices.size) {
|
for (i in 1 until vertices.size) {
|
||||||
val current = vertices[i]
|
val current = vertices[i]
|
||||||
val next = vertices[(i + 1) % vertices.size]
|
val next = vertices[(i + 1) % vertices.size]
|
||||||
builder.vertex().pushVec2f(zero.x.toFloat(), zero.y.toFloat())
|
builder.builder.vertex().pushVec2f(zero.x.toFloat(), zero.y.toFloat())
|
||||||
builder.vertex().pushVec2f(current.x.toFloat(), current.y.toFloat())
|
builder.builder.vertex().pushVec2f(current.x.toFloat(), current.y.toFloat())
|
||||||
builder.vertex().pushVec2f(next.x.toFloat(), next.y.toFloat())
|
builder.builder.vertex().pushVec2f(next.x.toFloat(), next.y.toFloat())
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.upload()
|
builder.upload()
|
||||||
|
@ -4,7 +4,7 @@ import org.lwjgl.opengl.GL46.*
|
|||||||
import ru.dbotthepony.kstarbound.client.gl.program.GLShaderProgram
|
import ru.dbotthepony.kstarbound.client.gl.program.GLShaderProgram
|
||||||
import ru.dbotthepony.kstarbound.client.gl.VertexArrayObject
|
import ru.dbotthepony.kstarbound.client.gl.VertexArrayObject
|
||||||
import ru.dbotthepony.kstarbound.client.gl.checkForGLError
|
import ru.dbotthepony.kstarbound.client.gl.checkForGLError
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.AbstractVertexBuilder
|
import ru.dbotthepony.kstarbound.client.gl.vertex.VertexBuilder
|
||||||
import ru.dbotthepony.kvector.api.IFloatMatrix
|
import ru.dbotthepony.kvector.api.IFloatMatrix
|
||||||
import ru.dbotthepony.kvector.matrix.Matrix4fStack
|
import ru.dbotthepony.kvector.matrix.Matrix4fStack
|
||||||
|
|
||||||
@ -47,11 +47,11 @@ class ConfiguredStaticMesh(
|
|||||||
) : AutoCloseable {
|
) : AutoCloseable {
|
||||||
private var onClose = {}
|
private var onClose = {}
|
||||||
|
|
||||||
constructor(programState: ConfiguredShaderProgram, builder: AbstractVertexBuilder<*>) : this(
|
constructor(programState: ConfiguredShaderProgram, builder: VertexBuilder) : this(
|
||||||
programState,
|
programState,
|
||||||
builder.indexCount,
|
builder.indexCount,
|
||||||
programState.program.state.newVAO(),
|
programState.program.state.newVAO(),
|
||||||
builder.elementIndexType,
|
builder.indexType,
|
||||||
) {
|
) {
|
||||||
val vbo = programState.program.state.newVBO()
|
val vbo = programState.program.state.newVBO()
|
||||||
val ebo = programState.program.state.newEBO()
|
val ebo = programState.program.state.newEBO()
|
||||||
|
@ -7,10 +7,9 @@ import ru.dbotthepony.kstarbound.client.freetype.LoadFlag
|
|||||||
import ru.dbotthepony.kstarbound.client.gl.*
|
import ru.dbotthepony.kstarbound.client.gl.*
|
||||||
import ru.dbotthepony.kstarbound.client.freetype.struct.FT_Pixel_Mode
|
import ru.dbotthepony.kstarbound.client.freetype.struct.FT_Pixel_Mode
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GLAttributeList
|
import ru.dbotthepony.kstarbound.client.gl.vertex.GLAttributeList
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.HeapVertexBuilder
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.quad
|
import ru.dbotthepony.kstarbound.client.gl.vertex.VertexBuilder
|
||||||
import ru.dbotthepony.kvector.matrix.Matrix4fStack
|
import ru.dbotthepony.kvector.matrix.Matrix4fStack
|
||||||
import ru.dbotthepony.kvector.vector.Color
|
import ru.dbotthepony.kvector.vector.Color
|
||||||
|
|
||||||
@ -308,14 +307,14 @@ class Font(
|
|||||||
ebo.bind()
|
ebo.bind()
|
||||||
vbo.bind()
|
vbo.bind()
|
||||||
|
|
||||||
val builder = HeapVertexBuilder(GLAttributeList.VERTEX_2D_TEXTURE, GeometryType.QUADS)
|
val builder = VertexBuilder(GLAttributeList.VERTEX_2D_TEXTURE, GeometryType.QUADS)
|
||||||
|
|
||||||
builder.quad(0f, 0f, width, height, QuadTransformers.uv())
|
builder.quad(0f, 0f, width, height, QuadTransformers.uv())
|
||||||
builder.upload(vbo, ebo, GL_STATIC_DRAW)
|
builder.upload(vbo, ebo, GL_STATIC_DRAW)
|
||||||
builder.attributes.apply(vao, true)
|
builder.attributes.apply(vao, true)
|
||||||
indexCount = builder.indexCount
|
indexCount = builder.indexCount
|
||||||
|
|
||||||
elementIndexType = builder.elementIndexType
|
elementIndexType = builder.indexType
|
||||||
|
|
||||||
vao.unbind()
|
vao.unbind()
|
||||||
ebo.unbind()
|
ebo.unbind()
|
||||||
|
@ -16,7 +16,6 @@ import ru.dbotthepony.kstarbound.client.gl.vertex.GLAttributeList
|
|||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.StreamVertexBuilder
|
import ru.dbotthepony.kstarbound.client.gl.vertex.StreamVertexBuilder
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.quad
|
|
||||||
import ru.dbotthepony.kvector.matrix.Matrix4fStack
|
import ru.dbotthepony.kvector.matrix.Matrix4fStack
|
||||||
import ru.dbotthepony.kvector.vector.Color
|
import ru.dbotthepony.kvector.vector.Color
|
||||||
import ru.dbotthepony.kvector.vector.nfloat.Vector2f
|
import ru.dbotthepony.kvector.vector.nfloat.Vector2f
|
||||||
@ -182,8 +181,8 @@ class GPULightRenderer(val state: GLStateTracker) {
|
|||||||
// Свет
|
// Свет
|
||||||
val builder = state.programs.light.builder
|
val builder = state.programs.light.builder
|
||||||
|
|
||||||
builder.begin()
|
builder.builder.begin()
|
||||||
builder.quad(position.x - radius, position.y - radius, position.x + radius, position.y + radius, QuadTransformers.uv())
|
builder.builder.quad(position.x - radius, position.y - radius, position.x + radius, position.y + radius, QuadTransformers.uv())
|
||||||
builder.upload()
|
builder.upload()
|
||||||
|
|
||||||
state.blendFunc = BLEND_MODE_INV
|
state.blendFunc = BLEND_MODE_INV
|
||||||
@ -248,8 +247,8 @@ class GPULightRenderer(val state: GLStateTracker) {
|
|||||||
// Свет
|
// Свет
|
||||||
val builder = state.programs.light.builder
|
val builder = state.programs.light.builder
|
||||||
|
|
||||||
builder.begin()
|
builder.builder.begin()
|
||||||
builder.quad(position.x - radius, position.y - radius, position.x + radius, position.y + radius, QuadTransformers.uv())
|
builder.builder.quad(position.x - radius, position.y - radius, position.x + radius, position.y + radius, QuadTransformers.uv())
|
||||||
builder.upload()
|
builder.upload()
|
||||||
|
|
||||||
state.blendFunc = BLEND_MODE_SOFT
|
state.blendFunc = BLEND_MODE_SOFT
|
||||||
|
@ -18,7 +18,7 @@ import kotlin.collections.HashMap
|
|||||||
|
|
||||||
data class TileLayer(
|
data class TileLayer(
|
||||||
val bakedProgramState: ConfiguredShaderProgram,
|
val bakedProgramState: ConfiguredShaderProgram,
|
||||||
val vertexBuilder: AbstractVertexBuilder<*>,
|
val vertexBuilder: VertexBuilder,
|
||||||
val zPos: Int
|
val zPos: Int
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ class TileLayerList {
|
|||||||
*
|
*
|
||||||
* Если такого слоя нет, вызывается [compute] и создаётся новый [TileLayer], затем возвращается результат [compute].
|
* Если такого слоя нет, вызывается [compute] и создаётся новый [TileLayer], затем возвращается результат [compute].
|
||||||
*/
|
*/
|
||||||
fun computeIfAbsent(program: ConfiguredShaderProgram, zLevel: Int, compute: () -> AbstractVertexBuilder<*>): AbstractVertexBuilder<*> {
|
fun computeIfAbsent(program: ConfiguredShaderProgram, zLevel: Int, compute: () -> VertexBuilder): VertexBuilder {
|
||||||
return layers.computeIfAbsent(program) { Int2ObjectAVLTreeMap() }.computeIfAbsent(zLevel, Int2ObjectFunction {
|
return layers.computeIfAbsent(program) { Int2ObjectAVLTreeMap() }.computeIfAbsent(zLevel, Int2ObjectFunction {
|
||||||
return@Int2ObjectFunction TileLayer(program, compute.invoke(), zLevel)
|
return@Int2ObjectFunction TileLayer(program, compute.invoke(), zLevel)
|
||||||
}).vertexBuilder
|
}).vertexBuilder
|
||||||
@ -169,7 +169,7 @@ private enum class TileRenderTesselateResult {
|
|||||||
HALT
|
HALT
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun vertexTextureBuilder() = HeapVertexBuilder(GLAttributeList.TILE, GeometryType.QUADS)
|
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 {
|
||||||
@ -199,7 +199,7 @@ class TileRenderer(val renderers: TileRenderers, val def: IRenderableTile) {
|
|||||||
val bakedBackgroundProgramState = renderers.background(texture)
|
val bakedBackgroundProgramState = renderers.background(texture)
|
||||||
// private var notifiedDepth = false
|
// private var notifiedDepth = false
|
||||||
|
|
||||||
private fun tesselateAt(self: ITileState, piece: RenderPiece, getter: ITileChunk, builder: AbstractVertexBuilder<*>, pos: Vector2i, offset: Vector2i = Vector2i.ZERO, isModifier: Boolean) {
|
private fun tesselateAt(self: ITileState, piece: RenderPiece, getter: ITileChunk, builder: VertexBuilder, pos: Vector2i, offset: Vector2i = Vector2i.ZERO, isModifier: Boolean) {
|
||||||
val fx = pos.x.toFloat()
|
val fx = pos.x.toFloat()
|
||||||
val fy = pos.y.toFloat()
|
val fy = pos.y.toFloat()
|
||||||
|
|
||||||
@ -246,7 +246,7 @@ class TileRenderer(val renderers: TileRenderers, val def: IRenderableTile) {
|
|||||||
getter: ITileChunk,
|
getter: ITileChunk,
|
||||||
layers: TileLayerList,
|
layers: TileLayerList,
|
||||||
pos: Vector2i,
|
pos: Vector2i,
|
||||||
thisBuilder: AbstractVertexBuilder<*>,
|
thisBuilder: VertexBuilder,
|
||||||
background: Boolean,
|
background: Boolean,
|
||||||
isModifier: Boolean,
|
isModifier: Boolean,
|
||||||
): TileRenderTesselateResult {
|
): TileRenderTesselateResult {
|
||||||
|
@ -3,8 +3,6 @@ package ru.dbotthepony.kstarbound.client.render.entity
|
|||||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
|
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
|
||||||
import ru.dbotthepony.kstarbound.client.ClientChunk
|
import ru.dbotthepony.kstarbound.client.ClientChunk
|
||||||
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.quadRotatedZ
|
|
||||||
import ru.dbotthepony.kstarbound.client.render.bind
|
import ru.dbotthepony.kstarbound.client.render.bind
|
||||||
import ru.dbotthepony.kstarbound.world.entities.ItemEntity
|
import ru.dbotthepony.kstarbound.world.entities.ItemEntity
|
||||||
import ru.dbotthepony.kvector.matrix.Matrix4fStack
|
import ru.dbotthepony.kvector.matrix.Matrix4fStack
|
||||||
@ -25,7 +23,7 @@ class ItemRenderer(state: GLStateTracker, entity: ItemEntity, chunk: ClientChunk
|
|||||||
for (texture in textures) {
|
for (texture in textures) {
|
||||||
texture.bind()
|
texture.bind()
|
||||||
|
|
||||||
state.flat2DTexturedQuads.small.singleSprite(texture.width / PIXELS_IN_STARBOUND_UNITf, texture.height / PIXELS_IN_STARBOUND_UNITf, entity.movement.angle, texture.transformer)
|
state.flat2DTexturedQuads.singleSprite(texture.width / PIXELS_IN_STARBOUND_UNITf, texture.height / PIXELS_IN_STARBOUND_UNITf, entity.movement.angle, texture.transformer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
package ru.dbotthepony.kstarbound.util
|
|
||||||
|
|
||||||
import java.io.OutputStream
|
|
||||||
import java.nio.ByteBuffer
|
|
||||||
import java.nio.ByteOrder
|
|
||||||
|
|
||||||
class ByteBufferOutputStream(val buffer: ByteBuffer) : OutputStream() {
|
|
||||||
override fun write(b: Int) {
|
|
||||||
buffer.put(b.toByte())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun write(b: ByteArray) {
|
|
||||||
buffer.put(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun write(b: ByteArray, off: Int, len: Int) {
|
|
||||||
buffer.put(b, off, len)
|
|
||||||
}
|
|
||||||
|
|
||||||
var position: Int
|
|
||||||
get() = buffer.position()
|
|
||||||
set(value) { buffer.position(value) }
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun directLE(capacity: Int) = ByteBufferOutputStream(ByteBuffer.allocateDirect(capacity).also { it.order(ByteOrder.LITTLE_ENDIAN) })
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user