/*------------------------------------------------------------------------------ GL_READ_FRAMEBUFFER, or GL_DRAW_FRAMEBUFFER. allow you to bind an FBO so that reading commands (glReadPixels, glCopyPixels, etc) and writing commands (any command of the form glDraw*) can happen to two different buffers. width = display_mode->width; height = display_mode->height; ------------------------------------------------------------------------------*/ void render_to_fbo(void) { GLuint frame_buffer_name = 0, render_buffer_name = 0; int width, height; // make the FBO as big as the screen width = glutGet(GLUT_SCREEN_WIDTH); height = glutGet(GLUT_SCREEN_HEIGHT); // create a framebuffer object glGenFramebuffers(1, &frame_buffer_name); // GL_FRAMEBUFFER target simply sets both the read and the write to // the same FBO. glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer_name); if(!glIsFramebuffer(frame_buffer_name)) { program_error(__FILE__, __LINE__, __FUNC__, "glIsFramebuffer failed (frame_buffer_name=%d)", frame_buffer_name); } // create a renderbuffer object to store the image glGenRenderbuffers(1, &render_buffer_name); glBindRenderbuffer(GL_RENDERBUFFER, render_buffer_name); if(!glIsRenderbuffer(render_buffer_name)) { program_error(__FILE__, __LINE__, __FUNC__, "glIsRenderbuffer failed (render_buffer_name=%d)", render_buffer_name); } // We are guaranteed to be able to have at least color attachment 0 // attach the renderbuffer to GL_COLOR_ATTACHMENT0 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, render_buffer_name); glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, width, height); check_framebuffer_completeness_status(__FILE__, __LINE__, __FUNC__); OpenGL_error_check(__FILE__, __LINE__, __FUNC__); set_OpenGL_viewport(width, height); glReadBuffer(GL_COLOR_ATTACHMENT0); glDrawBuffer(GL_COLOR_ATTACHMENT0); glEnable(GL_BLEND); // enable blending glEnable(GL_TEXTURE_2D); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glClearColor(1.0, 1.0, 1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); program_information ( __FILE__, __LINE__, __FUNC__, "FBO rendering to %dpx X %dpx buffer", width, height ); OpenGL_error_check(__FILE__, __LINE__, __FUNC__); } /*------------------------------------------------------------------------------ glBlitFramebuffer transfers a rectangle of pixel values from one region of the read framebuffer to another region in the draw framebuffer. mask is the bitwise OR of a number of values indicating which buffers are to be copied. The values are GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, and GL_STENCIL_BUFFER_BIT. The pixels corresponding to these buffers are copied from the source rectangle bounded by the locations (srcX0; srcY0) and (srcX1; srcY1) to the destination rectangle bounded by the locations (dstX0; dstY0) and (dstX1; dstY1). The lower bounds of the rectangle are inclusive, while the upper bounds are exclusive. Create and FBO: set the draw framebuffer to be the FBO glDrawBuffer(GL_COLOR_ATTACHMENT0); set the read framebuffer to be the FBO glReadBuffer(GL_COLOR_ATTACHMENT0); render the paint strokes to the FBO pixel reads will come from the FBO The name comes from BLIT, which is not an acronym A typical use for a blitter is the movement of a bitmap glDebugMessageCallback requires OpenGL 4.3 ------------------------------------------------------------------------------*/ void blit_fbo_to_front_buffer(void) { GLint frame_buffer_name; GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); glGetIntegerv(GL_FRAMEBUFFER_BINDING, &frame_buffer_name); // change draw framebuffer to be the front buffer glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glDrawBuffer(GL_FRONT); //OpenGL_error_check(__FILE__, __LINE__, __FUNC__); glBlitFramebuffer // copy FBO data to the back buffer ( viewport[0], viewport[1], viewport[2] + viewport[0], viewport[3] + viewport[1], viewport[0], viewport[1], viewport[2] + viewport[0], viewport[3] + viewport[1], GL_COLOR_BUFFER_BIT, GL_NEAREST ); // restore draw framebuffer to be the FBO glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer_name); glDrawBuffer(GL_COLOR_ATTACHMENT0); } /*------------------------------------------------------------------------------ #define USE_INTEL_FBO ------------------------------------------------------------------------------*/ void select_rendering_mode_for_mesa_version(int argc, char **argv) { if(cpuid_without_stepping() == 0x1067) // U7300 { program_information(__FILE__, __LINE__, __FUNC__, "U7300 with GM45"); program_information(__FILE__, __LINE__, __FUNC__, "glutSwapBuffers GLUT_DOUBLE"); glutInit(&argc, argv); glutCreateWindow("FourteenthStreetStudio"); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); glDrawBuffer(GL_FRONT_AND_BACK); glutDisplayFunc(glutSwapBuffers); // set the glut callback } else if(strcasestr(get_opengl_version_string(), "11.2.0") != NULL) { program_information(__FILE__, __LINE__, __FUNC__, "Mesa 11.2.0 installed"); #ifdef USE_INTEL_FBO program_information(__FILE__, __LINE__, __FUNC__, "blit_fbo_to_front_buffer GLUT_SINGLE artefacts? = yes"); glutInit(&argc, argv); glutCreateWindow("FourteenthStreetStudio"); glutInitDisplayMode(GLUT_RGBA | GLUT_SINGLE); render_to_fbo(); glutDisplayFunc(blit_fbo_to_front_buffer); // set the glut callback #else program_information(__FILE__, __LINE__, __FUNC__, "glutSwapBuffers GLUT_DOUBLE"); glutInit(&argc, argv); glutCreateWindow("FourteenthStreetStudio"); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); glDrawBuffer(GL_FRONT_AND_BACK); glutDisplayFunc(glutSwapBuffers); // set the glut callback #endif } else if(strcasestr(get_opengl_version_string(), "11.1.0-devel") != NULL) { program_information(__FILE__, __LINE__, __FUNC__, "Mesa 11.1.0 installed"); #ifdef USE_INTEL_FBO program_information(__FILE__, __LINE__, __FUNC__, "blit_fbo_to_front_buffer GLUT_SINGLE artefacts?"); glutInit(&argc, argv); glutCreateWindow("FourteenthStreetStudio"); glutInitDisplayMode(GLUT_RGBA | GLUT_SINGLE); render_to_fbo(); glutDisplayFunc(blit_fbo_to_front_buffer); // set the glut callback #else program_information(__FILE__, __LINE__, __FUNC__, "glutSwapBuffers GLUT_DOUBLE"); glutInit(&argc, argv); glutCreateWindow("FourteenthStreetStudio"); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); glDrawBuffer(GL_FRONT_AND_BACK); glutDisplayFunc(glutSwapBuffers); // set the glut callback #endif } else if(strcasestr(get_opengl_version_string(), "10.6.3") != NULL) { program_information(__FILE__, __LINE__, __FUNC__, "Mesa 10.6.3 installed"); program_information(__FILE__, __LINE__, __FUNC__, "glutSwapBuffers GLUT_DOUBLE"); glutInit(&argc, argv); glutCreateWindow("FourteenthStreetStudio"); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); glutDisplayFunc(glutSwapBuffers); // set the glut callback glDrawBuffer(GL_FRONT_AND_BACK); } else if(strcasestr(get_opengl_version_string(), "10.1.0") != NULL) { program_information(__FILE__, __LINE__, __FUNC__, "Mesa 10.1.0 installed"); program_information(__FILE__, __LINE__, __FUNC__, "glutSwapBuffers GLUT_SINGLE"); glutInit(&argc, argv); glutCreateWindow("FourteenthStreetStudio"); glutInitDisplayMode(GLUT_RGBA | GLUT_SINGLE); glutDisplayFunc(glutSwapBuffers); // set the glut callback glDrawBuffer(GL_FRONT); } else { program_warning(__FILE__, __LINE__, __FUNC__, "Did NOT find a known Mesa driver installation %s", get_opengl_version_string()); #ifdef USE_INTEL_FBO program_information(__FILE__, __LINE__, __FUNC__, "blit_fbo_to_front_buffer GLUT_SINGLE"); glutInit(&argc, argv); glutCreateWindow("FourteenthStreetStudio"); glutInitDisplayMode(GLUT_RGBA | GLUT_SINGLE); render_to_fbo(); glutDisplayFunc(blit_fbo_to_front_buffer); // set the glut callback #else program_information(__FILE__, __LINE__, __FUNC__, "glutSwapBuffers GLUT_DOUBLE"); glutInit(&argc, argv); glutCreateWindow("FourteenthStreetStudio"); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); glDrawBuffer(GL_FRONT_AND_BACK); glutDisplayFunc(glutSwapBuffers); // set the glut callback #endif } } /*------------------------------------------------------------------------------ This will set the rendering mode based on the platform's GPU and driver Rendering is either done via swapbuffers() or by render_to_fbo() ------------------------------------------------------------------------------*/ void set_OpenGL_rendering_mode(int argc, char **argv) { if(strcasestr(get_opengl_version_string(), "Mesa") != NULL) { program_information(__FILE__, __LINE__, __FUNC__, "using Mesa driver"); select_rendering_mode_for_mesa_version(argc, argv); } else { program_information(__FILE__, __LINE__, __FUNC__, "using non-Mesa driver"); glutInit(&argc, argv); glutCreateWindow("FourteenthStreetStudio"); // any configuration with an Nvida GPU glutInitDisplayMode(GLUT_RGBA | GLUT_SINGLE); render_to_fbo(); glutDisplayFunc(blit_fbo_to_front_buffer); // set the glut callback } OpenGL_error_check(__FILE__, __LINE__, __FUNC__); }