OpenGL framebuffer: can clear it, but can't draw to it
Asked Answered
K

4

6

On a Mac, I've got an OpenGL setup that is working just fine apart from framebuffers - texturing works, etc. So I know that texturing is enabled, I have a valid context, etc. All works flawlessly until I try to create a framebuffer.

I created a framebuffer with glGenFramebuffers, glBindFramebuffer, and glFramebufferTexture2D, and glCheckFramebufferStatus is returning GL_FRAMEBUFFER_COMPLETE. If I then call glClear, followed by a call to glGetTexImage, the returned data shows that the glClear acted on the texture bound to the framebuffer just as it should. I can set glClearColor to anything I want, and the glClear sets the texture data correctly.

But that's where the good news stops. I can't draw anything into the framebuffer, whether I use VBOs or glBegin/glEnd. The texture data from the texture bound to the framebuffer is untouched by the draw calls (though the glClear results still appear). This is all true even if I call glFlush and glFinish before the glGetTexImage call. Also, glGetError is returning no error as to any of my calls.

I've posted below some sample code that I added at a relevant point in the program just to try to work on this issue, in case that gives anyone an idea. (This doesn't include the glClear call, but I know from separate testing at the same point that that works OK).

    glGenFramebuffers(1, &fb);
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbTexID, 0);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 
if(status != GL_FRAMEBUFFER_COMPLETE)
    Debugger(); 

glEnable(GL_TEXTURE_2D); 
glCullFace(GL_NONE); 
glGenTextures(1,(GLuint*)&tex); 
glBindTexture(GL_TEXTURE_2D,tex); 
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,1024,1024,0,GL_RGBA,GL_UNSIGNED_BYTE,NULL); 
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 1024, 1024, 0, -5000, 5000); 
glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); 
glViewport(0, 0, 1024, 1024); 
glColor4f(1,1,1,1); 
glBegin(GL_TRIANGLES);
    glTexCoord2f(0, 0);
    glVertex2f(0, 0);
    glTexCoord2f(1, 0);
    glVertex2f(1024, 0);
    glTexCoord2f(0, 1);
    glVertex2f(0, 1024);
glEnd();
glFlush();
glFinish(); 
unsigned char *dd = new unsigned char[1024*1024*4]; 
glBindTexture(GL_TEXTURE_2D, fbTexID); //I've tried calling glBindFramebuffer(GL_FRAMEBUFFER,0) before this bind - makes no difference
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, dd);
delete dd; 
Kinsler answered 6/9, 2011 at 18:7 Comment(3)
Where do you create fbTexID? Where do you use tex?Branton
Both fbTexID and tex are just GLuints, defined earlier. (In my actual code they are members of a larger struct; I substituted the simpler names in my post here for the sake of simplicity and clarity. Thanks.Kinsler
Just for future readers and because I just stumbled upon it: Multisampling and FBOs might produce problems, too.Daisey
K
5

OK, answered my own question. It seems that the texture you generate to be the surface that the frame buffer draws to must be generated after the frame buffer is generated. So, this works:

glGenFramebuffers...
glBindFramebuffer...
glGenTextures...
glBindTexture...
glTexParameterf etc.
glFramebufferTexture2D...

but this does not:

glGenTextures...
glBindTexture...
glGenFramebuffers
glBindFramebuffer...
glFramebufferTexture2D...

I don't see this addressed anywhere, and it seems surprising, but my code went from not working to working just by moving the generation of the texture.

Kinsler answered 16/12, 2011 at 2:46 Comment(0)
C
9

Your texture did not work because it was bound! You cannnot have a bound texture work on a FBO as a rendertarget! This is something that isn't very documented, but makes sense when you think about it The driver developers need some safeguards too, just in case you do something weird like reading and writing to the same texture at the same time

Chassepot answered 19/11, 2012 at 22:43 Comment(0)
K
5

OK, answered my own question. It seems that the texture you generate to be the surface that the frame buffer draws to must be generated after the frame buffer is generated. So, this works:

glGenFramebuffers...
glBindFramebuffer...
glGenTextures...
glBindTexture...
glTexParameterf etc.
glFramebufferTexture2D...

but this does not:

glGenTextures...
glBindTexture...
glGenFramebuffers
glBindFramebuffer...
glFramebufferTexture2D...

I don't see this addressed anywhere, and it seems surprising, but my code went from not working to working just by moving the generation of the texture.

Kinsler answered 16/12, 2011 at 2:46 Comment(0)
M
1

This is a FBO test I wrote some time ago:

#include <GL/glew.h>
#include <GL/glut.h>

#include <cmath>
#include <iostream>

using namespace std;

namespace render
{
    int width, height;
    float aspect;

    void init();
    void reshape(int width, int height);
    void display();

    int const fbo_width = 512;
    int const fbo_height = 512;

    GLuint fb, color, depth;
};

void idle();

int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH );

    glutCreateWindow("FBO test");
    glutDisplayFunc(render::display);
    glutReshapeFunc(render::reshape);
    glutIdleFunc(idle);

    glewInit();

    render::init();
    glutMainLoop();

    return 0;
}

void idle()
{
    glutPostRedisplay();
}

void CHECK_FRAMEBUFFER_STATUS()
{                                                         
    GLenum status;
    status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); 
    switch(status) {
    case GL_FRAMEBUFFER_COMPLETE:
        break;

    case GL_FRAMEBUFFER_UNSUPPORTED:
    /* choose different formats */
        break;

    default:
        /* programming error; will fail on all hardware */
        throw "Framebuffer Error";
    }
}

namespace render
{
    float const light_dir[]={1,1,1,0};
    float const light_color[]={1,0.95,0.9,1};

    void init()
    {
        glGenFramebuffers(1, &fb);
        glGenTextures(1, &color);
        glGenRenderbuffers(1, &depth);

        glBindFramebuffer(GL_FRAMEBUFFER, fb);

        glBindTexture(GL_TEXTURE_2D, color);
        glTexImage2D(   GL_TEXTURE_2D, 
                0, 
                GL_RGBA, 
                fbo_width, fbo_height,
                0, 
                GL_RGBA, 
                GL_UNSIGNED_BYTE, 
                NULL);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0);

        glBindRenderbuffer(GL_RENDERBUFFER, depth);
        glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, fbo_width, fbo_height);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth);

        CHECK_FRAMEBUFFER_STATUS();
    }

    void reshape(int width, int height)
    {
        render::width=width;
        render::height=height;
        aspect=float(width)/float(height);
        glutPostRedisplay();
    }

    void prepare()
    {
        static float a=0, b=0, c=0;

        glBindTexture(GL_TEXTURE_2D, 0);
        glEnable(GL_TEXTURE_2D);
        glBindFramebuffer(GL_FRAMEBUFFER, fb);

        glViewport(0,0,fbo_width, fbo_height);

        glClearColor(1,1,1,0);
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(45, 1, 1, 10);

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        glEnable(GL_LIGHT0);
        glEnable(GL_LIGHTING);

        glEnable(GL_DEPTH_TEST);
        glDisable(GL_CULL_FACE);

        glLightfv(GL_LIGHT0, GL_POSITION, light_dir);
        glLightfv(GL_LIGHT0, GL_DIFFUSE, light_color);

        glTranslatef(0,0,-5);

        glRotatef(a, 1, 0, 0);
        glRotatef(b, 0, 1, 0);
        glRotatef(c, 0, 0, 1);

        glutSolidTeapot(0.75);

        a=fmod(a+0.1, 360.);
        b=fmod(b+0.5, 360.);
        c=fmod(c+0.25, 360.);
    }

    void final()
    {
        static float a=0, b=0, c=0;

        glBindFramebuffer(GL_FRAMEBUFFER, 0);

        glViewport(0,0, width, height);

        glClearColor(1.,1.,1.,0.);
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(45, aspect, 1, 10);

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(0,0,-5);

        glRotatef(b, 0, 1, 0);

        b=fmod(b+0.5, 360.);

        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, color);

        glEnable(GL_DEPTH_TEST);
        glEnable(GL_CULL_FACE);

        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

        glDisable(GL_LIGHTING);

        float cube[][5]=
        {
            {-1, -1, -1,  0,  0},
            { 1, -1, -1,  1,  0},
            { 1,  1, -1,  1,  1},
            {-1,  1, -1,  0,  1},

            {-1, -1,  1, -1,  0},
            { 1, -1,  1,  0,  0},
            { 1,  1,  1,  0,  1},
            {-1,  1,  1, -1,  1},
        };
        unsigned int faces[]=
        {
            0, 1, 2, 3,
            1, 5, 6, 2,
            5, 4, 7, 6,
            4, 0, 3, 7,
            3, 2, 6, 7,
            4, 5, 1, 0
        };

        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);

        glVertexPointer(3, GL_FLOAT, 5*sizeof(float), &cube[0][0]);
        glTexCoordPointer(2, GL_FLOAT, 5*sizeof(float), &cube[0][3]);

        glCullFace(GL_BACK);
        glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, faces);

        glCullFace(GL_FRONT);
        glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, faces);

        glDisableClientState(GL_VERTEX_ARRAY);
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);

    }

    void display()
    {
        prepare();
        final();

        glutSwapBuffers();
    }
}

Maybe this reference helps

Moderation answered 6/9, 2011 at 18:17 Comment(0)
B
0

Here's a FBO "benchmark" I wrote a while ago. set_fbo_size() has a creation sequence that Works For Me(TM).

/////////////////////////////////////////////////////////////////////////////
// INCLUDES /////////////////////////////////////////////////////////////////

#include <GL/glew.h>
#include <GL/glut.h>

#include <iostream>
#include <iomanip>
#include <sstream>

using namespace std;


/////////////////////////////////////////////////////////////////////////////
// CLASSES //////////////////////////////////////////////////////////////////

// http://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
class ExpAvg 
{
public:
    ExpAvg(float initial, unsigned int time_periods) : avg(initial), alpha(2.0f / ( time_periods + 1 )) {}
    void Update(float nextval) { avg = alpha*nextval + (1.0f-alpha)*avg; }
    float Get() { return avg; }
private:
    float avg;
    float alpha;
};

class gl2D
{
public:
    gl2D() {
        int viewport[4];
        glGetIntegerv(GL_VIEWPORT, viewport);
        glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity();
        gluOrtho2D(0, viewport[2], 0, viewport[3]);
        glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity();
    }
    ~gl2D() {
        glMatrixMode(GL_PROJECTION); glPopMatrix();
        glMatrixMode(GL_MODELVIEW); glPopMatrix();
    }
};


/////////////////////////////////////////////////////////////////////////////
// GLOBALS //////////////////////////////////////////////////////////////////

int screen_width = 1024;
int screen_height = 768;
int mouse_x, mouse_y;
bool mouse_left, mouse_right;
float camera_angle_x = 45;
float camera_angle_y = 45;
float camera_distance = 0;

int texture_width, texture_height;
GLuint tex, fbo, rbo;  // object IDs


/////////////////////////////////////////////////////////////////////////////
// UTILITIES ////////////////////////////////////////////////////////////////

bool get_fbo_status()
{
    GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
    switch(status) {
    case GL_FRAMEBUFFER_COMPLETE_EXT: 
        cout << "Framebuffer complete." << endl; return true;
    case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
        cerr << "[ERROR] Attachment is NOT complete." << endl; return false;
    case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
        cerr << "[ERROR] No image is attached to FBO." << endl; return false;
    case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
        cerr << "[ERROR] Attached images have different dimensions." << endl; return false;
    case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
        cerr << "[ERROR] Color attached images have different internal formats." << endl; return false;
    case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
        cerr << "[ERROR] Draw buffer." << endl; return false;
    case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
        cerr << "[ERROR] Read buffer." << endl; return false;
    case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
        cerr << "[ERROR] Unsupported by FBO implementation." << endl; return false;
    default:
        cerr << "[ERROR] Unknow error." << endl; return false;
    }
}

void gl_print(const char *str, int x, int y, void *font)
{
    glPushAttrib(GL_ENABLE_BIT);
    glDisable(GL_LIGHTING);     // need to disable lighting for proper text color
    glDisable(GL_TEXTURE_2D);
    glRasterPos2i(x, y);        // place text position
    while(*str) glutBitmapCharacter(font, *str++); 
    glPopAttrib();
}

void textured_cube()
{
    glBegin(GL_QUADS);
    glColor4f(1, 1, 1, 1);

    // face v0-v1-v2-v3
    glNormal3f(0,0,1);
    glTexCoord2f(1, 1);  glVertex3f(1,1,1);
    glTexCoord2f(0, 1);  glVertex3f(-1,1,1);
    glTexCoord2f(0, 0);  glVertex3f(-1,-1,1);
    glTexCoord2f(1, 0);  glVertex3f(1,-1,1);

    // face v0-v3-v4-v5
    glNormal3f(1,0,0);
    glTexCoord2f(0, 1);  glVertex3f(1,1,1);
    glTexCoord2f(0, 0);  glVertex3f(1,-1,1);
    glTexCoord2f(1, 0);  glVertex3f(1,-1,-1);
    glTexCoord2f(1, 1);  glVertex3f(1,1,-1);

    // face v0-v5-v6-v1
    glNormal3f(0,1,0);
    glTexCoord2f(1, 0);  glVertex3f(1,1,1);
    glTexCoord2f(1, 1);  glVertex3f(1,1,-1);
    glTexCoord2f(0, 1);  glVertex3f(-1,1,-1);
    glTexCoord2f(0, 0);  glVertex3f(-1,1,1);

    // face  v1-v6-v7-v2
    glNormal3f(-1,0,0);
    glTexCoord2f(1, 1);  glVertex3f(-1,1,1);
    glTexCoord2f(0, 1);  glVertex3f(-1,1,-1);
    glTexCoord2f(0, 0);  glVertex3f(-1,-1,-1);
    glTexCoord2f(1, 0);  glVertex3f(-1,-1,1);

    // face v7-v4-v3-v2
    glNormal3f(0,-1,0);
    glTexCoord2f(0, 0);  glVertex3f(-1,-1,-1);
    glTexCoord2f(1, 0);  glVertex3f(1,-1,-1);
    glTexCoord2f(1, 1);  glVertex3f(1,-1,1);
    glTexCoord2f(0, 1);  glVertex3f(-1,-1,1);

    // face v4-v7-v6-v5
    glNormal3f(0,0,-1);
    glTexCoord2f(0, 0);  glVertex3f(1,-1,-1);
    glTexCoord2f(1, 0);  glVertex3f(-1,-1,-1);
    glTexCoord2f(1, 1);  glVertex3f(-1,1,-1);
    glTexCoord2f(0, 1);  glVertex3f(1,1,-1);
    glEnd();
}

bool set_fbo_size(int width, int height)
{
    int max_size;
    glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &max_size);
    if(width > max_size) return false;
    if(height > max_size) return false;

    texture_width = width; texture_height = height;

    // create FBO
    if(fbo) glDeleteFramebuffersEXT(1, &fbo);
    glGenFramebuffersEXT(1, &fbo);
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);    

    // create and attach a new texture as the FBO's color buffer
    if(tex) glDeleteTextures(1, &tex);
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, tex, 0);

    // create and attach a new depth buffer to currently bound FBO
    if(rbo) glDeleteRenderbuffersEXT(1, &rbo);
    glGenRenderbuffersEXT(1, &rbo);
    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rbo);
    glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height);
    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, rbo);

    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // unbind fbo
    if( !get_fbo_status() ) exit(1);
    return true;
}


/////////////////////////////////////////////////////////////////////////////
// GLUT CALLBACKS ///////////////////////////////////////////////////////////

void CB_Idle()
{
    glutPostRedisplay();
}

void CB_Reshape(int width, int height)
{
    screen_width = width;
    screen_height = height;
    glViewport(0, 0, (GLsizei)width, (GLsizei)height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0f, (float)(width)/height, 1.0f, 1000.0f); 
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void CB_Mouse(int button, int state, int x, int y)
{
    mouse_x = x; mouse_y = y;
    if(button == GLUT_LEFT_BUTTON)
        mouse_left = (state == GLUT_DOWN);
    else if(button == GLUT_RIGHT_BUTTON)
        mouse_right = (state == GLUT_DOWN);
}

void CB_Motion(int x, int y)
{
    if(mouse_left) {
        camera_angle_y += (x - mouse_x);
        camera_angle_x += (y - mouse_y);
        mouse_x = x; mouse_y = y;
    }
    if(mouse_right) {
        camera_distance += (y - mouse_y) * 0.2f;
        mouse_y = y;
    }
}

void CB_Keyboard(unsigned char key, int x, int y)
{
    static int drawMode = 0;
    static int tex_size = 0;
    bool ret = false;

    switch(key) {
    case 27: // ESCAPE
        exit(0);
        break;
    case ' ':
        while(!ret) {
            tex_size = (tex_size+1) % 7;
            switch(tex_size) {
                case 0: ret = set_fbo_size(128,128); break;
                case 1: ret = set_fbo_size(256,256); break;
                case 2: ret = set_fbo_size(512,512); break;
                case 3: ret = set_fbo_size(1024,1024); break;
                case 4: ret = set_fbo_size(2048,2048); break;
                case 5: ret = set_fbo_size(4096,4096); break;
                case 6: ret = set_fbo_size(8192,8192); break;
                default: ; break;
            }
        }
        break;
    default:
        break;
    }
    glutPostRedisplay();
}

void CB_Init() 
{
    GLenum err = glewInit();
    if(GLEW_OK != err) {
        cerr << "Error: " << glewGetErrorString(err) << endl; 
        exit(1);
    }

    if(!GLEW_EXT_framebuffer_object) {
        cerr << "Requires EXT_framebuffer_object" << endl; 
        exit(1);
    }

    tex = fbo = rbo = 0;

    glShadeModel(GL_SMOOTH);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LIGHTING);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_CULL_FACE);

    glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
    glEnable(GL_COLOR_MATERIAL);
    glClearColor(0, 0, 0, 0);

    GLfloat lightKa[] = {.2f, .2f, .2f, 1.0f};  // ambient light
    GLfloat lightKd[] = {.7f, .7f, .7f, 1.0f};  // diffuse light
    GLfloat lightKs[] = {1, 1, 1, 1};           // specular light
    glLightfv(GL_LIGHT0, GL_AMBIENT, lightKa);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, lightKd);
    glLightfv(GL_LIGHT0, GL_SPECULAR, lightKs);
    float lightPos[4] = {0, 0, 20, 1};          // positional light
    glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
    glEnable(GL_LIGHT0);

    set_fbo_size(128, 128);
}

void CB_Exit()
{
    glDeleteTextures(1, &tex);
    glDeleteFramebuffersEXT(1, &fbo);
    glDeleteRenderbuffersEXT(1, &rbo);
}

void CB_Display()
{
    static ExpAvg ft_fbo(0, 19);
    static ExpAvg ft_overall(0, 19);

    int before = glutGet(GLUT_ELAPSED_TIME);  

    // compute rotation angle
    const float ANGLE_SPEED = 90;   // degree/s
    float angle = ANGLE_SPEED * (glutGet(GLUT_ELAPSED_TIME) / 1000.0f);

    // render using fbo /////////////////////////////////////////////
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // bind fbo

    // adjust viewport and projection matrix to texture dimension
    glViewport(0, 0, texture_width, texture_height);
    glMatrixMode(GL_PROJECTION); glLoadIdentity();
    gluPerspective(60.0f, (float)(texture_width)/texture_height, 1.0f, 100.0f);
    glMatrixMode(GL_MODELVIEW); glLoadIdentity();

    // clear buffer
    glClearColor(1, 1, 1, 0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glTranslatef(0,0,-3);
    glPushMatrix();
    glRotatef(angle*0.5f, 1, 0, 0);
    glRotatef(angle, 0, 1, 0);
    glRotatef(angle*0.7f, 0, 0, 1);

    // set up teapot colors
    float shininess = 15.0f;
    float diffuseColor[3] = {0.929524f, 0.796542f, 0.178823f};
    float specularColor[4] = {1.00000f, 0.980392f, 0.549020f, 1.0f};
    glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess); // range 0 ~ 128
    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specularColor);
    glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
    glColor3fv(diffuseColor);

    glBindTexture(GL_TEXTURE_2D, 0);
    glFrontFace(GL_CW);
    glutSolidTeapot(1.0); 
    glFrontFace(GL_CCW); 
    glPopMatrix();

    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // unbind fbo
    glFinish();

    ft_fbo.Update( (float)(glutGet(GLUT_ELAPSED_TIME) - before) );

    // normal rendering ///////////////////////////////////

    // back to normal viewport and projection matrix
    glViewport(0, 0, screen_width, screen_height);
    glMatrixMode(GL_PROJECTION); glLoadIdentity();
    gluPerspective(60.0f, (float)(screen_width)/screen_height, 1.0f, 100.0f);
    glMatrixMode(GL_MODELVIEW); glLoadIdentity();

    glClearColor(0, 0, 0, 0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glTranslatef(0,0,-4);
    glPushMatrix();
    glTranslatef(0, 0, camera_distance);
    glRotatef(camera_angle_x, 1, 0, 0);
    glRotatef(camera_angle_y, 0, 1, 0);

    // draw a cube with the dynamic texture
    glBindTexture(GL_TEXTURE_2D, tex);
    textured_cube();     
    glPopMatrix();

    { 
        gl2D two_dee;   // set 2D mode
        glDisable(GL_DEPTH_TEST);
        stringstream ss;
        glColor3f(1,1,0);
        ss << fixed << setprecision(3);
        int pos = 1;

        ss.str(""); ss << "Texture size: " << texture_width << "x" << texture_height;
        gl_print(ss.str().c_str(), 10, screen_height - (pos++ * 20), GLUT_BITMAP_8_BY_13);
        ss.str(""); ss << "Overall frame time: " << ft_overall.Get() << " ms";
        gl_print(ss.str().c_str(), 10, screen_height - (pos++ * 20), GLUT_BITMAP_8_BY_13);
        ss.str(""); ss << "    FBO frame time: " << ft_fbo.Get() << " ms";
        gl_print(ss.str().c_str(), 10, screen_height - (pos++ * 20), GLUT_BITMAP_8_BY_13);
        ss.str(""); ss << "Press space to change texture size; mouse moves/zooms cube";
        gl_print(ss.str().c_str(), 10, 10, GLUT_BITMAP_8_BY_13);
        glEnable(GL_DEPTH_TEST);
    }

    glutSwapBuffers();
    ft_overall.Update( (float)(glutGet(GLUT_ELAPSED_TIME) - before) );
}


/////////////////////////////////////////////////////////////////////////////
// MAIN /////////////////////////////////////////////////////////////////////

int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
    glutInitWindowSize(screen_width, screen_height);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("FBO Test");

    glutDisplayFunc(CB_Display);
    glutIdleFunc(CB_Idle);
    glutReshapeFunc(CB_Reshape);
    glutKeyboardFunc(CB_Keyboard);
    glutMouseFunc(CB_Mouse);
    glutMotionFunc(CB_Motion);
    atexit(CB_Exit);

    CB_Init();
    glutMainLoop();
    return 0;
}
Branton answered 6/9, 2011 at 18:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.