diff --git a/korgw/src/commonMain/kotlin/com/soywiz/korag/shader/shaders.kt b/korgw/src/commonMain/kotlin/com/soywiz/korag/shader/shaders.kt index f16d854fb4..be3a8344f9 100644 --- a/korgw/src/commonMain/kotlin/com/soywiz/korag/shader/shaders.kt +++ b/korgw/src/commonMain/kotlin/com/soywiz/korag/shader/shaders.kt @@ -7,7 +7,8 @@ package com.soywiz.korag.shader import com.soywiz.kds.* -import com.soywiz.kmem.nextAlignedTo +import com.soywiz.kmem.* +import com.soywiz.korag.* import com.soywiz.korag.annotation.KoragExperimental import com.soywiz.korio.lang.Closeable import com.soywiz.korio.lang.invalidOp @@ -1038,38 +1039,81 @@ inline fun FragmentShader(callback: Program.Builder.() -> Unit): FragmentShader return FragmentShader(builder._buildFuncs()) } -typealias UniformLayout = ProgramLayout typealias VertexLayout = ProgramLayout -open class ProgramLayout(attr: List, private val layoutSize: Int?) { - private val myattr = attr - val attributes = attr +inline val ProgramLayout.attributes: List get() = items +inline val ProgramLayout.attributePositions: IntArrayList get() = _positions + +open class ProgramLayout( + @PublishedApi internal val items: List, + private val layoutSize: Int? +) { constructor(attributes: List) : this(attributes, null) - constructor(vararg attributes: TVariable) : this(attributes.toFastList(), null) constructor(vararg attributes: TVariable, layoutSize: Int? = null) : this(attributes.toFastList(), layoutSize) private var _lastPos: Int = 0 - val alignments = myattr.map { + val alignments: IntArrayList = items.mapInt { val a = it.type.kind.bytesSize if (a <= 1) 1 else a } - val attributePositions = myattr.mapInt { - if (it.offset != null) { - _lastPos = it.offset - } else { - _lastPos = _lastPos.nextAlignedTo(it.type.kind.bytesSize) - } + @PublishedApi internal val _positions: IntArrayList = items.mapInt { + _lastPos = when { + it.offset != null -> it.offset + else -> _lastPos.nextAlignedTo(it.type.kind.bytesSize) + } val out = _lastPos _lastPos += it.type.bytesSize out } - val maxAlignment = alignments.maxOrNull() ?: 1 + val maxAlignment: Int = alignments.maxOrNull() ?: 1 /** Size in bytes for each vertex */ val totalSize: Int = layoutSize ?: _lastPos.nextAlignedTo(maxAlignment) - protected fun names(): String = myattr.joinToString(", ") { it.name } + protected fun names(): String = items.joinToString(", ") { it.name } override fun toString(): String = "VertexLayout[${names()}]" } + +typealias UniformLayout = ProgramLayout +typealias UniformBlock = ProgramLayout +inline val ProgramLayout.uniforms: List get() = items +inline val ProgramLayout.uniformPositions: IntArrayList get() = _positions + +class UniformBlockData(val block: UniformBlock) { + val data = Buffer(block.totalSize) + val values = (0 until block.uniformPositions.size).map { index -> + val uniform = block.uniforms[index] + val position = block.uniformPositions[index] + val size = uniform.type.bytesSize + AGUniformValue(uniform, data.sliceWithSize(position, size), null, AGTextureUnitInfo.DEFAULT) + } + val valuesByUniform = values.associateBy { it.uniform } + operator fun get(uniform: Uniform): AGUniformValue = valuesByUniform[uniform] ?: error("Can't get uniform $uniform in $this") +} + +class UniformBlockBuffer(val block: UniformBlock, val maxElements: Int) { + val buffer = Buffer(block.totalSize * maxElements) + operator fun set(index: Int, data: UniformBlockData) { + if (data.block != block) error("${data.block} != $block") + arraycopy(data.data, 0, this.buffer, index * block.totalSize, block.totalSize) + } + fun copyIndexTo(index: Int, data: UniformBlockData) { + if (data.block != block) error("${data.block} != $block") + arraycopy(this.buffer, index * block.totalSize, data.data, 0, block.totalSize) + } + + var lastIndex = 0 + private set + + fun reset() { + lastIndex = 0 + } + + fun put(data: UniformBlockData): Int { + val index = lastIndex++ + this[index] = data + return index + } +} diff --git a/korgw/src/commonTest/kotlin/com/soywiz/korgw/AGUniformsTest.kt b/korgw/src/commonTest/kotlin/com/soywiz/korgw/AGUniformsTest.kt new file mode 100644 index 0000000000..0baaf903b8 --- /dev/null +++ b/korgw/src/commonTest/kotlin/com/soywiz/korgw/AGUniformsTest.kt @@ -0,0 +1,35 @@ +package com.soywiz.korgw + +import com.soywiz.kmem.* +import com.soywiz.korag.shader.* +import com.soywiz.korma.geom.* +import kotlin.test.* + +class AGUniformsTest { + @Test + fun testUniformBlockDataAndBuffer() { + val projMatrix by Uniform(VarType.Mat4) + val viewMatrix by Uniform(VarType.Mat4) + val color1 by Uniform(VarType.UByte4) + val block = UniformBlock(projMatrix, viewMatrix, color1, layoutSize = null) + val data = UniformBlockData(block) + val buffer = UniformBlockBuffer(block, 2) + data[projMatrix].set(Matrix3D().multiply(2f)) + val index1 = buffer.put(data) + data[projMatrix].set(Matrix3D().multiply(3f)) + val index2 = buffer.put(data) + //println(buffer.buffer.f32.toFloatArray().toList()) + + assertEquals(listOf(0, 1), listOf(index1, index2)) + + buffer.copyIndexTo(index1, data) + assertEquals(Matrix3D().multiply(2f), Matrix3D().setColumns4x4(data[projMatrix].data.f32.toFloatArray(), 0)) + + buffer.copyIndexTo(index2, data) + assertEquals(Matrix3D().multiply(3f), Matrix3D().setColumns4x4(data[projMatrix].data.f32.toFloatArray(), 0)) + + //block.attributePositions + //println(block.totalSize) + } + +} diff --git a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Matrix3D.kt b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Matrix3D.kt index 44e84f9ff1..e4a571d081 100644 --- a/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Matrix3D.kt +++ b/korma/src/commonMain/kotlin/com/soywiz/korma/geom/Matrix3D.kt @@ -119,21 +119,21 @@ class Matrix3D { return this } - fun setColumns4x4(f: FloatArray, offset: Int) = setColumns( + fun setColumns4x4(f: FloatArray, offset: Int): Matrix3D = setColumns( f[offset + 0], f[offset + 1], f[offset + 2], f[offset + 3], f[offset + 4], f[offset + 5], f[offset + 6], f[offset + 7], f[offset + 8], f[offset + 9], f[offset + 10], f[offset + 11], f[offset + 12], f[offset + 13], f[offset + 14], f[offset + 15] ) - fun setRows4x4(f: FloatArray, offset: Int) = setRows( + fun setRows4x4(f: FloatArray, offset: Int): Matrix3D = setRows( f[offset + 0], f[offset + 1], f[offset + 2], f[offset + 3], f[offset + 4], f[offset + 5], f[offset + 6], f[offset + 7], f[offset + 8], f[offset + 9], f[offset + 10], f[offset + 11], f[offset + 12], f[offset + 13], f[offset + 14], f[offset + 15] ) - fun setColumns3x3(f: FloatArray, offset: Int) = setColumns( + fun setColumns3x3(f: FloatArray, offset: Int): Matrix3D = setColumns( f[offset + 0], f[offset + 1], f[offset + 2], 0f, f[offset + 3], f[offset + 4], f[offset + 5], 0f, f[offset + 6], f[offset + 7], f[offset + 8], 0f, @@ -419,8 +419,9 @@ class Matrix3D { rv30.toFloat(), rv31.toFloat(), rv32.toFloat(), rv33.toFloat(), ) - fun multiply(scale: Float, l: Matrix3D = this) = this.apply { + fun multiply(scale: Float, l: Matrix3D = this): Matrix3D { for (n in 0 until 16) this.data[n] = l.data[n] * scale + return this } fun copyFrom(that: Matrix3D): Matrix3D {