From 67f009c15752ebb9ea894dd640841f43c05bfc9a Mon Sep 17 00:00:00 2001 From: Alberto Torres Date: Tue, 10 Sep 2024 00:59:16 +0200 Subject: [PATCH] Framebuffer: allow usage of texture arrays and changing type of depth texture. --- src/graphics/framebuffer.nim | 66 ++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 25 deletions(-) diff --git a/src/graphics/framebuffer.nim b/src/graphics/framebuffer.nim index e564e13..f6541be 100644 --- a/src/graphics/framebuffer.nim +++ b/src/graphics/framebuffer.nim @@ -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)