private void _initialize()
{
// Release depth and stencil, if they were bound
_manager.ReleaseRenderBuffer( _depth );
_manager.ReleaseRenderBuffer( _stencil );
/// First buffer must be bound
if ( _color[ 0 ].Buffer == null )
{
throw new ArgumentException( "Attachment 0 must have surface attached." );
}
/// Bind FBO to frame buffer
Bind();
/// Store basic stats
int width = _color[ 0 ].Buffer.Width;
int height = _color[ 0 ].Buffer.Height;
int glFormat = _color[ 0 ].Buffer.GLFormat;
PixelFormat format = _color[ 0 ].Buffer.Format;
/// Bind all attachment points to frame buffer
for ( int x = 0; x < Config.MaxMultipleRenderTargets; ++x )
{
if ( _color[ x ].Buffer != null )
{
if ( _color[ x ].Buffer.Width != width || _color[ x ].Buffer.Height != height )
{
throw new ArgumentException( String.Format( "Attachment {0} has incompatible size {1}x{2}. It must be of the same as the size of surface 0, {3}x{4}.", x, _color[ x ].Buffer.Width, _color[ x ].Buffer.Height, width, height ) );
}
if ( _color[ x ].Buffer.GLFormat != glFormat )
{
throw new ArgumentException( String.Format( "Attachment {0} has incompatible format.", x ) );
}
_color[ x ].Buffer.BindToFramebuffer( Gl.GL_COLOR_ATTACHMENT0_EXT + x, _color[ x ].ZOffset );
}
else
{
// Detach
Gl.glFramebufferRenderbufferEXT( Gl.GL_FRAMEBUFFER_EXT, Gl.GL_COLOR_ATTACHMENT0_EXT + x, Gl.GL_RENDERBUFFER_EXT, 0 );
}
}
/// Find suitable depth and stencil format that is compatible with colour format
int depthFormat, stencilFormat;
_manager.GetBestDepthStencil( format, out depthFormat, out stencilFormat );
/// Request surfaces
_depth = _manager.RequestRenderBuffer( depthFormat, width, height );
if ( depthFormat == GLFBORTTManager.GL_DEPTH24_STENCIL8_EXT )
{
// bind same buffer to depth and stencil attachments
_manager.RequestRenderBuffer( _depth );
_stencil = _depth;
}
else
{
// separate stencil
_stencil = _manager.RequestRenderBuffer( stencilFormat, width, height );
}
/// Attach/detach surfaces
if ( _depth.Buffer != null )
{
_depth.Buffer.BindToFramebuffer( Gl.GL_DEPTH_ATTACHMENT_EXT, _depth.ZOffset );
}
else
{
Gl.glFramebufferRenderbufferEXT( Gl.GL_FRAMEBUFFER_EXT, Gl.GL_DEPTH_ATTACHMENT_EXT, Gl.GL_RENDERBUFFER_EXT, 0 );
}
if ( _stencil.Buffer != null )
{
_stencil.Buffer.BindToFramebuffer( Gl.GL_STENCIL_ATTACHMENT_EXT, _stencil.ZOffset );
}
else
{
Gl.glFramebufferRenderbufferEXT( Gl.GL_FRAMEBUFFER_EXT, Gl.GL_STENCIL_ATTACHMENT_EXT, Gl.GL_RENDERBUFFER_EXT, 0 );
}
/// Do glDrawBuffer calls
int[] bufs = new int[ Config.MaxMultipleRenderTargets ];
int n = 0;
for ( int x = 0; x < Config.MaxMultipleRenderTargets; ++x )
{
// Fill attached colour buffers
if ( _color[ x ].Buffer != null )
{
bufs[ x ] = Gl.GL_COLOR_ATTACHMENT0_EXT + x;
// Keep highest used buffer + 1
n = x + 1;
}
else
{
bufs[ x ] = Gl.GL_NONE;
}
}
if ( _manager.GLSupport.CheckExtension( "GL_ARB_draw_buffers" ) )
{
/// Drawbuffer extension supported, use it
Gl.glDrawBuffers( n, bufs );
}
else if ( _manager.GLSupport.CheckExtension( "GL_ATI_draw_buffers" ) )
{
Gl.glDrawBuffersATI( n, bufs );
}
else
{
/// In this case, the capabilities will not show more than 1 simultaneaous render target.
Gl.glDrawBuffer( bufs[ 0 ] );
}
/// No read buffer, by default, if we want to read anyway we must not forget to set this.
Gl.glReadBuffer( Gl.GL_NONE );
/// Check status
int status;
status = Gl.glCheckFramebufferStatusEXT( Gl.GL_FRAMEBUFFER_EXT );
/// Bind main buffer
Gl.glBindFramebufferEXT( Gl.GL_FRAMEBUFFER_EXT, 0 );
switch ( status )
{
case Gl.GL_FRAMEBUFFER_COMPLETE_EXT:
// All is good
break;
case Gl.GL_FRAMEBUFFER_UNSUPPORTED_EXT:
throw new ArgumentException( "All framebuffer formats with this texture internal format unsupported" );
default:
throw new ArgumentException( "Framebuffer incomplete or other FBO status error" );
}
}