www.pudn.com > simple_framebuffer_object.zip > simple_framebuffer_object.cpp


/* 
    Simple framebuffer object (FBO) example 
 
    This example demonstrates how to use the framebuffer object extension to 
    perform simple rendering to a texture in OpenGL. 
 
    http://www.nvidia.com/dev_content/nvopenglspecs/GL_EXT_framebuffer_object.txt 
*/ 
 
#if defined(WIN32) 
#  include  
#endif 
 
#define GLH_EXT_SINGLE_FILE 
#include  
#include  
 
#include  
 
using namespace glh; 
 
bool b[256]; 
glut_simple_mouse_interactor object; 
 
GLuint fb;  // color render target 
GLuint depth_rb; // depth render target 
GLuint stencil_rb; // depth render target 
GLuint tex; // texture 
 
// texture dimensions 
int texWidth  = 256; 
int texHeight = 256; 
GLenum texInternalFormat = GL_RGBA8; 
GLenum texTarget = GL_TEXTURE_2D; 
GLenum filterMode = (texTarget == GL_TEXTURE_RECTANGLE_NV) ? GL_NEAREST : GL_LINEAR; 
int maxCoordS = (texTarget == GL_TEXTURE_RECTANGLE_NV) ? texWidth : 1; 
int maxCoordT = (texTarget == GL_TEXTURE_RECTANGLE_NV) ? texHeight : 1; 
GLuint textureProgram = 0, renderProgram = 0; 
float teapot_rot = 0.0f; 
 
#define GET_GLERROR(ret)                                          \ 
{                                                                 \ 
    GLenum err = glGetError();                                    \ 
    if (err != GL_NO_ERROR) {                                     \ 
    fprintf(stderr, "[%s line %d] GL Error: %s\n",                \ 
    __FILE__, __LINE__, gluErrorString(err));                     \ 
    fflush(stderr);                                               \ 
    }                                                             \ 
} 
 
void CheckFramebufferStatus() 
{ 
    GLenum status; 
    status = (GLenum) glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); 
    switch(status) { 
        case GL_FRAMEBUFFER_COMPLETE_EXT: 
            break; 
        case GL_FRAMEBUFFER_UNSUPPORTED_EXT: 
            printf("Unsupported framebuffer format\n"); 
            break; 
        case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: 
            printf("Framebuffer incomplete, missing attachment\n"); 
            break; 
        case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT: 
            printf("Framebuffer incomplete, duplicate attachment\n"); 
            break; 
        case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: 
            printf("Framebuffer incomplete, attached images must have same dimensions\n"); 
            break; 
        case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: 
            printf("Framebuffer incomplete, attached images must have same format\n"); 
            break; 
        case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: 
            printf("Framebuffer incomplete, missing draw buffer\n"); 
            break; 
        case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: 
            printf("Framebuffer incomplete, missing read buffer\n"); 
            break; 
        default: 
            assert(0); 
    } 
} 
 
void init_opengl() 
{ 
     if (!glh_init_extensions("GL_ARB_fragment_program " 
                              "GL_ARB_vertex_program " 
                              "GL_NV_float_buffer " 
                              "GL_EXT_framebuffer_object ")) 
     { 
         printf("Unable to load the following extension(s): %s\n\nExiting...\n",  
                glh_get_unsupported_extensions()); 
         quitapp(-1); 
     } 
 
    glEnable(GL_DEPTH_TEST); 
    glClearColor(0.2, 0.2, 0.2, 1.0); 
 
    glGenFramebuffersEXT(1, &fb); 
    glGenTextures(1, &tex); 
    glGenRenderbuffersEXT(1, &depth_rb); 
 
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);     
 
    // init texture 
    glBindTexture(texTarget, tex); 
    glTexImage2D(texTarget, 0, texInternalFormat, texWidth, texHeight, 0,  
                 GL_RGBA, GL_FLOAT, NULL); 
    GET_GLERROR(NULL); 
    glTexParameterf(texTarget, GL_TEXTURE_MIN_FILTER, filterMode); 
    glTexParameterf(texTarget, GL_TEXTURE_MAG_FILTER, filterMode); 
    glTexParameterf(texTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
    glTexParameterf(texTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 
 
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,  
                              texTarget, tex, 0); 
 
    GET_GLERROR(0); 
 
    // initialize depth renderbuffer 
    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_rb); 
    glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, texWidth, texHeight); 
    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,  
                                 GL_RENDERBUFFER_EXT, depth_rb); 
 
    GET_GLERROR(0); 
 
    CheckFramebufferStatus(); 
     
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 
 
    // load fragment programs 
    const char* strTextureProgram2D =  
        "!!ARBfp1.0\n" 
        "TEX result.color, fragment.texcoord[0], texture[0], 2D;\n" 
        "END\n"; 
 
    const char* strTextureProgramRECT =  
        "!!ARBfp1.0\n" 
        "TEX result.color, fragment.texcoord[0], texture[0], RECT;\n" 
        "END\n"; 
 
    glGenProgramsARB(1, &textureProgram); 
    glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, textureProgram); 
    // load correct program based on texture target 
    if (texTarget == GL_TEXTURE_RECTANGLE_NV) { 
        glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, 
                        (GLsizei)strlen(strTextureProgramRECT), strTextureProgramRECT); 
    } else { 
        glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, 
                        (GLsizei)strlen(strTextureProgram2D), strTextureProgram2D); 
    } 
 
    GET_GLERROR(0); 
 
    const char* strRenderProgram =  
        "!!ARBfp1.0\n" 
        "MOV result.color, fragment.color;\n" 
        "END\n"; 
     
    glGenProgramsARB(1, &renderProgram); 
    glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, renderProgram); 
    glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB,  
                       GL_PROGRAM_FORMAT_ASCII_ARB, 
                       (GLsizei)strlen(strRenderProgram), strRenderProgram); 
 
    GET_GLERROR(0); 
} 
 
void cleanup() 
{ 
    // destroy objects 
    glDeleteRenderbuffersEXT(1, &depth_rb); 
    glDeleteTextures(1, &tex); 
    glDeleteFramebuffersEXT(1, &fb); 
 
    glDeleteProgramsARB(1, &textureProgram); 
    glDeleteProgramsARB(1, &renderProgram); 
} 
 
void display() 
{ 
    // render to the render target texture first 
    glBindTexture(texTarget, 0); 
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb); 
    { 
        glPushAttrib(GL_VIEWPORT_BIT);  
        glViewport(0, 0, texWidth, texHeight); 
         
        glMatrixMode(GL_MODELVIEW); 
        glPushMatrix(); 
        glLoadIdentity(); 
        glTranslatef(0.0, 0.0, -1.5); 
        glRotatef(teapot_rot, 0.0, 1.0, 0.0); 
 
        glClearColor(0, 0, 0, 0); 
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
 
        glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, renderProgram); 
        glEnable(GL_FRAGMENT_PROGRAM_ARB); 
 
        glColor3f(0.0, 1.0, 0.0); 
        glutWireTeapot(0.5f); 
 
        glPopMatrix(); 
        glPopAttrib(); 
    } 
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 
 
    // now render to the screen using the texture... 
    glClearColor(0.2, 0.2, 0.2, 0.0); 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
    glMatrixMode(GL_MODELVIEW); 
    glPushMatrix(); 
    glLoadIdentity(); 
 
    object.apply_transform(); 
 
    // draw textured quad 
    glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, textureProgram); 
    glEnable(GL_FRAGMENT_PROGRAM_ARB); 
 
    glBindTexture(texTarget, tex); 
    glEnable(texTarget);   
 
    glColor3f(1.0, 1.0, 1.0); 
    glBegin(GL_QUADS); 
    { 
        glTexCoord2f(0,         0);         glVertex2f(-1, -1); 
        glTexCoord2f(maxCoordS, 0);         glVertex2f( 1, -1); 
        glTexCoord2f(maxCoordS, maxCoordT); glVertex2f( 1,  1); 
        glTexCoord2f(0,         maxCoordT); glVertex2f(-1,  1); 
    } 
    glEnd(); 
 
    glPopMatrix(); 
    glDisable(GL_FRAGMENT_PROGRAM_ARB); 
 
    glutSwapBuffers(); 
} 
 
void idle() 
{ 
    if (b[' ']) { 
        object.trackball.increment_rotation(); 
        teapot_rot += 0.5; 
    } 
 
    glutPostRedisplay(); 
} 
 
void key(unsigned char k, int x, int y) 
{ 
	b[k] = ! b[k]; 
    if(k==27 || k=='q') { 
        cleanup(); 
        exit(0); 
    } 
 
    object.keyboard(k, x, y); 
     
	glutPostRedisplay(); 
} 
 
void resize(int w, int h) 
{ 
    if (h == 0) h = 1; 
 
    glViewport(0, 0, w, h); 
     
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
     
    gluPerspective(60.0, (GLfloat)w/(GLfloat)h, 0.1, 100.0); 
     
    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 
 
    object.reshape(w, h); 
} 
 
void mouse(int button, int state, int x, int y) 
{ 
    object.mouse(button, state, x, y); 
} 
 
void motion(int x, int y) 
{ 
    object.motion(x, y); 
} 
 
int main(int argc, char **argv) 
{ 
	glutInit(&argc, argv); 
	glutInitWindowSize(512, 512); 
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGB); 
	glutCreateWindow("Simple Framebuffer Object"); 
 
	init_opengl(); 
 
    object.configure_buttons(1); 
    object.dolly.dolly[2] = -2; 
 
	glutDisplayFunc(display); 
    glutMouseFunc(mouse); 
    glutMotionFunc(motion); 
    glutIdleFunc(idle); 
    glutKeyboardFunc(key); 
    glutReshapeFunc(resize); 
 
    b[' '] = true; 
 
	glutMainLoop(); 
 
	return 0; 
}