Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update FrameBuffer to handle multiple color attachments #227

Merged
merged 10 commits into from
Jan 28, 2024
29 changes: 29 additions & 0 deletions core/src/androidMain/kotlin/com/lehaine/littlekt/AndroidGL.kt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,29 @@ class AndroidGL(private val engineStats: EngineStats) : GL {
GLES20.glClearStencil(stencil)
}

override fun clearBufferiv(buffer: Int, drawBuffer: Int, value: IntBuffer) {
engineStats.calls++
value as IntBufferImpl
GLES30.glClearBufferiv(buffer, drawBuffer, value.buffer)
}

override fun clearBufferuiv(buffer: Int, drawBuffer: Int, value: IntBuffer) {
engineStats.calls++
value as IntBufferImpl
GLES30.glClearBufferuiv(buffer, drawBuffer, value.buffer)
}

override fun clearBufferfv(buffer: Int, drawBuffer: Int, value: FloatBuffer) {
engineStats.calls++
value as FloatBufferImpl
GLES30.glClearBufferfv(buffer, drawBuffer, value.buffer)
}

override fun clearBufferfi(buffer: Int, drawBuffer: Int, depth: Float, stencil: Int) {
engineStats.calls++
GLES30.glClearBufferfi(buffer, drawBuffer, depth, stencil)
}

override fun colorMask(red: Boolean, green: Boolean, blue: Boolean, alpha: Boolean) {
engineStats.calls++
GLES20.glColorMask(red, green, blue, alpha)
Expand Down Expand Up @@ -660,6 +683,12 @@ class AndroidGL(private val engineStats: EngineStats) : GL {
GLES20.glDrawElements(mode, count, type, offset)
}

override fun drawBuffers(size: Int, buffers: IntBuffer) {
engineStats.calls++
buffers as IntBufferImpl
GLES30.glDrawBuffers(size, buffers.buffer)
}

override fun pixelStorei(pname: Int, param: Int) {
engineStats.calls++
GLES20.glPixelStorei(pname, param)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import com.lehaine.littlekt.graph.SceneGraph
import com.lehaine.littlekt.graph.node.annotation.SceneGraphDslMarker
import com.lehaine.littlekt.graph.node.resource.InputEvent
import com.lehaine.littlekt.graph.node.ui.Control
import com.lehaine.littlekt.graphics.*
import com.lehaine.littlekt.graphics.Camera
import com.lehaine.littlekt.graphics.Color
import com.lehaine.littlekt.graphics.FrameBuffer
import com.lehaine.littlekt.graphics.Texture
import com.lehaine.littlekt.graphics.g2d.Batch
import com.lehaine.littlekt.graphics.g2d.shape.ShapeRenderer
import com.lehaine.littlekt.graphics.gl.ClearBufferMask
Expand Down Expand Up @@ -49,7 +52,7 @@ open class FrameBufferNode : CanvasLayer() {
/**
* The color buffer texture from the [FrameBuffer].
*/
val fboTexture: Texture? get() = fbo?.colorBufferTexture
val fboTexture: Texture? get() = fbo?.textures?.getOrNull(0)

/**
* Signal that is emitted when the [FrameBuffer] is resized and recreated.
Expand Down Expand Up @@ -98,8 +101,12 @@ open class FrameBufferNode : CanvasLayer() {
fbo = FrameBuffer(
width,
height,
minFilter = TexMinFilter.NEAREST,
magFilter = TexMagFilter.NEAREST
colorAttachments = listOf(
FrameBuffer.ColorAttachment(
minFilter = TexMinFilter.NEAREST,
magFilter = TexMagFilter.NEAREST
)
),
).also { it.prepare(scene.context) }
viewport.width = width
viewport.height = height
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.lehaine.littlekt.graphics
import com.lehaine.littlekt.Context
import com.lehaine.littlekt.Disposable
import com.lehaine.littlekt.file.createIntBuffer
import com.lehaine.littlekt.graphics.FrameBuffer.ColorAttachment
import com.lehaine.littlekt.graphics.gl.*
import com.lehaine.littlekt.math.MutableVec4i
import kotlin.contracts.ExperimentalContracts
Expand All @@ -13,23 +14,67 @@ import kotlin.contracts.contract
* Encapsulates OpenGL frame buffer objects.
* @param width the width of the framebuffer in pixels
* @param height the height of the framebuffer in pixels
* @param colorAttachments the list of [ColorAttachment] to attach to the FrameBuffer.
* @param hasDepth whether to attach a depth buffer. Defaults to false.
* @param hasStencil whether to attach a stencil buffer. Defaults to false.
* @param format the format of the color buffer
* @param hasPackedDepthStencil whether to attach a packed depth/stencil buffer. Defaults to false.
* @author Colton Daily
* @date 11/25/2021
*/
open class FrameBuffer(
val width: Int,
val height: Int,
val colorAttachments: List<ColorAttachment> = listOf(ColorAttachment()),
val hasDepth: Boolean = false,
val hasStencil: Boolean = false,
var hasPackedDepthStencil: Boolean = false,
val format: Pixmap.Format = Pixmap.Format.RGBA8888,
val minFilter: TexMinFilter = TexMinFilter.LINEAR,
val magFilter: TexMagFilter = TexMagFilter.LINEAR,
) : Preparable, Disposable {

/**
* Encapsulates OpenGL frame buffer objects.
* @param width the width of the framebuffer in pixels
* @param height the height of the framebuffer in pixels
* @param format format of the color buffer
* @param hasDepth whether to attach a depth buffer. Defaults to false.
* @param hasStencil whether to attach a stencil buffer. Defaults to false.
* @param hasPackedDepthStencil whether to attach a packed depth/stencil buffer. Defaults to false.
* @param minFilter texture min filter
* @param magFilter texture mag filter
* @param wrap format for UV texture wrap
*/
constructor(
width: Int,
height: Int,
hasDepth: Boolean = false,
hasStencil: Boolean = false,
hasPackedDepthStencil: Boolean = false,
format: Pixmap.Format = Pixmap.Format.RGBA8888,
minFilter: TexMinFilter = TexMinFilter.LINEAR,
magFilter: TexMagFilter = TexMagFilter.LINEAR,
wrap: TexWrap = TexWrap.CLAMP_TO_EDGE,
) : this(
width,
height,
listOf(ColorAttachment(format, minFilter, magFilter, wrap)),
hasDepth,
hasStencil,
hasPackedDepthStencil
)

/**
* A color attachment to be used in [FrameBuffer].
* @param format format of the color buffer
* @param minFilter texture min filter
* @param magFilter texture mag filter
* @param wrap format for UV texture wrap
*/
class ColorAttachment(
val format: Pixmap.Format = Pixmap.Format.RGBA8888,
val minFilter: TexMinFilter = TexMinFilter.LINEAR,
val magFilter: TexMagFilter = TexMagFilter.LINEAR,
val wrap: TexWrap = TexWrap.CLAMP_TO_EDGE,
)

/**
* Gets set when the frame buffer is prepared by the application
*/
Expand All @@ -45,8 +90,18 @@ open class FrameBuffer(
private var isBound = false
private var isPrepared = false

var texture: Texture? = null
val colorBufferTexture get() = texture!!
private val _textures = mutableListOf<Texture>()
val textures: List<Texture> get() = _textures

/**
* Alias for `textures.getOrNull(0)`.
*/
val texture: Texture? get() = textures.getOrNull(0)

/**
* Alias for `textures[0]`.
*/
val colorBufferTexture: Texture get() = textures[0]

override val prepared: Boolean
get() = isPrepared
Expand Down Expand Up @@ -81,15 +136,31 @@ open class FrameBuffer(
gl.renderBufferStorage(RenderBufferInternalFormat.DEPTH24_STENCIL8, width, height)
}
}
texture = Texture(GLTextureData(width, height, 0, format.glFormat, format.glFormat, format.glType)).apply {
minFilter = this@FrameBuffer.minFilter
magFilter = this@FrameBuffer.magFilter
uWrap = TexWrap.CLAMP_TO_EDGE
vWrap = TexWrap.CLAMP_TO_EDGE
}.also { it.prepare(context) } // preparing the texture will also bind it

texture?.glTexture?.let {
gl.frameBufferTexture2D(FrameBufferRenderBufferAttachment.COLOR_ATTACHMENT(), it, 0)
colorAttachments.forEachIndexed { i, colorAttachment ->
_textures += Texture(
GLTextureData(
width,
height,
0,
colorAttachment.format.glFormat,
colorAttachment.format.glFormat,
colorAttachment.format.glType
)
).apply {
minFilter = colorAttachment.minFilter
magFilter = colorAttachment.magFilter
uWrap = colorAttachment.wrap
vWrap = colorAttachment.wrap
}.also { texture ->
texture.prepare(context) // preparing the texture will also bind it
gl.frameBufferTexture2D(
FrameBufferRenderBufferAttachment.COLOR_ATTACHMENT(i),
texture.glTexture
?: throw RuntimeException("FrameBuffer failed on attempting to add color attachment($i)!"),
0
)
}
}

depthBufferHandle?.let {
Expand All @@ -104,9 +175,6 @@ open class FrameBuffer(
}

gl.bindDefaultRenderBuffer()
texture?.glTexture?.let {
gl.bindTexture(TextureTarget._2D, it)
}

var result = gl.checkFrameBufferStatus()
if (result == FrameBufferStatus.FRAMEBUFFER_UNSUPPORTED && hasDepth && hasStencil &&
Expand Down Expand Up @@ -190,7 +258,9 @@ open class FrameBuffer(
}

override fun dispose() {
texture?.dispose()
_textures.forEach {
it.dispose()
}

if (hasDepth) {
depthBufferHandle?.let {
Expand Down
15 changes: 11 additions & 4 deletions core/src/commonMain/kotlin/com/lehaine/littlekt/graphics/GL.kt
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ interface GL {
fun clear(mask: ClearBufferMask) = clear(mask.glFlag)
fun clearDepth(depth: Float)
fun clearStencil(stencil: Int)
fun clearBufferiv(buffer: Int, drawBuffer: Int, value: IntBuffer)
fun clearBufferuiv(buffer: Int, drawBuffer: Int, value: IntBuffer)
fun clearBufferfv(buffer: Int, drawBuffer: Int, value: FloatBuffer)
fun clearBufferfi(buffer: Int, drawBuffer: Int, depth: Float, stencil: Int)
fun colorMask(red: Boolean, green: Boolean, blue: Boolean, alpha: Boolean)
fun cullFace(mode: Int)
fun cullFace(mode: CullFaceMode) = cullFace(mode.glFlag)
Expand Down Expand Up @@ -232,26 +236,29 @@ interface GL {

fun uniform1fv(uniformLocation: UniformLocation, floats: FloatArray)
fun uniform1fv(uniformLocation: UniformLocation, floats: Array<Float>) =
uniform1fv(uniformLocation, floats.toFloatArray())
uniform1fv(uniformLocation, floats.toFloatArray()) // TODO optimize this so it doesn't create a new array

fun uniform2fv(uniformLocation: UniformLocation, floats: FloatArray)
fun uniform2fv(uniformLocation: UniformLocation, floats: Array<Float>) =
uniform2fv(uniformLocation, floats.toFloatArray())
uniform2fv(uniformLocation, floats.toFloatArray()) // TODO optimize this so it doesn't create a new array

fun uniform3fv(uniformLocation: UniformLocation, floats: FloatArray)
fun uniform3fv(uniformLocation: UniformLocation, floats: Array<Float>) =
uniform3fv(uniformLocation, floats.toFloatArray())
uniform3fv(uniformLocation, floats.toFloatArray()) // TODO optimize this so it doesn't create a new array

fun uniform4fv(uniformLocation: UniformLocation, floats: FloatArray)
fun uniform4fv(uniformLocation: UniformLocation, floats: Array<Float>) =
uniform4fv(uniformLocation, floats.toFloatArray())
uniform4fv(uniformLocation, floats.toFloatArray()) // TODO optimize this so it doesn't create a new array

fun drawArrays(mode: Int, offset: Int, count: Int)
fun drawArrays(mode: DrawMode, offset: Int, count: Int) = drawArrays(mode.glFlag, offset, count)
fun drawElements(mode: Int, count: Int, type: Int, offset: Int)
fun drawElements(mode: DrawMode, count: Int, type: IndexType, offset: Int) =
drawElements(mode.glFlag, count, type.glFlag, offset)

fun drawBuffers(size: Int, buffers: IntBuffer)
fun drawBuffers(buffers: IntBuffer) = drawBuffers(buffers.limit, buffers)

fun pixelStorei(pname: Int, param: Int)
fun pixelStorei(pname: PixelStoreParameter, param: Int) = pixelStorei(pname.glFlag, param)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class VectorFont(private val font: TtfFont) : Preparable {
context.graphics.width,
context.graphics.height,
).apply { prepare(context) }
fboSlice = fbo.colorBufferTexture.slice()
fboSlice = fbo.textures[0].slice()
isPrepared = true
}

Expand All @@ -76,7 +76,7 @@ class VectorFont(private val font: TtfFont) : Preparable {
fbo = FrameBuffer(
width, height
).apply { prepare(context) }
fboSlice = fbo.colorBufferTexture.slice()
fboSlice = fbo.textures[0].slice()
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ abstract class FragmentShaderModel : GlslGenerator(), FragmentShader {

var gl_FragCoord by BuiltinVarDelegate()
var gl_FragColor by BuiltinVarDelegate()
val gl_FragData by BuiltInVec4ArrayDelegate()

val gl_FrontFacing = "gl_FrontFacing".bool

Expand Down Expand Up @@ -67,9 +68,7 @@ abstract class FragmentShaderModel : GlslGenerator(), FragmentShader {

other as FragmentShaderModel

if (source != other.source) return false

return true
return source == other.source
}

override fun hashCode(): Int {
Expand Down
Loading
Loading