Framebuffer: allow usage of texture arrays and changing type of depth texture.

This commit is contained in:
Alberto Torres 2024-09-10 00:59:16 +02:00
parent 17d6ccc32d
commit 67f009c157

View file

@ -44,11 +44,15 @@ proc newFramebuffer*(engine: MyouEngine,
depth_only = false,
filter: TextureFilter = Linear,
tex_type: TextureType = Tex2D,
depth_filter: TextureFilter = Linear,
depth_tex_type: TextureType = Tex2D,
layer_count = 1,
texture: Texture = nil,
): Framebuffer
proc set_attachments(self: Framebuffer; layer, mipmap_level: int)
proc enable*(self: Framebuffer, rect = none((int32,int32,int32,int32)),
layer = -1, mipmap_level = 0, mark_textures = true): Framebuffer {.discardable.}
proc clear*(self: Framebuffer, color = vec4(0,0,0,0), clear_color = true, clear_depth = true) {.inline.}
proc clear*(self: Framebuffer, color = vec4(0,0,0,0), clear_color = true, clear_depth = true, layer = -1) {.inline.}
proc disable*(self: Framebuffer)
proc draw*(dest: Framebuffer, shader_mat: Material, inputs: seq[Texture],
rect = none((int32,int32,int32,int32)), layer = -1, mipmap_level = 0)
@ -79,8 +83,17 @@ proc newFramebuffer*(engine: MyouEngine,
depth_only = false,
filter: TextureFilter = Linear,
tex_type: TextureType = Tex2D,
depth_filter: TextureFilter = Linear,
depth_tex_type: TextureType = Tex2D,
layer_count = 1,
texture: Texture = nil,
): Framebuffer =
assert Tex3D notin [tex_type, depth_tex_type],
"Tex3D framebuffer not supported"
assert TexExternal notin [tex_type, depth_tex_type],
"TexExternal framebuffer not supported"
let self = new Framebuffer
# TODO: detect support for float textures and framebuffers in renderer
if width == 0 or height == 0:
@ -97,7 +110,8 @@ proc newFramebuffer*(engine: MyouEngine,
if self.texture != nil:
# TODO: rely on destructor instead
self.texture.destroy()
self.texture = engine.newTexture("fb_tex", width, height, 1, format, tex_type=tex_type, filter=filter)
self.texture = engine.newTexture("fb_tex", width, height,
layer_count, format, tex_type=tex_type, filter=filter)
# TODO: set as loaded only after having rendered something?
self.texture.loaded = true
self.texture.setExtrapolation Clamp
@ -113,24 +127,16 @@ proc newFramebuffer*(engine: MyouEngine,
self.depth_texture.destroy()
self.depth_texture = nil
if depth_type == DepthTexture:
# TODO: configure depth tex type?
self.depth_texture = engine.newTexture("fb_depth", width, height, 1, depth_format, filter=Linear)
self.depth_texture = engine.newTexture("fb_depth", width, height,
layer_count, depth_format, tex_type=depth_tex_type,
filter=depth_filter)
self.depth_texture.loaded = true
var fb, rb: GLuint
glGenFramebuffers(1, fb.addr)
self.framebuffer = fb
glBindFramebuffer(GL_FRAMEBUFFER, fb)
let target = case tex_type:
of Tex2D: GL_TEXTURE_2D
of TexCube: GL_TEXTURE_CUBE_MAP_POSITIVE_X
of Tex2DArray: GL_TEXTURE_2D_ARRAY
of Tex3D: raise ValueError.newException "Tex3D framebuffer not supported"
of TexExternal: raise ValueError.newException "TexExternal framebuffer not supported"
if self.texture != nil:
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, self.texture.storage.tex, 0)
if depth_type == DepthTexture:
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, self.depth_texture.storage.tex, 0)
elif depth_type == DepthRenderBuffer:
self.set_attachments(0, 0)
if depth_type == DepthRenderBuffer:
glGenRenderbuffers(1, rb.addr)
self.render_buffer = rb
glBindRenderbuffer(GL_RENDERBUFFER, rb)
@ -150,6 +156,23 @@ proc newFramebuffer*(engine: MyouEngine,
engine.all_framebuffers.add(self)
return self
proc set_attachments(self: Framebuffer; layer, mipmap_level: int) =
let attachments = [GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT]
for i,tex in [self.texture, self.depth_texture]:
if tex != nil:
if tex.tex_type == Tex2DArray:
assert layer >= 0, "Texture array layer must be specified"
glFramebufferTextureLayer(GL_FRAMEBUFFER, attachments[i],
tex.storage.tex, mipmap_level.GLint, layer.GLint)
elif tex.tex_type == TexCube:
assert layer >= 0, "Texture cube side must be specified"
glFramebufferTexture2D(GL_FRAMEBUFFER, attachments[i],
(GL_TEXTURE_CUBE_MAP_POSITIVE_X.int + layer).GLenum,
tex.storage.tex, mipmap_level.GLint)
elif self.current_mipmap_level != mipmap_level:
glFramebufferTexture2D(GL_FRAMEBUFFER, attachments[i],
tex.storage.target, tex.storage.tex, mipmap_level.GLint)
proc enable*(self: Framebuffer, rect = none((int32,int32,int32,int32)),
layer = -1, mipmap_level = 0, mark_textures = true): Framebuffer {.discardable.} =
self.has_mipmap = false
@ -174,14 +197,7 @@ proc enable*(self: Framebuffer, rect = none((int32,int32,int32,int32)),
when not defined(opengl_es):
if self.use_sRGB:
glEnable(GL_FRAMEBUFFER_SRGB)
if self.texture != nil:
if layer != -1:
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
(GL_TEXTURE_CUBE_MAP_POSITIVE_X.int + layer).GLenum,
self.texture.storage.tex, mipmap_level.GLint)
elif self.current_mipmap_level != mipmap_level:
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
self.texture.storage.target, self.texture.storage.tex, mipmap_level.GLint)
self.set_attachments(layer, mipmap_level)
self.current_mipmap_level = mipmap_level
active_layer = layer
glViewport(left, bottom, width, height)
@ -199,8 +215,8 @@ proc enable*(self: Framebuffer, rect = none((int32,int32,int32,int32)),
# filters_should_blend = self.filters_should_blend
return self
proc clear*(self: Framebuffer, color = vec4(0,0,0,0), clear_color = true, clear_depth = true) {.inline.} =
self.enable()
proc clear*(self: Framebuffer, color = vec4(0,0,0,0), clear_color = true, clear_depth = true, layer = -1) {.inline.} =
self.enable(layer=layer)
var bits: uint32
if clear_color:
glClearColor(color.r, color.g, color.b, color.a)