diff --git a/libopenage/renderer/opengl/context.cpp b/libopenage/renderer/opengl/context.cpp index 91e2fb431b..e02992d25e 100644 --- a/libopenage/renderer/opengl/context.cpp +++ b/libopenage/renderer/opengl/context.cpp @@ -156,6 +156,10 @@ std::shared_ptr GlContext::get_raw_context() const { return this->gl_context; } +GLuint GlContext::get_default_framebuffer_id() { + return this->gl_context->defaultFramebufferObject(); +} + gl_context_spec GlContext::get_specs() const { return this->specs; } diff --git a/libopenage/renderer/opengl/context.h b/libopenage/renderer/opengl/context.h index 68e3e39c1f..ba5459ed5f 100644 --- a/libopenage/renderer/opengl/context.h +++ b/libopenage/renderer/opengl/context.h @@ -66,6 +66,17 @@ class GlContext { */ std::shared_ptr get_raw_context() const; + /** + * Get the ID of the default framebuffer used for displaying to + * the window. + * + * This value may change on every frame, so it should be called every + * time the default framebuffer is bound. + * + * @return ID of the default (display) framebuffer. + */ + unsigned int get_default_framebuffer_id(); + /** * Get the capabilities of this context. */ diff --git a/libopenage/renderer/opengl/framebuffer.cpp b/libopenage/renderer/opengl/framebuffer.cpp index e9862ff7ce..477c628f90 100644 --- a/libopenage/renderer/opengl/framebuffer.cpp +++ b/libopenage/renderer/opengl/framebuffer.cpp @@ -2,17 +2,25 @@ #include "framebuffer.h" +#include "renderer/opengl/context.h" #include "renderer/opengl/texture.h" namespace openage::renderer::opengl { +GlFramebuffer::GlFramebuffer(const std::shared_ptr &context) : + GlSimpleObject(context, + [](GLuint /*handle*/) {}), + type{gl_framebuffer_t::display} { +} + // TODO the validity of this object is contingent // on its texture existing. use shared_ptr? GlFramebuffer::GlFramebuffer(const std::shared_ptr &context, std::vector> const &textures) : GlSimpleObject(context, - [](GLuint handle) { glDeleteFramebuffers(1, &handle); }) { + [](GLuint handle) { glDeleteFramebuffers(1, &handle); }), + type{gl_framebuffer_t::textures} { GLuint handle; glGenFramebuffers(1, &handle); this->handle = handle; @@ -21,6 +29,10 @@ GlFramebuffer::GlFramebuffer(const std::shared_ptr &context, std::vector drawBuffers; + if (textures.empty()) { + throw Error{ERR << "At least 1 texture must be assigned to texture framebuffer."}; + } + size_t colorTextureCount = 0; for (auto const &texture : textures) { // TODO figure out attachment points from pixel formats @@ -41,12 +53,26 @@ GlFramebuffer::GlFramebuffer(const std::shared_ptr &context, } } +gl_framebuffer_t GlFramebuffer::get_type() const { + return this->type; +} + void GlFramebuffer::bind_read() const { - glBindFramebuffer(GL_READ_FRAMEBUFFER, *this->handle); + if (this->type == gl_framebuffer_t::textures) { + glBindFramebuffer(GL_READ_FRAMEBUFFER, *this->handle); + } + else { + glBindFramebuffer(GL_READ_FRAMEBUFFER, this->context->get_default_framebuffer_id()); + } } void GlFramebuffer::bind_write() const { - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *this->handle); + if (this->type == gl_framebuffer_t::textures) { + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *this->handle); + } + else { + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, this->context->get_default_framebuffer_id()); + } } } // namespace openage::renderer::opengl diff --git a/libopenage/renderer/opengl/framebuffer.h b/libopenage/renderer/opengl/framebuffer.h index ccd544f57e..cd37ccb76a 100644 --- a/libopenage/renderer/opengl/framebuffer.h +++ b/libopenage/renderer/opengl/framebuffer.h @@ -7,30 +7,75 @@ #include "renderer/opengl/simple_object.h" -namespace openage { -namespace renderer { -namespace opengl { +namespace openage::renderer::opengl { class GlTexture2d; -/// Represents an OpenGL Framebuffer Object. -/// It is a collection of bitmap targets that can be drawn into -/// and read from. +/** + * The type of OpenGL framebuffer. + */ +enum class gl_framebuffer_t { + /** + * The actual window. This is visible to the user after swapping front and back buffers. + */ + display, + /** + * A bunch of textures. These can be color texture, depth textures, etc. + */ + textures, +}; + +/** + * Represents an OpenGL Framebuffer Object. + * It is a collection of bitmap targets that can be drawn into + * and read from. + */ class GlFramebuffer final : public GlSimpleObject { public: - /// Construct a framebuffer pointing at the given textures. - /// Texture are attached to points specific to their pixel format, - /// e.g. a depth texture will be set as the depth target. + /** + * Construct a framebuffer pointing at the default framebuffer - the window. + * + * Drawing into this framebuffer draws onto the screen. + * + * @param context OpenGL context used for drawing. + */ + GlFramebuffer(const std::shared_ptr &context); + + /** + * Construct a framebuffer pointing at the given textures. + * + * Texture are attached to points specific to their pixel format, + * e.g. a depth texture will be set as the depth target. + * + * @param context OpenGL context used for drawing. + * @param textures Textures targeted by the framebuffer. They are automatically + * attached to the correct attachement points depending on their type. + */ GlFramebuffer(const std::shared_ptr &context, std::vector> const &textures); - /// Bind this framebuffer to GL_READ_FRAMEBUFFER. + /** + * Get the type of this framebuffer. + * + * @return Framebuffer type. + */ + gl_framebuffer_t get_type() const; + + /** + * Bind this framebuffer to \p GL_READ_FRAMEBUFFER. + */ void bind_read() const; - /// Bind this framebuffer to GL_DRAW_FRAMEBUFFER. + /** + * Bind this framebuffer to \p GL_DRAW_FRAMEBUFFER. + */ void bind_write() const; + +private: + /** + * Type of this framebuffer. + */ + gl_framebuffer_t type; }; -} // namespace opengl -} // namespace renderer -} // namespace openage +} // namespace openage::renderer::opengl diff --git a/libopenage/renderer/opengl/render_target.cpp b/libopenage/renderer/opengl/render_target.cpp index b2f844d83b..c0da3a22a8 100644 --- a/libopenage/renderer/opengl/render_target.cpp +++ b/libopenage/renderer/opengl/render_target.cpp @@ -2,17 +2,20 @@ #include "render_target.h" +#include "error/error.h" + #include "renderer/opengl/texture.h" namespace openage::renderer::opengl { -GlRenderTarget::GlRenderTarget(size_t width, size_t height) : - type(gl_render_target_t::display), - size(width, height) {} +GlRenderTarget::GlRenderTarget(const std::shared_ptr &context, size_t width, size_t height) : + type(gl_render_target_t::framebuffer), + size(width, height), + framebuffer(context) {} GlRenderTarget::GlRenderTarget(const std::shared_ptr &context, const std::vector> &textures) : - type(gl_render_target_t::textures), + type(gl_render_target_t::framebuffer), framebuffer({context, textures}), textures(textures) { // TODO: Check if the textures are all the same size @@ -21,7 +24,7 @@ GlRenderTarget::GlRenderTarget(const std::shared_ptr &context, std::vector> GlRenderTarget::get_texture_targets() { std::vector> textures{}; - if (this->type == gl_render_target_t::display) { + if (this->framebuffer->get_type() == gl_framebuffer_t::display) { return textures; } //else upcast pointers @@ -33,8 +36,9 @@ std::vector> GlRenderTarget::get_texture_targets() { } void GlRenderTarget::resize(size_t width, size_t height) { - if (this->type != gl_render_target_t::display) { - throw Error{ERR << "Texture render target should not be resized. Create a new one instead."}; + if (this->framebuffer->get_type() == gl_framebuffer_t::textures) { + throw Error{ERR << "Render target with textured framebuffer should not be resized. " + << "Create a new one instead."}; } this->size = std::make_pair(width, height); @@ -46,23 +50,11 @@ void GlRenderTarget::bind_write() const { // different sizes glViewport(0, 0, size.first, size.second); - if (this->type == gl_render_target_t::textures) { - this->framebuffer->bind_write(); - } - else { - // 0 is the default, window framebuffer - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - } + this->framebuffer->bind_write(); } void GlRenderTarget::bind_read() const { - if (this->type == gl_render_target_t::textures) { - this->framebuffer->bind_read(); - } - else { - // 0 is the default, window framebuffer - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - } + this->framebuffer->bind_read(); } } // namespace openage::renderer::opengl diff --git a/libopenage/renderer/opengl/render_target.h b/libopenage/renderer/opengl/render_target.h index 546ac1e8ca..5246b03cb7 100644 --- a/libopenage/renderer/opengl/render_target.h +++ b/libopenage/renderer/opengl/render_target.h @@ -17,50 +17,92 @@ namespace opengl { class GlTexture2d; -/// The type of OpenGL render target +/** + * The type of OpenGL render target. + */ enum class gl_render_target_t { - /// The actual window. This is visible to the user after swapping front and back buffers - display, - /// A bunch of textures - textures, + /** + * Render into a framebuffer. + */ + framebuffer, // TODO renderbuffers mixed with textures }; -/// Represents an OpenGL target that can be drawn into. -/// It can be either a framebuffer or the display (the window). +/** + * Represents an OpenGL target that can be drawn into. + * It can be either a framebuffer with texture attachements or the display (the window). + */ class GlRenderTarget final : public RenderTarget { public: - /// Construct a render target pointed at the default framebuffer - the window. - GlRenderTarget(size_t width, size_t height); - - /// Construct a render target pointing at the given textures. - /// Texture are attached to points specific to their pixel format, - /// e.g. a depth texture will be set as the depth target. + /** + * Construct a render target pointed at the default framebuffer - the window. + * + * @param context OpenGL context used for drawing. + * @param width Current width of the window. + * @param height Current height of the window. + */ + GlRenderTarget(const std::shared_ptr &context, + size_t width, + size_t height); + + /** + * Construct a render target pointing at the given textures. + * Texture are attached to points specific to their pixel format, + * e.g. a depth texture will be set as the depth target. + * + * @param context OpenGL context used for drawing. + * @param textures Texture attachements. + */ GlRenderTarget(const std::shared_ptr &context, std::vector> const &textures); - // Get the targeted textures + /** + * Get the targeted textures. + * + * @return Textures drawn into by the render target. + */ std::vector> get_texture_targets() override; - // Resize the render target for scaling viewport correctly. + /** + * Resize the render target to the specified dimensions. + * + * This is used to scale the viewport to the correct size when + * binding the render target with write access. + * + * @param width New width. + * @param height New height. + */ void resize(size_t width, size_t height); - /// Bind this render target to be drawn into. + /** + * Bind this render target to be drawn into. + */ void bind_write() const; - /// Bind this render target to be read from. + /** + * Bind this render target to be read from. + */ void bind_read() const; private: + /** + * Type of this render target. + */ gl_render_target_t type; - // Size of the window or the texture target + /** + * Size of the window or the texture targets. + */ std::pair size; - /// For textures target type, the framebuffer. + /** + * For framebuffer target type, the framebuffer. + */ std::optional framebuffer; - // target textures if the render target is an fbo + /** + * Target textures if the render target is a textured fbo. + */ std::optional>> textures; }; diff --git a/libopenage/renderer/opengl/renderer.cpp b/libopenage/renderer/opengl/renderer.cpp index f0e513f14c..91cc5b35ee 100644 --- a/libopenage/renderer/opengl/renderer.cpp +++ b/libopenage/renderer/opengl/renderer.cpp @@ -24,7 +24,9 @@ namespace openage::renderer::opengl { GlRenderer::GlRenderer(const std::shared_ptr &ctx, const util::Vector2s &viewport_size) : gl_context{ctx}, - display{std::make_shared(viewport_size[0], viewport_size[1])} { + display{std::make_shared(ctx, + viewport_size[0], + viewport_size[1])} { // global GL alpha blending settings glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);