// // fbo.h // J // // Created by Joshua Moerman on 7/01/11. // Copyright 2011 Vadovas. All rights reserved. // /* Like the shader object, all work is done in the constructor and destructor. So copying a fbo object is impossible, use smart pointers instead. The standard constructor only takes a width and height. Texture settings and the presence of a depth buffer are preset and cannot be changed (since one probably wants those things, and there is not a lot of flexibility in ES2). The other constructor (wich is defined in fbo.mm) is to make EAGLView more compact, it makes a fbo in a given context and with a given layer (no texture will be generated, so you cannot use this fbo for texture lookup). Just like the shader, this class has begin() and end() functions. */ #ifndef FBO_H #define FBO_H #include #include #include #include "to_string.h" #include "basic.h" #include "texture.h" @class EAGLContext; @class CAEAGLLayer; // TODO: more error checking in debug build. // TODO: make texture class? for easier switching between linear/nearest interpolation for example. (also affects shader::set_texture). // NOTE: stencil attachment is not supported namespace J { class fbo { public: typedef std::map RenderbuffersMap; int width, height; GLuint fbo_number; RenderbuffersMap renderbuffers; GLuint texture_id; public: // standard ctor, makes use of textures template fbo(int width, int height, Texture const & texture = no_texture()) : width(width), height(height), fbo_number(0), renderbuffers(), texture_id(0) { glGenFramebuffers(1, &fbo_number); bind(); // generate texture glGenTextures(1, &texture_id); glBindTexture(GL_TEXTURE_2D, texture_id); bool should_clear = !make_tex(texture); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_id, 0); // attach depth create_attach_renderbuffer(GL_DEPTH_COMPONENT16, GL_DEPTH_ATTACHMENT); check_error(); check_status(); if(should_clear){ glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } unbind(); } // ctor from EAGLContext, not using textures, so you cannot use it as lookup, only as renderer. // this one is defined in fbo.mm, because it uses Quartz and objC / iOS stuff. fbo(EAGLContext* context, CAEAGLLayer* layer); ~fbo() { end(); glDeleteFramebuffers(1, &fbo_number); for(RenderbuffersMap::const_iterator i = renderbuffers.begin(); i != renderbuffers.end(); ++i){ RenderbuffersMap::value_type const & it = *i; glDeleteRenderbuffers(1, &it.second); } glDeleteTextures(1, &texture_id); // NOTE: glDeleteTextures silently ignores 0's and names that do not correspond to existing textures. } void begin(){ bind(); glViewport(0, 0, width, height); } void end(){ unbind(); // NOTE: we don't set a viewport, because it will be always set (the 'main' fbo is also an J::fbo) } private: template bool make_tex(Texture const & texture){ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, Texture::gl_format, Texture::gl_type, texture.data()); return true; } bool make_tex(no_texture const &){ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); return false; } void bind(){ glBindFramebuffer(GL_FRAMEBUFFER, fbo_number); check_error(); } void unbind(){ glBindFramebuffer(GL_FRAMEBUFFER, 0); } void create_attach_renderbuffer(GLenum format, GLenum attachment_point) { GLuint buffer; glGenRenderbuffers(1, &buffer); glBindRenderbuffer(GL_RENDERBUFFER, buffer); glRenderbufferStorage(GL_RENDERBUFFER, format, width, height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment_point, GL_RENDERBUFFER, buffer); renderbuffers[format] = buffer; } void check_status() { #if defined(DEBUG) GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); switch(status) { case GL_FRAMEBUFFER_COMPLETE: std::cout << "FRAMEBUFFER_COMPLETE - OK" << std::endl; return; case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: std::cout << "FRAMEBUFFER_INCOMPLETE_ATTACHMENT" << std::endl; break; case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: std::cout << "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT" << std::endl; break; case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: std::cout << "FRAMEBUFFER_INCOMPLETE_DIMENSIONS" << std::endl; break; case GL_FRAMEBUFFER_UNSUPPORTED: std::cout << "FRAMEBUFFER_UNSUPPORTED" << std::endl; break; default: std::cout << "UNKNOWN FRAMEBUFFER ERROR" << std::endl; break; } throw std::runtime_error("I will not continu.."); #endif } }; } // namespace J #endif // FBO_H