#include "framebuffer.h" #include "renderbuffer.h" #include "texture.h" #include #include static void framebuffer_attach_colour( FrameBuffer* framebuffer, const FrameBufferAttachment* attachment) { assert(framebuffer); assert(attachment); switch (attachment->type) { case FrameBufferNoAttachment: break; case FrameBufferTexture: glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, attachment->texture.texture->id, attachment->texture.mip_level); break; case FrameBufferCubemapTexture: glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, to_GL_cubemap_face(attachment->cubemap.face), attachment->cubemap.texture->id, attachment->cubemap.mip_level); break; case FrameBufferRenderBuffer: glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, attachment->renderbuffer->id); break; } ASSERT_GL; } static void framebuffer_attach_depth( FrameBuffer* framebuffer, const FrameBufferAttachment* attachment) { assert(framebuffer); assert(attachment); switch (attachment->type) { case FrameBufferNoAttachment: break; case FrameBufferTexture: glFramebufferTexture2D( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_DEPTH_COMPONENT, attachment->texture.texture->id, attachment->texture.mip_level); break; // TODO: Could distinguish between colour and depth attachment types to make // this a compile-time error. case FrameBufferCubemapTexture: log_error("Cannot use a cubemap texture as a depth framebuffer attachment"); break; case FrameBufferRenderBuffer: glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, attachment->renderbuffer->id); break; } ASSERT_GL; } bool gfx_init_framebuffer( FrameBuffer* framebuffer, const FrameBufferDesc* desc) { assert(framebuffer); assert(desc); glGenFramebuffers(1, &framebuffer->id); if (!framebuffer->id) { log_error("glGenFramebuffers() failed"); return false; } // Allow incomplete framebuffers for flexibility. // Attach buffers and check the framebuffer status only if buffers are given // up front. if (desc->colour.type != FrameBufferNoAttachment || desc->depth.type != FrameBufferNoAttachment) { // TODO: Could use the "named" API to avoid having to bind the framebuffer. glBindFramebuffer(GL_FRAMEBUFFER, framebuffer->id); framebuffer_attach_colour(framebuffer, &desc->colour); framebuffer_attach_depth(framebuffer, &desc->depth); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { log_error("glCheckFramebufferStatus() failed"); gfx_del_framebuffer(framebuffer); return false; } glBindFramebuffer(GL_FRAMEBUFFER, 0); } ASSERT_GL; return true; } bool gfx_framebuffer_attach_colour( FrameBuffer* framebuffer, const FrameBufferAttachment* attachment) { assert(framebuffer); assert(attachment); // TODO: Could use the "named" API to avoid having to bind the framebuffer. glBindFramebuffer(GL_FRAMEBUFFER, framebuffer->id); framebuffer_attach_colour(framebuffer, attachment); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { log_error("glCheckFramebufferStatus() failed"); return false; } return true; } bool gfx_framebuffer_attach_depth( FrameBuffer* framebuffer, const FrameBufferAttachment* attachment) { assert(framebuffer); assert(attachment); // TODO: Could use the "named" API to avoid having to bind the framebuffer. glBindFramebuffer(GL_FRAMEBUFFER, framebuffer->id); framebuffer_attach_depth(framebuffer, attachment); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { log_error("glCheckFramebufferStatus() failed"); return false; } return true; } void gfx_del_framebuffer(FrameBuffer* framebuffer) { assert(framebuffer); if (framebuffer->id) { glDeleteFramebuffers(1, &framebuffer->id); framebuffer->id = 0; } } void gfx_activate_framebuffer(const FrameBuffer* framebuffer) { assert(framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer->id); } void gfx_deactivate_framebuffer(const FrameBuffer* framebuffer) { assert(framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, 0); } void gfx_framebuffer_set_viewport( FrameBuffer* framebuffer, int x, int y, int width, int height) { assert(framebuffer); glViewport(x, y, width, height); }