/* * RB_BindFrameBufferObject */ void RB_BindFrameBufferObject( int object ) { int width, height; RFB_BindObject( object ); RFB_CheckObjectStatus(); RFB_GetObjectSize( object, &width, &height ); if( rb.gl.fbHeight != height ) rb.gl.scissorChanged = true; rb.gl.fbWidth = width; rb.gl.fbHeight = height; }
/* * RFB_RegisterObject */ int RFB_RegisterObject( int width, int height, bool builtin, bool depthRB, bool stencilRB, bool colorRB, int samples, bool useFloat, bool sRGB ) { int i; int format; GLuint fbID; GLuint rbID = 0; r_fbo_t *fbo = NULL; if( !r_frambuffer_objects_initialized ) { return 0; } #ifdef GL_ES_VERSION_2_0 if( samples ) { return 0; } #else if( samples && !glConfig.ext.framebuffer_multisample ) { return 0; } #endif for( i = 0, fbo = r_framebuffer_objects; i < r_num_framebuffer_objects; i++, fbo++ ) { if( !fbo->objectID ) { // free slot goto found; } } if( i == MAX_FRAMEBUFFER_OBJECTS ) { Com_Printf( S_COLOR_YELLOW "RFB_RegisterObject: framebuffer objects limit exceeded\n" ); return 0; } clamp_high( samples, glConfig.maxFramebufferSamples ); i = r_num_framebuffer_objects++; fbo = r_framebuffer_objects + i; found: qglGenFramebuffersEXT( 1, &fbID ); memset( fbo, 0, sizeof( *fbo ) ); fbo->objectID = fbID; if( builtin ) { fbo->registrationSequence = -1; } else { fbo->registrationSequence = rsh.registrationSequence; } fbo->width = width; fbo->height = height; fbo->samples = samples; fbo->sRGB = sRGB; qglBindFramebufferEXT( GL_FRAMEBUFFER_EXT, fbo->objectID ); if( colorRB ) { format = glConfig.forceRGBAFramebuffers ? GL_RGBA : GL_RGB; if( useFloat ) { format = glConfig.forceRGBAFramebuffers ? GL_RGBA16F_ARB : GL_RGB16F_ARB; } qglGenRenderbuffersEXT( 1, &rbID ); fbo->colorRenderBuffer = rbID; qglBindRenderbufferEXT( GL_RENDERBUFFER_EXT, rbID ); #ifndef GL_ES_VERSION_2_0 if( samples ) { qglRenderbufferStorageMultisampleEXT( GL_RENDERBUFFER_EXT, samples, format, width, height ); } else #endif qglRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, format, width, height ); } #ifndef GL_ES_VERSION_2_0 else { // until a color texture is attached, don't enable drawing to the buffer qglDrawBuffer( GL_NONE ); qglReadBuffer( GL_NONE ); } #endif if( depthRB ) { qglGenRenderbuffersEXT( 1, &rbID ); fbo->depthRenderBuffer = rbID; qglBindRenderbufferEXT( GL_RENDERBUFFER_EXT, rbID ); if( stencilRB ) { format = GL_DEPTH24_STENCIL8_EXT; } else if( glConfig.ext.depth24 ) { format = GL_DEPTH_COMPONENT24; } else if( glConfig.ext.depth_nonlinear ) { format = GL_DEPTH_COMPONENT16_NONLINEAR_NV; } else { format = GL_DEPTH_COMPONENT16; } #ifndef GL_ES_VERSION_2_0 if( samples ) { qglRenderbufferStorageMultisampleEXT( GL_RENDERBUFFER_EXT, samples, format, width, height ); } else #endif qglRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, format, width, height ); if( stencilRB ) { fbo->stencilRenderBuffer = rbID; } } if( rbID ) { qglBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 ); } if( fbo->colorRenderBuffer ) { qglFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, fbo->colorRenderBuffer ); } if( fbo->depthRenderBuffer ) { qglFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->depthRenderBuffer ); } if( fbo->stencilRenderBuffer ) { qglFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->stencilRenderBuffer ); } if( colorRB && depthRB ) { if( !RFB_CheckObjectStatus() ) { goto fail; } } if( r_bound_framebuffer_objectID ) { qglBindFramebufferEXT( GL_FRAMEBUFFER_EXT, r_bound_framebuffer_object->objectID ); } else { qglBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); } return i + 1; fail: RFB_DeleteObject( fbo ); qglBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); return 0; }
/* * RFB_AttachTextureToObject */ bool RFB_AttachTextureToObject( int object, bool depth, int target, image_t *texture ) { r_fbo_t *fbo; int attachment; GLuint texnum = 0; assert( object > 0 && object <= r_num_framebuffer_objects ); if( object <= 0 || object > r_num_framebuffer_objects ) { return false; } if( target < 0 || target >= MAX_FRAMEBUFFER_COLOR_ATTACHMENTS ) { return false; } if( target > 0 && !glConfig.ext.draw_buffers ) { return false; } fbo = r_framebuffer_objects + object - 1; qglBindFramebufferEXT( GL_FRAMEBUFFER_EXT, fbo->objectID ); bind: if( depth ) { attachment = GL_DEPTH_ATTACHMENT_EXT; if( texture ) { assert( texture->flags & IT_DEPTH ); texnum = texture->texnum; texture->fbo = object; } } else { #ifndef GL_ES_VERSION_2_0 const GLenum fboBuffers[8] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_COLOR_ATTACHMENT2_EXT, GL_COLOR_ATTACHMENT3_EXT, GL_COLOR_ATTACHMENT4_EXT, GL_COLOR_ATTACHMENT5_EXT, GL_COLOR_ATTACHMENT6_EXT, GL_COLOR_ATTACHMENT7_EXT, }; #endif attachment = GL_COLOR_ATTACHMENT0_EXT + target; #ifndef GL_ES_VERSION_2_0 if( target > 0 && texture ) { qglDrawBuffersARB( target + 1, fboBuffers ); } else { if( glConfig.ext.draw_buffers ) { qglDrawBuffersARB( 0, fboBuffers ); } qglDrawBuffer( GL_COLOR_ATTACHMENT0_EXT ); qglReadBuffer( GL_COLOR_ATTACHMENT0_EXT ); } #endif if( texture ) { assert( !( texture->flags & IT_DEPTH ) ); texnum = texture->texnum; texture->fbo = object; } } // attach texture qglFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, attachment, GL_TEXTURE_2D, texnum, 0 ); if( texture ) { if( ( texture->flags & ( IT_DEPTH | IT_STENCIL ) ) == ( IT_DEPTH | IT_STENCIL ) ) { qglFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, texnum, 0 ); } } else { if( depth ) { qglFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, texnum, 0 ); } } qglBindFramebufferEXT( GL_FRAMEBUFFER_EXT, r_bound_framebuffer_objectID ? r_bound_framebuffer_object->objectID : 0 ); // check framebuffer status and unbind if failed if( !RFB_CheckObjectStatus() ) { if( texture ) { texture = NULL; goto bind; } return false; } if( depth ) { fbo->depthTexture = texture; } else { fbo->colorTexture[target] = texture; } return true; }