/* * to compile: * gcc multiFBO.c -I/usr/include/GL -lglut -I~/SDK/LIBS/inc -lCg -lpthread -lCgGL * where you may need to set the SDK include path to where your SDK path is. * * Renders to a frambuffer object, then uses result as a texture. * A Fragment shader runs on the rendered frambuffer scene, turning the line * to a different colour (as specified by the output colour in the fragment * shader program) * this program uses a fragment program to render fragments to two different * targets of the framebuffer object. The targets are COLOR_ATTACHMENT0 and * COLOR_ATTACHMENT1 corresponding to the output colors COLORO and COLOR1 in * the fragment program. * * The scene rendered to the render targets * is a blue background with a diagonal line. The color of the fragments * produced by this line is set by the fragmnt program, rendered as a * grey line for texture0 (color_attachment0, colorO) , and red for the * other. * * The scene rendered to the screen is a green background with two * textured quadrilaterals. in the upper left is the first rendered texture, * (with the grey coloured line) and in the lower right is the second * rendered texture (with the red line) */ #include #include #include #include #include #include GLuint fb,depth_rb,tex[2]; /* vars for Cg */ CGcontext cgContext; CGprogram fragmentProgram; CGprofile cgProfile; /* vars to draw to multiple draw buffers */ int numBuffers = 2; const GLenum buffers[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT }; #define CHECK_FRAMEBUFFER_STATUS() \ {\ GLenum status; \ status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); \ fprintf(stderr, "%x\n", status);\ switch(status) { \ case GL_FRAMEBUFFER_COMPLETE_EXT: \ fprintf(stderr,"framebuffer complete!\n");\ break; \ case GL_FRAMEBUFFER_UNSUPPORTED_EXT: \ fprintf(stderr,"framebuffer GL_FRAMEBUFFER_UNSUPPORTED_EXT\n");\ /* you gotta choose different formats */ \ assert(0); \ break; \ case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: \ fprintf(stderr,"framebuffer INCOMPLETE_ATTACHMENT\n");\ break; \ case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: \ fprintf(stderr,"framebuffer FRAMEBUFFER_MISSING_ATTACHMENT\n");\ break; \ case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: \ fprintf(stderr,"framebuffer FRAMEBUFFER_DIMENSIONS\n");\ break; \ case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT: \ fprintf(stderr,"framebuffer INCOMPLETE_DUPLICATE_ATTACHMENT\n");\ break; \ case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: \ fprintf(stderr,"framebuffer INCOMPLETE_FORMATS\n");\ break; \ case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: \ fprintf(stderr,"framebuffer INCOMPLETE_DRAW_BUFFER\n");\ break; \ case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: \ fprintf(stderr,"framebuffer INCOMPLETE_READ_BUFFER\n");\ break; \ case GL_FRAMEBUFFER_BINDING_EXT: \ fprintf(stderr,"framebuffer BINDING_EXT\n");\ break; \ default: \ /* programming error; will fail on all hardware */ \ assert(0); \ }\ } /* * A callback function for cg to use when it encounters an error */ void cgErrorCallback(void) { CGerror LastError = cgGetError(); if(LastError) { const char *Listing = cgGetLastListing(cgContext); printf("\n---------------------------------------------------\n"); printf("%s\n\n", cgGetErrorString(LastError)); printf("%s\n", Listing); printf("---------------------------------------------------\n"); printf("Cg error, exiting...\n"); exit(0); } } int imageWinWidth = 256; int imageWinHeight = 256; void reshape(int w, int h) { glClearColor (0.0, 0.0, 0.0, 0.0); glViewport(0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(0.0, 1.0, 1.0, 0.0, 1.0, 100.0); gluLookAt(0.0,0.0,0.0, 0.0, 0.0, -1.0, 0.0, 1.0, 0.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glutPostRedisplay(); } static GLenum errCode; const GLubyte *errString; void errcheck() { if ((errCode = glGetError()) != GL_NO_ERROR) { errString = gluErrorString(errCode); fprintf (stderr, "OpenGL Error: %s\n", errString); exit(1); } } void myIdle(){ glutPostRedisplay(); } void keyboard (unsigned char key, int x, int y) { switch (key) { case 27: exit(0); break; default: break; } } void MouseFunc( int button, int state, int x, int y) { switch(button) { case GLUT_LEFT_BUTTON : break; case GLUT_RIGHT_BUTTON : break; } } void render_redirect() { // clear all buffers // set destination buffers //bind the FBO, and the associated texture. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb); glDrawBuffers(2, buffers); errcheck(); // draw a scene. the results are being // written into the associated texture,'tex' glClearColor(0.0, 0.0, 1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor4f( 1.0, 1.0, 1.0, 1.0); glLineWidth(5.0); //enable the fragment program. It wil colour the following line // differently: grey for the first textue target (attachemnt0), and // red for the second one. cgGLEnableProfile(cgProfile); cgGLBindProgram(fragmentProgram); glBegin(GL_LINES); glColor4f( 1.0, 1.0, 1.0, 1.0); glVertex3f( 0.0, 0.0, -1.0); glVertex3f( 1.0, 1.0, -1.0); glEnd(); cgGLDisableProfile(cgProfile); // 'unbind' the FBO. things will now be drawn to screen as usual glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glClearColor(0.0, 1.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3f(1.0, 1.0, 1.0); glEnable(GL_TEXTURE_RECTANGLE_NV); glBindTexture(GL_TEXTURE_RECTANGLE_NV, tex[0]); // draw the first texture containing the render results of output COLOR0 // from the fragment shader glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex3f(0.0, 0.0, -1.0); glTexCoord2f(0, 256); glVertex3f(0.0, .5, -1.0); glTexCoord2f(256,256); glVertex3f(.5,.5, -1.0); glTexCoord2f(256,0); glVertex3f(.5, 0.0, -1.0); glEnd(); glDisable(GL_TEXTURE_RECTANGLE_NV); glEnable(GL_TEXTURE_RECTANGLE_NV); glBindTexture(GL_TEXTURE_RECTANGLE_NV, tex[1]); // draw the second texture containing the render results of output COLOR1 // from the fragment shader glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex3f(0.5, 0.5, -1.0); glTexCoord2f(0, 256); glVertex3f(0.5, 1.0, -1.0); glTexCoord2f(256,256); glVertex3f(1.0,1.0, -1.0); glTexCoord2f(256,0); glVertex3f(1.0, 0.5, -1.0); glEnd(); glDisable(GL_TEXTURE_RECTANGLE_NV); glutSwapBuffers(); } void init_cg() { cgProfile = CG_PROFILE_FP40; cgSetErrorCallback(cgErrorCallback); cgContext = cgCreateContext(); fragmentProgram = cgCreateProgramFromFile( cgContext, CG_SOURCE, "FP-name.cg", cgProfile, "FragmentProgram", 0); cgGLLoadProgram( fragmentProgram ); } int main(int argc, char *argv[] ) { glutInit( &argc, argv ); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(imageWinWidth, imageWinHeight); glutCreateWindow(argv[0]); //gen the frambuffer object (FBO), similar manner as a texture glGenFramebuffersEXT(1, &fb); errcheck(); // make a texture glGenTextures(2, &tex[0]); // texture //bind the framebuffer, fb, so operations will now occur on it glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb); // initialize texture that will store the framebuffer image (first target) glBindTexture(GL_TEXTURE_RECTANGLE_NV, tex[0]); glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GL_RGBA, 256,256, 0, GL_RGBA, GL_FLOAT,NULL); errcheck(); // bind this texture to the current framebuffer obj. as // color_attachement_0 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_NV, tex[0], 0); errcheck(); // initialize texture that will store the framebuffer image (second target) glBindTexture(GL_TEXTURE_RECTANGLE_NV, tex[1]); glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GL_RGBA, 256,256, 0, GL_RGBA, GL_FLOAT,NULL); errcheck(); // bind this texture to the current framebuffer obj. as // color_attachement_1 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_NV, tex[1], 0); errcheck(); //see if everything is OK CHECK_FRAMEBUFFER_STATUS() //'unbind' the frambuffer object, so subsequent drawing ops are not // drawn into the FBO. // '0' means "windowing system provided framebuffer glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); init_cg(); glutDisplayFunc(render_redirect); glutIdleFunc(myIdle); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMouseFunc(MouseFunc); glutMainLoop(); return 0; }