From a09a2326dabff5c1eec447876dce881a4f628509 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Mon, 22 Aug 2016 18:40:54 +0900 Subject: [PATCH 1/2] Textures can be created blank and attached to a FBO. --- modules/graphics/include/moon/texture.hxx | 2 ++ modules/graphics/src/texture.cxx | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/modules/graphics/include/moon/texture.hxx b/modules/graphics/include/moon/texture.hxx index 6af7d97..772ecce 100644 --- a/modules/graphics/include/moon/texture.hxx +++ b/modules/graphics/include/moon/texture.hxx @@ -12,8 +12,10 @@ namespace Moon { class Texture { public: Texture(std::string filename); + Texture(int width, int height); ~Texture(); void Bind(); + void Attach(); GLint GetWidth(); GLint GetHeight(); GLuint GetID(); diff --git a/modules/graphics/src/texture.cxx b/modules/graphics/src/texture.cxx index b5e40c0..cb07cc7 100644 --- a/modules/graphics/src/texture.cxx +++ b/modules/graphics/src/texture.cxx @@ -22,6 +22,21 @@ namespace Moon { glBindTexture(GL_TEXTURE_2D, 0); }; + Texture::Texture(int width, int height) + { + float border_color[4] = { 0.0, 0.0, 0.0, 0.0 }; + // Generate empty (RGB) texture + glGenTextures(1, &m_gl_texture_id); + glBindTexture(GL_TEXTURE_2D, m_gl_texture_id); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color); + glBindTexture(GL_TEXTURE_2D, 0); + }; + Texture::~Texture() { //Delete texture if (m_gl_texture_id != 0) { @@ -44,4 +59,9 @@ namespace Moon { void Texture::Bind() { glBindTexture(GL_TEXTURE_2D, m_gl_texture_id); }; + + void Texture::Attach() { + // Attach it to currently bound framebuffer object + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_gl_texture_id, 0); + }; } From 63e04ef11d01dd0c6e9042de09eed2124e76e6ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Mon, 22 Aug 2016 19:21:30 +0900 Subject: [PATCH 2/2] Initial draft for a Framebuffer object with rendering. --- modules/engine/mrblib/engine.rb | 7 +-- modules/graphics/mrblib/framebuffer.rb | 74 ++++++++++++++++++++++++++ modules/graphics/mrblib/screen.rb | 17 ++++++ 3 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 modules/graphics/mrblib/framebuffer.rb diff --git a/modules/engine/mrblib/engine.rb b/modules/engine/mrblib/engine.rb index 8356070..cac06bc 100644 --- a/modules/engine/mrblib/engine.rb +++ b/modules/engine/mrblib/engine.rb @@ -117,11 +117,12 @@ def shutdown def main @logger.info "Audio Module: #{Audio::NAME}" @logger.debug 'Starting main loop' - clear_bits = GL2::GL_COLOR_BUFFER_BIT | GL2::GL_DEPTH_BUFFER_BIT until @screen.should_close? - GL2.glClear clear_bits Audio.update - @step.call self, @fps.restart + @screen.render do + @screen.clear + @step.call self, @fps.restart + end @screen.title = sprintf "FPS: %d", @fps.fps @screen.swap GLFW.poll_events diff --git a/modules/graphics/mrblib/framebuffer.rb b/modules/graphics/mrblib/framebuffer.rb new file mode 100644 index 0000000..8b0575c --- /dev/null +++ b/modules/graphics/mrblib/framebuffer.rb @@ -0,0 +1,74 @@ +module Moon + class Framebuffer + + def initialize + @texture = Texture.new(600, 800) + @vbo = VertexBuffer.new(VertexBuffer::STATIC_DRAW) + @shader = Shader.load('todo', 'todo') + + # TODO: generate the 0->1 vertices for a quad that covers entire screen + + # TODO: handle window resizes, texture needs to be resized + + # Depth buffer RBO + rbo_depth = GL2::glGenRenderbuffers(1).first + GL2::glBindRenderbuffer(GL2::GL_RENDERBUFFER, rbo_depth) + GL2::glRenderbufferStorage(GL2::GL_RENDERBUFFER, GL2::GL_DEPTH_COMPONENT16, screen_width, screen_height) + GL2::glBindRenderbuffer(GL2::GL_RENDERBUFFER, 0) + + # Framebuffer to link everything together + @fbo = GL2::glGenFramebuffers(1).first + GL2::glBindFramebuffer(GL2::GL_FRAMEBUFFER, @fbo) + + # attach the texture to FBO color attachment point + GL2::glFramebufferTexture2D( + GL2::GL_FRAMEBUFFER, + GL2::GL_COLOR_ATTACHMENT0, + GL2::GL_TEXTURE_2D, + @texture.id, + 0 + ) + + # attach the renderbuffer to depth attachment point + GL2::glFramebufferRenderbuffer( + GL2::GL_FRAMEBUFFER, + GL2::GL_DEPTH_ATTACHMENT, + GL2::GL_RENDERBUFFER, + rbo_depth + ) + + if ((status = GL2::glCheckFramebufferStatus(GL2::GL_FRAMEBUFFER)) != GL2::GL_FRAMEBUFFER_COMPLETE) + fprintf(stderr, "glCheckFramebufferStatus: error %p", status) + return 0 + end + glBindFramebuffer(GL_FRAMEBUFFER, 0) + end + + def bind + # set rendering destination to FBO + GL2::glBindFramebuffer(GL2::GL_FRAMEBUFFER, @fbo) + + # clear buffers + clear_bits = GL2::GL_COLOR_BUFFER_BIT | GL2::GL_DEPTH_BUFFER_BIT + GL2.glClear clear_bits + + # draw a scene to a texture directly + yield + + # unbind FBO + GL2::glBindFramebuffer(GL2::GL_FRAMEBUFFER, 0) + end + + def render + @shader.use + @shader.set_uniform 'tex0', Renderer.instance.bind_texture(@texture) + glDisable(GL_DEPTH_TEST) + @vbo.render OpenGL::TRIANGLE_STRIP + end + + def terminate + # TODO: delete FBO & RBO + end + + end +end diff --git a/modules/graphics/mrblib/screen.rb b/modules/graphics/mrblib/screen.rb index d69d205..116fe7f 100644 --- a/modules/graphics/mrblib/screen.rb +++ b/modules/graphics/mrblib/screen.rb @@ -120,6 +120,7 @@ def shutdown private def initialize_clear_color @clear_color = Vector4.new 0, 0, 0, 0 + @clear_bits = GL2::GL_COLOR_BUFFER_BIT | GL2::GL_DEPTH_BUFFER_BIT self.clear_color = @clear_color end @@ -129,6 +130,22 @@ def shutdown private def initialize_renderer Moon::Renderer.instance = Moon::Renderer.new + @framebuffer = Moon::Framebuffer.new + end + + # magically wraps the render calls in a two pass render (first render to + # framebuffer, then render the FBO to screen with a shader). Allows us to do + # post-processing effects (screen toning, warping, etc). + def render(&block) + # first pass (clear is called inside main) + @framebuffer.bind(&block) + # second pass + clear + @framebuffer.render # render the fbo + end + + def clear + GL2.glClear @clear_bits end # @param [Vector4] color