// This code example is created for educational purpose // by Thorsten Thormaehlen (contact: www.thormae.de). // It is distributed without any warranty. #include #include // we use glut here as window manager #define _USE_MATH_DEFINES #include #include #include #include #include using namespace std; class Renderer { public: float t; int mode; private: GLuint fboID; GLuint depthID; int fboTexSize; int width; int height; public: // constructor Renderer() : t(0.0), mode(1), fboID(0), depthID(0), fboTexSize(512), width(0), height(0) {} // destructor ~Renderer() { if(fboID !=0) glDeleteFramebuffers(1, &fboID); if(depthID != 0) glDeleteTextures(1, &depthID); } public: void init() { glEnable(GL_DEPTH_TEST); // create a frame buffer object glGenFramebuffers(1, &fboID); // bind the frame buffer glBindFramebuffer(GL_FRAMEBUFFER, fboID); // Generate render texture // this is not used (but some drivers require it) GLuint texID; glGenTextures (1, &texID); glBindTexture(GL_TEXTURE_2D, texID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); int level = 0; glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, fboTexSize, fboTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // Attach the texture to the fbo glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texID, level); if(!checkFramebufferStatus()) exit(1); // Generate depth render texture glGenTextures (1, &depthID); glBindTexture(GL_TEXTURE_2D, depthID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, level, GL_DEPTH_COMPONENT, fboTexSize, fboTexSize, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // Attach the texture to the fbo glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthID, level); if(!checkFramebufferStatus()) exit(1); // unbind texture glBindTexture(GL_TEXTURE_2D, 0); //unbind fbo glBindFramebuffer(GL_FRAMEBUFFER, 0); } void resize(int w, int h) { width = w; height = h; changeViewport(w, h); } void display() { if(mode > 0) { // bind the fbo glBindFramebuffer(GL_FRAMEBUFFER, fboID); changeViewport(fboTexSize,fboTexSize); }else{ changeViewport(width, height); } glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // render to attached fbo drawScene(); if(mode == 1) { // unbind frame buffer glBindFramebuffer(GL_FRAMEBUFFER, 0); changeViewportOrtho(width, height); // using first render pass result as texture glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, depthID); //draw quad with depth texture glColor3f(1.0f,0.0f,0.0f); glBegin(GL_POLYGON); glTexCoord2f(0.00f,0.00f); glVertex3f(-1.0f,-1.0f, 0.0f); glTexCoord2f(1.00f,0.00f); glVertex3f( 1.0f,-1.0f, 0.0f); glTexCoord2f(1.00f,1.00f); glVertex3f( 1.0f, 1.0f, 0.0f); glTexCoord2f(0.00f,1.00f); glVertex3f(-1.0f, 1.0f, 0.0f); glEnd(); glDisable(GL_TEXTURE_2D); } } private: void changeViewport(int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective (30.0, (float)w/(float)h, 7.0, 12.0); } void changeViewportOrtho(int w, int h) { float aspect = (float)w/(float)h; glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1.0*aspect, 1.0*aspect, -1.0, 1.0, -1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void drawScene() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // set camera gluLookAt(8.0, -2.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0); // draw scene glRotatef(t, 0.0f, 0.0f, 1.0f); drawTexturedCube(); } bool checkFramebufferStatus() { GLenum status; status = (GLenum) glCheckFramebufferStatus(GL_FRAMEBUFFER); switch(status) { case GL_FRAMEBUFFER_COMPLETE: return true; case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: printf("Framebuffer incomplete, incomplete attachment\n"); return false; case GL_FRAMEBUFFER_UNSUPPORTED: printf("Unsupported framebuffer format\n"); return false; case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: printf("Framebuffer incomplete, missing attachment\n"); return false; case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: printf("Framebuffer incomplete, missing draw buffer\n"); return false; case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: printf("Framebuffer incomplete, missing read buffer\n"); return false; } return false; } void drawTexturedCube() { glColor3f(1.0f,0.0f,0.0f); glBegin(GL_POLYGON); glTexCoord2f(0.00f,0.00f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(1.00f,0.00f); glVertex3f(-1.0f,-1.0f, 1.0f); glTexCoord2f(1.00f,1.00f); glVertex3f( 1.0f,-1.0f, 1.0f); glTexCoord2f(0.00f,1.00f); glVertex3f( 1.0f, 1.0f, 1.0f); glEnd(); glColor3f(1.0f,1.0f,0.0f); glBegin(GL_POLYGON); glTexCoord2f(0.00f,0.00f); glVertex3f(-1.0f, 1.0f,-1.0f); glTexCoord2f(1.00f,0.00f); glVertex3f(-1.0f,-1.0f,-1.0f); glTexCoord2f(1.00f,1.00f); glVertex3f(-1.0f,-1.0f, 1.0f); glTexCoord2f(0.00f,1.00f); glVertex3f(-1.0f, 1.0f, 1.0f); glEnd(); glColor3f(0.0f,0.0f,1.0f); glBegin(GL_POLYGON); glTexCoord2f(0.00f,0.00f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(1.00f,0.00f); glVertex3f( 1.0f,-1.0f, 1.0f); glTexCoord2f(1.00f,1.00f); glVertex3f( 1.0f,-1.0f,-1.0f); glTexCoord2f(0.00f,1.00f); glVertex3f( 1.0f, 1.0f,-1.0f); glEnd(); glColor3f(1.0f,0.0f,1.0f); glBegin(GL_POLYGON); glTexCoord2f(0.00f,0.00f); glVertex3f(-1.0f, 1.0f,-1.0f); glTexCoord2f(1.00f,0.00f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(1.00f,1.00f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(0.00f,1.00f); glVertex3f( 1.0f, 1.0f,-1.0f); glEnd(); glColor3f(0.0f,1.0f,1.0f); glBegin(GL_POLYGON); glTexCoord2f(0.00f,0.00f); glVertex3f(-1.0f, -1.0f, 1.0f); glTexCoord2f(1.00f,0.00f); glVertex3f(-1.0f, -1.0f,-1.0f); glTexCoord2f(1.00f,1.00f); glVertex3f( 1.0f, -1.0f,-1.0f); glTexCoord2f(0.00f,1.00f); glVertex3f( 1.0f, -1.0f, 1.0f); glEnd(); glColor3f(0.0f,1.0f,0.0f); glBegin(GL_POLYGON); glTexCoord2f(0.00f,0.00f); glVertex3f( 1.0f, 1.0f,-1.0f); glTexCoord2f(1.00f,0.00f); glVertex3f( 1.0f,-1.0f,-1.0f); glTexCoord2f(1.00f,1.00f); glVertex3f(-1.0f,-1.0f,-1.0f); glTexCoord2f(0.00f,1.00f); glVertex3f(-1.0f, 1.0f,-1.0f); glEnd(); } }; //this is a static pointer to a Renderer used in the glut callback functions static Renderer *renderer; //glut static callbacks start static void glutResize(int w, int h) { renderer->resize(w,h); } static void glutDisplay() { renderer->display(); glutSwapBuffers(); glutReportErrors(); } static void timer(int v) { float offset = 0.25f; renderer->t += offset; glutDisplay(); glutTimerFunc(unsigned(20), timer, ++v); } static void glutKeyboard(unsigned char key, int x, int y) { bool redraw = false; std::string modeStr; switch(key) { case '1': if(renderer->mode == 1) { renderer->mode = 0; modeStr = "first render pass result"; } else { renderer->mode = 1; modeStr = "second render pass result"; } redraw = true; break; } if(redraw) { glutDisplay(); cout << modeStr << endl; glutSetWindowTitle(modeStr.c_str()); } } int main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); glutInitWindowPosition(100,100); glutInitWindowSize(320, 320); glutCreateWindow("Press 1 to toggle between first/second render pass"); GLenum err = glewInit(); if (GLEW_OK != err) { fprintf(stderr, "Glew error: %s\n", glewGetErrorString(err)); } glutDisplayFunc(glutDisplay); //glutIdleFunc(glutDisplay); glutReshapeFunc(glutResize); glutKeyboardFunc(glutKeyboard); renderer = new Renderer; renderer->init(); glutTimerFunc(unsigned(20), timer, 0); glutMainLoop(); }