/*
								+---------------------------------+
								|                                 |
								| *** GL 2.0 offscreen render *** |
								|                                 |
								|  Copyright  © -tHE SWINe- 2006  |
								|                                 |
								|        RenderBuffer2.cpp        |
								|                                 |
								+---------------------------------+
*/

/**
 *	@file gl2/RenderBuffer2.cpp
 *	@date 2006
 *	@author -tHE SWINe-
 *	@brief OpenGL 2.0 offscreen render
 *
 *	@date 2006-10-05
 *
 *	passed code revision
 *
 *	integers, containing just true and false were replaced with bool
 *	fixed some design issues to enable binding depth and stencil output texture along with
 *	color texture
 *	WGL_ARB_pixel_buffer support was deprecated
 *	files were renamed to RenderBuffer2.cpp and RenderBuffer2.h respectively
 *
 *	@date 2007-03-06
 *
 *	removed __declspec(dllexport)
 *
 *	@date 2007-08-07
 *
 *	added couple of functions to access render buffer properties (namely
 *	CGLRenderBuffer::n_Draw_Buffer_Num(), CGLRenderBuffer::n_Color_Format(),
 *	CGLRenderBuffer::b_Depth_Buffer(), CGLRenderBuffer::n_Depth_Format(),
 *	CGLRenderBuffer::b_Stencil_Buffer(), CGLRenderBuffer::n_Stencil_Format(),
 *	CGLRenderBuffer::b_Color_TextureTarget(), CGLRenderBuffer::b_Depth_TextureTarget(),
 *	CGLRenderBuffer::b_Stencil_TextureTarget())
 *
 *	@date 2007-08-07
 *
 *	when using automatic texture un-binding in CGLFrameBuffer_FBO::CopyTextureData()
 *	it was assumed all textures are GL_TEXTURE_2D. now proper texture target is
 *	stored in memory (when using another targets such as GL_TEXTURE_RECTANGLE)
 *	and most of all, 3D textures are now correctly un-bound.
 *	note today's nvidia drivers do not support direct rendering to 3D texture so it has
 *	to be done manually (glFramebufferTexture3DEXT causes GL_FRAMEBUFFER_UNSUPPORTED_EXT)
 *
 *	@date 2007-08-14
 *
 *	added CGLRenderBuffer::n_Draw_Buffer() to get names of draw buffers in case it's
 *	necessary to read data from them (so it's possible to change read / draw buffers)
 *
 *	fixed error which didn't restore original draw buffer configuration in case FBO
 *	with zero color buffers was bound (is it possible to create such a FBO at all?)
 *
 *	fixed error which bound auxiliary buffers instead of color attachment buffers
 *	in case multiple render buffers were specified
 *
 *	n_Max_DrawBuffer_Num() was decalred virtual (was static before) because number
 *	of draw buffers / color attachments might change when different FBO's are bound
 *
 *	@date 2007-11-10
 *
 *	improved linux compatibility
 *
 *	@date 2007-11-12
 *
 *	reformat (added line breaks where lines were longer than 100 characters)
 *
 *	@date 2008-03-03
 *
 *	removed glGetError() calls from CGLFrameBuffer_FBO bind functions
 *	to improve performance
 *
 *	@date 2008-03-04
 *
 *	renamed CGLRenderBuffer to CGLFrameBuffer and CGLRenderBuffer_FBO to CGLFrameBuffer_FBO
 *	since ÜberLame OpenGL state guard is aimed for single context only, it's unlikely
 *	PBuffer framebuffer class would be implemented, therefore virtual modifier on
 *	CGLFrameBuffer_FBO member functions is useless and can be removed by defining
 *	__RENDER_BUFFER2_DISABLE_VIRTUAL
 *
 *	@date 2008-03-18
 *
 *	added clarifying comment not to use CGLFrameBuffer_Base
 *
 *	@date 2008-05-07
 *
 *	fixed some typos in documentation comments
 *	fixed GL error with multiple draw buffers (occured when restoring original
 *	draw buffers in CGLRenderBuffer_FBO::Release())
 *
 *	@date 2008-08-08
 *
 *	added \#ifdef for windows 64
 *
 *	@date 2009-05-03
 *
 *	added the following overloads for texture bind functions without target parameter:
 *	CGLFrameBuffer::BindDepthTexture_2D() and CGLFrameBuffer::BindStencilTexture_2D()
 *	(bind target is the same as texture target; this works for GL_TEXTURE_2D
 *	and GL_TEXTURE_RECTANGLE, it doesn't work for GL_TEXTURE_CUBE_MAP which
 *	needs one of cube face targets GL_TEXTURE_CUBE_MAP_POSITIVE_X, etc.
 *	also note overloading BindColorTexture_2D() in this way would cause aliasing)
 *
 *	added CGLFrameBuffer_FBO::n_Max_Size() and CGLFrameBuffer_FBO::n_Status()
 *
 *	@date 2009-05-04
 *
 *	fixed mixed windows / linux line endings
 *
 */

#include "../NewFix.h"

#include "../CallStack.h"
#include <vector>
#include "OpenGL20.h"
#include "OpenGLState.h"
#include "Texture.h"
#include "RenderBuffer2.h"

/*
 *								=== CGLFrameBuffer_Base ===
 */

CGLFrameBuffer_Base::CGLFrameBuffer_Base(int n_width, int n_height,
	int n_color_buffer_num, bool b_color_texture_target, GLenum n_color_internal_format,
	bool b_depth_buffer, bool b_depth_texture_target, GLenum n_depth_internal_format,
	bool b_stencil_buffer, bool b_stencil_texture_target, GLenum n_stencil_internal_format)
	:m_p_state(0), m_n_width(n_width), m_n_height(n_height),
	m_n_draw_buffer_num(n_color_buffer_num), m_n_color_internal_format(n_color_internal_format),
	m_b_depth_buffer(b_depth_buffer), m_n_depth_internal_format(n_depth_internal_format),
	m_b_stencil_buffer(b_stencil_buffer), m_n_stencil_internal_format(n_stencil_internal_format),
	m_b_color_texture_target(b_color_texture_target),
	m_b_depth_texture_target(b_depth_texture_target),
	m_b_stencil_texture_target(b_stencil_texture_target),
	m_n_bound_color_texture_num(0), m_n_bound_depth_texture(0), m_n_bound_stencil_texture(0),
	m_b_status(false), m_b_active(false)
{
	__FuncGuard("CGLFrameBuffer_Base::CGLFrameBuffer_Base");

	memset(m_p_bound_color_texture, 0, sizeof(m_p_bound_color_texture));
}

CGLFrameBuffer_Base::CGLFrameBuffer_Base(int n_width, int n_height, int n_color_buffer_num,
	bool b_color_texture_target, GLenum n_color_format, int n_color_bit_num, bool b_float_color,
	bool b_depth_buffer, bool b_depth_texture_target, int n_depth_bit_num,
	bool b_stencil_buffer, bool b_stencil_texture_target, int n_stencil_bit_num)
	:m_p_state(0),
	m_n_width(n_width), m_n_height(n_height),
	m_n_draw_buffer_num(n_color_buffer_num),
	m_b_depth_buffer(b_depth_buffer),
	m_b_stencil_buffer(b_stencil_buffer),
	m_b_color_texture_target(b_color_texture_target),
	m_b_depth_texture_target(b_depth_texture_target),
	m_b_stencil_texture_target(b_stencil_texture_target),
	m_n_bound_color_texture_num(0), m_n_bound_depth_texture(0), m_n_bound_stencil_texture(0),
	m_b_status(false), m_b_active(false)
{
	__FuncGuard("CGLFrameBuffer_Base::CGLFrameBuffer_Base");

	if(b_depth_buffer) {
		switch(n_depth_bit_num) {
		case 16:
			m_n_depth_internal_format = GL_DEPTH_COMPONENT16;
			break;
		case 24:
			m_n_depth_internal_format = GL_DEPTH_COMPONENT24;
			break;
		case 32:
			m_n_depth_internal_format = GL_DEPTH_COMPONENT32;
			break;
		default:
			m_n_depth_internal_format = 0;
			m_b_status = false;
			return;
		}
	}
	// find depth component format

	if(b_stencil_buffer) {
		switch(n_stencil_bit_num) {
		case 1:
			m_n_depth_internal_format = GL_STENCIL_INDEX1_EXT;
			break;
		case 4:
			m_n_depth_internal_format = GL_STENCIL_INDEX4_EXT;
			break;
		case 8:
			m_n_depth_internal_format = GL_STENCIL_INDEX8_EXT;
			break;
		case 16:
			m_n_depth_internal_format = GL_STENCIL_INDEX16_EXT;
			break;
		default:
			m_n_depth_internal_format = 0;
			m_b_status = false;
			return;
		}
	}
	// find stencil component format

	if(n_color_buffer_num) {
		if(!(m_n_color_internal_format = n_InternalColorFormat(n_color_format,
		   n_color_bit_num, b_float_color))) {
			m_b_status = false;
			return;
		}
	}
	// find color component format

	memset(m_p_bound_color_texture, 0, sizeof(m_p_bound_color_texture));
}

/*
 *	static bool CGLFrameBuffer_Base::b_Supported()
 *		- returns true in case the render buffer class have necessary hardware support
 */
bool CGLFrameBuffer_Base::b_Supported()
{
	__FuncGuard("CGLFrameBuffer_Base::b_Supported");

	return false; // this is virtual class only
}

/*
 *	static GLenum CGLFrameBuffer_Base::n_InternalColorFormat(GLenum n_color_format,
 *		int n_bit_num, bool b_float)
 *		- n_color_format is one of GL_ALPHA, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_INTENSITY,
 *		  GL_RGB or GL_RGBA
 *		- n_bit_num can be 4, 8 or 16 for integer and 16 or 32 for float representation
 *		- in case b_float is true, float representation will be used. otherwise integer
 *		  representation will be used
 *		- returns OpenGL internal color format (or 0 in case no specified format exists)
 */
GLenum CGLFrameBuffer_Base::n_InternalColorFormat(GLenum n_color_format,
	int n_bit_num, bool b_float)
{
	__FuncGuard("CGLFrameBuffer_Base::n_InternalColorFormat");

	const GLenum p_format_array[][4] = {
		{GL_ALPHA4, GL_ALPHA8, GL_ALPHA16, 0},
		{GL_LUMINANCE4, GL_LUMINANCE8, GL_LUMINANCE16, 0},
		{GL_LUMINANCE4_ALPHA4, GL_LUMINANCE8_ALPHA8, GL_LUMINANCE16_ALPHA16, 0},
		{GL_INTENSITY4, GL_INTENSITY8, GL_INTENSITY16, 0},
		{GL_RGB4, GL_RGB8, GL_RGB16, 0},
		{GL_RGBA4, GL_RGBA8, GL_RGBA16, 0},
	};
	const GLenum p_float_format_array[][4] = {
		{0, 0, GL_ALPHA16F_ARB, GL_ALPHA32F_ARB},
		{0, 0, GL_LUMINANCE16F_ARB, GL_LUMINANCE32F_ARB},
		{0, 0, GL_LUMINANCE_ALPHA16F_ARB, GL_LUMINANCE_ALPHA32F_ARB},
		{0, 0, GL_INTENSITY16F_ARB, GL_INTENSITY32F_ARB},
		{0, 0, GL_RGB16F_ARB, GL_RGB32F_ARB},
		{0, 0, GL_RGBA16F_ARB, GL_RGBA32F_ARB},
	};

	int n_col_index;
	switch(n_bit_num) {
	case 4:
		n_col_index = 0;
		break;
	case 8:
		n_col_index = 1;
		break;
	case 16:
		n_col_index = 2;
		break;
	case 32:
		n_col_index = 3;
		break;
	default:
		return 0;
	}

	int n_row_index;
	switch(n_color_format) {
	case GL_ALPHA:
		n_row_index = 0;
		break;
	case GL_LUMINANCE:
		n_row_index = 1;
		break;
	case GL_LUMINANCE_ALPHA:
		n_row_index = 2;
		break;
	case GL_INTENSITY:
		n_row_index = 3;
		break;
	case GL_RGB:
		n_row_index = 4;
		break;
	case GL_RGBA:
		n_row_index = 5;
		break;
	default:
		return 0;
	}

	return ((b_float)? p_float_format_array : p_format_array)[n_row_index][n_col_index];
}

/*
 *								=== ~CGLFrameBuffer_Base ===
 */

/*
 *								=== CGLFrameBuffer ===
 */

#ifndef __RENDER_BUFFER2_DISABLE_VIRTUAL

/*
 *	CGLFrameBuffer(int n_width, int n_height,
 *		int n_color_buffer_num, bool b_color_texture_target, GLenum n_color_internal_format,
 *		bool b_depth_buffer, bool b_depth_texture_target, GLenum n_depth_internal_format,
 *		bool b_stencil_buffer, bool b_stencil_texture_target, GLenum n_stencil_internal_format)
 *		- constructor; creates the render buffer (OpenGL must be initialized)
 *		- n_width and n_height are dimensions of the output buffer
 *		- n_color_buffer_num is number of draw buffers (0 / 1 / 2 / 4 on geforce, 8 on quadro,
 *		  up to 16 in future; 0 means no color output is generated - depth map rendering)
 *		- b_color_texture_target enables binding color texture(s) as render target(s)
 *		  otherwise color is rendered into internal buffer (glReadPixels() / glCopyTexImage*())
 *		- n_color_internal_format is OpenGL internal texture format (such as GL_RGB8, ...)
 *		- b_depth_buffer enables depth output
 *		- b_depth_texture_target enables writing depth fragments into bound depth texture
 *		  (otherwise depth fragments are written into internal buffer)
 *		- n_depth_internal_format is depth buffer pixel format (one of GL_DEPTH_COMPONENT16,
 *		  GL_DEPTH_COMPONENT24 or GL_DEPTH_COMPONENT32)
 *		- b_stencil_buffer enables stencil output
 *		- b_stencil_texture_target enables writing stencil fragments into bound stencil texture
 *		  (otherwise stencil fragments are written into internal buffer)
 *		- n_stencil_internal_format is stencil buffer pixel format (one of
 *		  GL_STENCIL_INDEX1_EXT, GL_STENCIL_INDEX4_EXT, GL_STENCIL_INDEX8_EXT or
 *		  GL_STENCIL_INDEX16_EXT)
 */
CGLFrameBuffer::CGLFrameBuffer(int n_width, int n_height,
	int n_color_buffer_num, bool b_color_texture_target, GLenum n_color_internal_format,
	bool b_depth_buffer, bool b_depth_texture_target, GLenum n_depth_internal_format,
	bool b_stencil_buffer, bool b_stencil_texture_target, GLenum n_stencil_internal_format)
	:CGLFrameBuffer_Base(n_width, n_height, n_color_buffer_num, b_color_texture_target,
	n_color_internal_format, b_depth_buffer, b_depth_texture_target, n_depth_internal_format,
	b_stencil_buffer, b_stencil_texture_target, n_stencil_internal_format)
{
	__FuncGuard("CGLFrameBuffer::CGLFrameBuffer");
}

/*
 *	CGLFrameBuffer(int n_width, int n_height,
 *		int n_color_buffer_num, bool b_color_texture_target, GLenum n_color_format,
 *		int n_color_bit_num, bool b_float_color,
 *		bool b_depth_buffer, bool b_depth_texture_target, int n_depth_bit_num,
 *		bool b_stencil_buffer, bool b_stencil_texture_target, int n_stencil_bit_num)
 *		- constructor; creates the render buffer (OpenGL must be initialized)
 *		- n_width and n_height are dimensions of the output buffer
 *		- n_color_buffer_num is number of draw buffers (0 / 1 / 2 / 4 on geforce, 8 on quadro,
 *		  up to 16 in future; 0 means no color output is generated - depth map rendering)
 *		- b_color_texture_target enables binding color texture(s) as render target(s)
 *		  otherwise color is rendered into internal buffer (glReadPixels() / glCopyTexImage*())
 *		- n_color_format is OpenGL texture format (one of GL_RGB, GL_RGBA, GL_INTENSITY,
 *		  GL_LUMINANCE, GL_ALPHA, GL_LUMINANCE_ALPHA)
 *		- n_color_bit_num is color bit depth (4, 8 or 16 for integer, 16 or 32 for float formats)
 *		- b_float_color decides between integer (false) or float (true) formats
 *		- b_depth_buffer enables depth output
 *		- b_depth_texture_target enables writing depth fragments into bound depth texture
 *		  (otherwise depth fragments are written into internal buffer)
 *		- n_depth_bit_num is depth buffer pixel width (16, 24 or 32)
 *		- b_stencil_buffer enables stencil output
 *		- b_stencil_texture_target enables writing stencil fragments into bound stencil texture
 *		  (otherwise stencil fragments are written into internal buffer)
 *		- n_stencil_bit_num is stencil buffer pixel width (1, 4, 8 or 16)
 */
CGLFrameBuffer::CGLFrameBuffer(int n_width, int n_height,
	int n_color_buffer_num, bool b_color_texture_target, GLenum n_color_format,
	int n_color_bit_num, bool b_float_color,
	bool b_depth_buffer, bool b_depth_texture_target, int n_depth_bit_num,
	bool b_stencil_buffer, bool b_stencil_texture_target, int n_stencil_bit_num)
	:CGLFrameBuffer_Base(n_width, n_height, n_color_buffer_num, b_color_texture_target,
	n_color_format, n_color_bit_num, b_float_color, b_depth_buffer,
	b_depth_texture_target, n_depth_bit_num, b_stencil_buffer, b_stencil_texture_target,
	n_stencil_bit_num)
{
	__FuncGuard("CGLFrameBuffer::CGLFrameBuffer");
}

#endif // __RENDER_BUFFER2_DISABLE_VIRTUAL

/*
 *								=== ~CGLFrameBuffer ===
 */

/*
 *								=== CGLFrameBuffer_FBO ===
 */

/*
 *	CGLFrameBuffer_FBO(int n_width, int n_height,
 *		int n_color_buffer_num, bool b_color_texture_target, GLenum n_color_internal_format,
 *		bool b_depth_buffer, bool b_depth_texture_target, GLenum n_depth_internal_format,
 *		bool b_stencil_buffer, bool b_stencil_texture_target, GLenum n_stencil_internal_format)
 *		- constructor; creates the render buffer (OpenGL must be initialized)
 *		- n_width and n_height are dimensions of the output buffer
 *		- n_color_buffer_num is number of draw buffers (0 / 1 / 2 / 4 on geforce, 8 on quadro,
 *		  up to 16 in future; 0 means no color output is generated - depth map rendering)
 *		- b_color_texture_target enables binding color texture(s) as render target(s)
 *		  otherwise color is rendered into internal buffer (glReadPixels() / glCopyTexImage*())
 *		- n_color_internal_format is OpenGL internal texture format (such as GL_RGB8, ...)
 *		- b_depth_buffer enables depth output
 *		- b_depth_texture_target enables writing depth fragments into bound depth texture
 *		  (otherwise depth fragments are written into internal buffer)
 *		- n_depth_internal_format is depth buffer pixel format (one of GL_DEPTH_COMPONENT16,
 *		  GL_DEPTH_COMPONENT24 or GL_DEPTH_COMPONENT32)
 *		- b_stencil_buffer enables stencil output
 *		- b_stencil_texture_target enables writing stencil fragments into bound stencil texture
 *		  (otherwise stencil fragments are written into internal buffer)
 *		- n_stencil_internal_format is stencil buffer pixel format (one of
 *		  GL_STENCIL_INDEX1_EXT, GL_STENCIL_INDEX4_EXT, GL_STENCIL_INDEX8_EXT or
 *		  GL_STENCIL_INDEX16_EXT)
 */
CGLFrameBuffer_FBO::CGLFrameBuffer_FBO(int n_width, int n_height,
	int n_color_buffer_num, bool b_color_texture_target, GLenum n_color_internal_format,
	bool b_depth_buffer, bool b_depth_texture_target, GLenum n_depth_internal_format,
	bool b_stencil_buffer, bool b_stencil_texture_target, GLenum n_stencil_internal_format)
	:CGLFrameBuffer_Root(n_width, n_height, n_color_buffer_num, b_color_texture_target,
	n_color_internal_format, b_depth_buffer, b_depth_texture_target, n_depth_internal_format,
	b_stencil_buffer, b_stencil_texture_target, n_stencil_internal_format)
{
	__FuncGuard("CGLFrameBuffer_FBO::CGLFrameBuffer_FBO");

	m_b_status = Create();
}

/*
 *	CGLFrameBuffer_FBO(int n_width, int n_height,
 *		int n_color_buffer_num, bool b_color_texture_target, GLenum n_color_format,
 *		int n_color_bit_num, bool b_float_color,
 *		bool b_depth_buffer, bool b_depth_texture_target, int n_depth_bit_num,
 *		bool b_stencil_buffer, bool b_stencil_texture_target, int n_stencil_bit_num)
 *		- constructor; creates the render buffer (OpenGL must be initialized)
 *		- n_width and n_height are dimensions of the output buffer
 *		- n_color_buffer_num is number of draw buffers (0 / 1 / 2 / 4 on geforce, 8 on quadro,
 *		  up to 16 in future; 0 means no color output is generated - depth map rendering)
 *		- b_color_texture_target enables binding color texture(s) as render target(s)
 *		  otherwise color is rendered into internal buffer (glReadPixels() / glCopyTexImage*())
 *		- n_color_format is OpenGL texture format (one of GL_RGB, GL_RGBA, GL_INTENSITY,
 *		  GL_LUMINANCE, GL_ALPHA, GL_LUMINANCE_ALPHA)
 *		- n_color_bit_num is color bit depth (4, 8 or 16 for integer, 16 or 32 for float formats)
 *		- b_float_color decides between integer (false) or float (true) formats
 *		- b_depth_buffer enables depth output
 *		- b_depth_texture_target enables writing depth fragments into bound depth texture
 *		  (otherwise depth fragments are written into internal buffer)
 *		- n_depth_bit_num is depth buffer pixel width (16, 24 or 32)
 *		- b_stencil_buffer enables stencil output
 *		- b_stencil_texture_target enables writing stencil fragments into bound stencil texture
 *		  (otherwise stencil fragments are written into internal buffer)
 *		- n_stencil_bit_num is stencil buffer pixel width (1, 4, 8 or 16)
 */
CGLFrameBuffer_FBO::CGLFrameBuffer_FBO(int n_width, int n_height,
	int n_color_buffer_num, bool b_color_texture_target, GLenum n_color_format,
	int n_color_bit_num, bool b_float_color,
	bool b_depth_buffer, bool b_depth_texture_target, int n_depth_bit_num,
	bool b_stencil_buffer, bool b_stencil_texture_target, int n_stencil_bit_num)
	:CGLFrameBuffer_Root(n_width, n_height, n_color_buffer_num, b_color_texture_target,
	n_color_format, n_color_bit_num, b_float_color, b_depth_buffer,
	b_depth_texture_target, n_depth_bit_num, b_stencil_buffer, b_stencil_texture_target,
	n_stencil_bit_num)
{
	__FuncGuard("CGLFrameBuffer_FBO::CGLFrameBuffer_FBO");

	if((n_color_buffer_num && !m_n_color_internal_format) ||
	   (b_depth_buffer && !m_n_depth_internal_format) ||
	   (b_stencil_buffer && !m_n_stencil_internal_format))
	    m_b_status = false;
	else
		m_b_status = Create();
}

/*
 *	virtual CGLFrameBuffer_FBO::~CGLFrameBuffer_FBO()
 *		- destructor
 *		- takes care of cleaning up
 */
CGLFrameBuffer_FBO::~CGLFrameBuffer_FBO()
{
	__FuncGuard("CGLFrameBuffer_FBO::~CGLFrameBuffer_FBO");

	if(m_b_status) {
		if(m_n_draw_buffer_num && !m_b_color_texture_target)
			glDeleteRenderbuffersEXT(m_n_draw_buffer_num, m_p_color_rb);
		if(m_b_depth_buffer && !m_b_depth_texture_target)
			glDeleteRenderbuffersEXT(1, &m_n_depth_rb);
		if(m_b_stencil_buffer && !m_b_stencil_texture_target)
			glDeleteRenderbuffersEXT(1, &m_n_stencil_rb);
		glDeleteFramebuffersEXT(1, &m_n_framebuffer);

		m_b_status = false;
	}
	if(m_p_state)
		delete m_p_state;
}

/*
 *	static bool CGLFrameBuffer_FBO::b_Supported()
 *		- returns true in case the render buffer class have necessary hardware support
 */
bool CGLFrameBuffer_FBO::b_Supported()
{
	__FuncGuard("CGLFrameBuffer_FBO::b_Supported");

	return CGLExtensionHandler::b_SupportedExtension("GL_EXT_framebuffer_object") &&
		!CGLExtensionHandler::n_GetFramebufferObjectEXTFuncPointers();
}

/*
 *	static int CGLFrameBuffer_FBO::n_Max_Size()
 *		- returns maximal renderbuffer size in pixels,
 *		  note this won't work in case FBO's aren't supported (should return 0
 *		  and cause OpenGL error(s), but it is not guaranteed)
 */
int CGLFrameBuffer_FBO::n_Max_Size()
{
	__FuncGuard("CGLFrameBuffer_FBO::n_Max_Size");

	int n_max_size = 0; // in case GL_MAX_RENDERBUFFER_SIZE_EXT is unknown, OpenGL hopefully won't change this value
	glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &n_max_size);
	return n_max_size;
}

/*
 *	virtual int CGLFrameBuffer_FBO::n_Max_DrawBuffer_Num()
 *		- returns maximal number of OpenGL draw buffers (1 where not supported, otherwise
 *		  1, 2, 4, up to 16 in future)
 *		- note the value is cached so this is fast
 */
int CGLFrameBuffer_FBO::n_Max_DrawBuffer_Num()
{
	__FuncGuard("CGLFrameBuffer_FBO::n_Max_DrawBuffer_Num");

	return m_n_my_max_draw_buffer_num;
}

/*
 *	virtual bool CGLFrameBuffer_FBO::HandleModeSwitch()
 *		- see if the render-buffer was lost during display mode switch
 *		- returns true in case render-buffer is ok or false in case render buffer
 *		  was lost (creates a new buffer in latter case, the result can be obtained
 *		  by call to b_Status())
 */
bool CGLFrameBuffer_FBO::HandleModeSwitch()
{
	__FuncGuard("CGLFrameBuffer_FBO::HandleModeSwitch");

	return true;
}

/*
 *	bool CGLFrameBuffer_FBO::Create()
 *		- create new FBO, according to params, passed to constructor
 *		- return true in case of success, otherwise false
 */
bool CGLFrameBuffer_FBO::Create()
{
	__FuncGuard("CGLFrameBuffer_FBO::Create");

	if(!CGLFrameBuffer_FBO::b_Supported() || m_n_draw_buffer_num > 16)
		return false;
	// check for support (get function pointers same time)

	glGenFramebuffersEXT(1, &m_n_framebuffer);
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_n_framebuffer);
	if(glGetError() != GL_NO_ERROR)
		return false;
	// create a new framebuffer object

	if(m_n_draw_buffer_num && !m_b_color_texture_target) {
		glGenRenderbuffersEXT(m_n_draw_buffer_num, m_p_color_rb);
		for(int i = 0; i < m_n_draw_buffer_num; ++ i) {
			glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_p_color_rb[i]);
			glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, m_n_color_internal_format,
				m_n_width, m_n_height);
			glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
				GL_COLOR_ATTACHMENT0_EXT + i, GL_RENDERBUFFER_EXT, m_p_color_rb[i]);
		}
		if(glGetError() != GL_NO_ERROR)
			return false;
	}
	// create color buffer(s) (in case texture is not going to be bound only)

	if(m_b_depth_buffer && !m_b_depth_texture_target) {
		glGenRenderbuffersEXT(1, &m_n_depth_rb);
		glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_n_depth_rb);
		glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, m_n_depth_internal_format,
			m_n_width, m_n_height);
		glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
			GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_n_depth_rb);
		if(glGetError() != GL_NO_ERROR)
			return false;
	}
	// create depth buffer (in case depth texture is not going to be bound only)

	if(m_b_stencil_buffer && !m_b_stencil_texture_target) {
		glGenRenderbuffersEXT(1, &m_n_stencil_rb);
		glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_n_stencil_rb);
		glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, m_n_stencil_internal_format,
			m_n_width, m_n_height);
		glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
			GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_n_stencil_rb);
		if(glGetError() != GL_NO_ERROR)
			return false;
	}
	// create stencil buffer (in case stencil texture is not going to be bound only)

#ifdef GL_STATE_SINGLE_CONTEXT_ONLY
	if(!(m_p_state = new(std::nothrow) CGLState()))
		return false;
#else // GL_STATE_SINGLE_CONTEXT_ONLY
	if(!(m_p_state = new(std::nothrow) CGLState(wglGetCurrentDC(), wglGetCurrentContext())))
		return false;
#endif // GL_STATE_SINGLE_CONTEXT_ONLY
	// create state-tracking object

	glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &m_n_my_max_draw_buffer_num);
	int n_tmp;
	if(CGLExtensionHandler::b_SupportedExtension("GL_ARB_draw_buffers") ||
	   CGLExtensionHandler::b_Support_OpenGL(2, 0))
		glGetIntegerv(GL_MAX_DRAW_BUFFERS, &n_tmp);
	else
		n_tmp = 1;
	if(m_n_my_max_draw_buffer_num > n_tmp) // 6600 has 8 color attachments but only 4 draw buffers
		m_n_my_max_draw_buffer_num = n_tmp;
	_ASSERTE(m_n_my_max_draw_buffer_num <= 16);
	// get "my" maximal number of draw buffers (as it might depend on FBO format)

	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
	m_b_active = false;
	// it was necessary to bind framebuffer at the beginning, unbind it now

	if(m_n_draw_buffer_num > m_n_my_max_draw_buffer_num)
		return false;
	// can't bind as many draw buffers (but maybe can create as many color attachments)

	if(CGLExtensionHandler::b_SupportedExtension("GL_ARB_draw_buffers") ||
	   CGLExtensionHandler::b_Support_OpenGL(2, 0))
		glGetIntegerv(GL_MAX_DRAW_BUFFERS, &m_n_max_draw_buffer_num);
	else
		m_n_max_draw_buffer_num = 1;
	_ASSERTE(m_n_max_draw_buffer_num <= 16);
	// determine number of draw buffers (must be done while render-buffer is NOT bound,
	// OpenGL may limit max draw buffers for some formats / configurations such as
	// multisample buffers so the draw-buffers state would not be saved or restored
	// completely when buffer is being bound or released respectively)

	return true;
}

/*
 *	virtual GLenum CGLFrameBuffer_FBO::n_Draw_Buffer(int n_index) const
 *		- returns OpenGL name of color buffer with zero based index n_index
 *		- useful for manual copying of results of rendering to multiple buffers
 */
GLenum CGLFrameBuffer_FBO::n_Draw_Buffer(int n_index) const
{
	__FuncGuard("CGLFrameBuffer_FBO::n_Draw_Buffer");

	_ASSERTE(n_index >= 0 && n_index < m_n_draw_buffer_num);
	return GL_COLOR_ATTACHMENT0_EXT + n_index;
}

/*
 *	virtual bool CGLFrameBuffer_FBO::Bind()
 *		- binds the render buffer as OpenGL output buffer
 *		- returns true on success or false on failure
 */
bool CGLFrameBuffer_FBO::Bind()
{
	__FuncGuard("CGLFrameBuffer_FBO::Bind");

	if(!m_b_status)
		return false;

	if(m_b_active)
		return true;

	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_n_framebuffer);
	if(m_n_draw_buffer_num != 1) {
		for(int i = 0, n = m_n_max_draw_buffer_num; i < n; ++ i)
			glGetIntegerv(GL_DRAW_BUFFER0_ARB + i, (int*)&m_p_draw_buffers[i]);
		// remember draw buffers state

		if(m_n_draw_buffer_num) {
			const GLenum p_draw_buffers[] = {
				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,
				GL_COLOR_ATTACHMENT8_EXT, GL_COLOR_ATTACHMENT9_EXT,
				GL_COLOR_ATTACHMENT10_EXT, GL_COLOR_ATTACHMENT11_EXT,
				GL_COLOR_ATTACHMENT12_EXT, GL_COLOR_ATTACHMENT13_EXT,
				GL_COLOR_ATTACHMENT14_EXT, GL_COLOR_ATTACHMENT15_EXT
			};
			glDrawBuffers(m_n_draw_buffer_num, p_draw_buffers);
			// set new draw buffers state
		} else
			glDrawBuffer(GL_NONE);
	}

	m_b_active = true;

	return true;
}

/*
 *	virtual bool CGLFrameBuffer_FBO::Release()
 *		- releases the render buffer from OpenGL output buffer binding
 *		- returns true on success or false on failure
 */
bool CGLFrameBuffer_FBO::Release()
{
	__FuncGuard("CGLFrameBuffer_FBO::Release");

	if(!m_b_status || !m_b_active)
		return false;

	if(m_n_draw_buffer_num != 1)
		glDrawBuffers(m_n_max_draw_buffer_num, m_p_draw_buffers);
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
	// restore draw buffers state

	m_b_active = false;

	return true;
}

/*
 *	virtual bool CGLFrameBuffer_FBO::BindColorTexture_2D(const CGLTexture &r_texture,
 *		GLenum n_texture_type, int n_index = 0)
 *		- binds OpenGL texture r_texture.n_Id() as target for color output
 *		- n_texture_type is either GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE,
 *		  GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
 *		  GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
 *		  GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, or GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
 *		- n_index is index of one of draw buffers texture is to be bound to
 *		- binding texture with id 0 releases previously bound texture
 *		- returns true on success or false on failure
 */
bool CGLFrameBuffer_FBO::BindColorTexture_2D(const CGLTexture &r_texture,
	GLenum n_texture_type, int n_index)
{
	__FuncGuard("CGLFrameBuffer_FBO::BindColorTexture_2D");

	if(!m_b_status || !m_b_active || !m_n_draw_buffer_num)
		return false;
	if(n_index < 0 || n_index >= m_n_draw_buffer_num)
		return false;

	if(m_p_bound_color_texture[n_index].n_texture_id == r_texture.n_Id())
		return true;
	// bound already

	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
		GL_COLOR_ATTACHMENT0_EXT + n_index, n_texture_type, r_texture.n_Id(), 0);

	/*if(glGetError() != GL_NO_ERROR)
		return false;*/

	if(!m_p_bound_color_texture[n_index].n_texture_id && r_texture.n_Id())
		m_n_bound_color_texture_num ++;
	else if(m_p_bound_color_texture[n_index].n_texture_id && !r_texture.n_Id())
		m_n_bound_color_texture_num --;
	// maintain number of bound textures

	m_p_bound_color_texture[n_index].n_texture_id = r_texture.n_Id();
	m_p_bound_color_texture[n_index].n_target = n_texture_type;

	return true;
}

/*
 *	virtual bool CGLFrameBuffer_FBO::BindColorTexture_3D(const CGLTexture &r_texture,
 *		int n_z_offset, Glenum int n_index = 0)
 *		- binds OpenGL texture r_texture.n_Id() as target for color output
 *		- n_z_offset is index of 2D slice to be rendered to
 *		- n_index is index of one of draw buffers texture is to be bound to
 *		- binding texture with id 0 releases previously bound texture
 *		- returns true on success or false on failure
 */
bool CGLFrameBuffer_FBO::BindColorTexture_3D(const CGLTexture &r_texture,
	int n_z_offset, int n_index)
{
	__FuncGuard("CGLFrameBuffer_FBO::BindColorTexture_3D");

	if(!m_b_status || !m_b_active || !m_n_draw_buffer_num)
		return false;
	if(n_index < 0 || n_index >= m_n_draw_buffer_num)
		return false;

	if(m_p_bound_color_texture[n_index].n_texture_id == r_texture.n_Id())
		return true;
	// bound already

	glFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT,
		GL_COLOR_ATTACHMENT0_EXT + n_index, GL_TEXTURE_3D, r_texture.n_Id(), 0, n_z_offset);

	/*if(glGetError() != GL_NO_ERROR)
		return false;*/

	if(!m_p_bound_color_texture[n_index].n_texture_id && r_texture.n_Id())
		m_n_bound_color_texture_num ++;
	else if(m_p_bound_color_texture[n_index].n_texture_id && !r_texture.n_Id())
		m_n_bound_color_texture_num --;
	// maintain number of bound textures

	m_p_bound_color_texture[n_index].n_texture_id = r_texture.n_Id();
	m_p_bound_color_texture[n_index].n_target = GL_TEXTURE_3D;
	//m_p_bound_color_texture[n_index].n_3d_tex_slice = n_z_offset;

	return true;
}

/*
 *	virtual bool CGLFrameBuffer_FBO::BindDepthTexture_2D(const CGLTexture &r_texture,
 *		GLenum n_texture_type)
 *		- binds OpenGL texture r_texture.n_Id() as target for depth output
 *		- n_texture_type is either GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE
 *		- binding texture with id 0 releases previously bound texture
 *		- returns true on success or false on failure
 */
bool CGLFrameBuffer_FBO::BindDepthTexture_2D(const CGLTexture &r_texture, GLenum n_texture_type)
{
	__FuncGuard("CGLFrameBuffer_FBO::BindDepthTexture_2D");

	if(!m_b_status || !m_b_active || !m_b_depth_buffer || !m_b_depth_texture_target)
		return false;

	if(m_n_bound_depth_texture == r_texture.n_Id())
		return true;
	// bound already

	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
		GL_DEPTH_ATTACHMENT_EXT, n_texture_type, r_texture.n_Id(), 0);

	/*if(glGetError() != GL_NO_ERROR)
		return false;*/

	m_n_bound_depth_texture = r_texture.n_Id();

	return true;
}

/*
 *	virtual bool CGLFrameBuffer_FBO::BindStencilTexture_2D(const CGLTexture &r_texture,
 *		GLenum n_texture_type)
 *		- binds OpenGL texture r_texture.n_Id() as target for stencil output
 *		- n_texture_type is either GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE,
 *		  GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
 *		  GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
 *		  GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, or GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
 *		- binding texture with id 0 releases previously bound texture
 *		- returns true on success or false on failure
 */
bool CGLFrameBuffer_FBO::BindStencilTexture_2D(const CGLTexture &r_texture,
	GLenum n_texture_type)
{
	__FuncGuard("CGLFrameBuffer_FBO::BindStencilTexture_2D");

	if(!m_b_status || !m_b_active || !m_b_stencil_buffer || !m_b_stencil_texture_target)
		return false;

	if(m_n_bound_stencil_texture == r_texture.n_Id())
		return true;
	// bound already

	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
		GL_STENCIL_ATTACHMENT_EXT, n_texture_type, r_texture.n_Id(), 0);

	/*if(glGetError() != GL_NO_ERROR)
		return false;*/

	m_n_bound_stencil_texture = r_texture.n_Id();

	return true;
}

/*
 *	virtual bool CGLFrameBuffer_FBO::BindColorTexture_2D(GLuint n_texture,
 *		GLenum n_texture_type, int n_index = 0)
 *		- binds OpenGL texture n_texture as target for color output
 *		- n_texture_type is either GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE,
 *		  GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
 *		  GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
 *		  GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, or GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
 *		- n_index is index of one of draw buffers texture is to be bound to
 *		- binding texture with id 0 releases previously bound texture
 *		- returns true on success or false on failure
 */
bool CGLFrameBuffer_FBO::BindColorTexture_2D(GLuint n_texture,
	GLenum n_texture_type, int n_index)
{
	__FuncGuard("CGLFrameBuffer_FBO::BindColorTexture_2D");

	if(!m_b_status || !m_b_active || !m_n_draw_buffer_num)
		return false;
	if(n_index < 0 || n_index >= m_n_draw_buffer_num)
		return false;

	if(m_p_bound_color_texture[n_index].n_texture_id == n_texture)
		return true;
	// bound already

	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
		GL_COLOR_ATTACHMENT0_EXT + n_index, n_texture_type, n_texture, 0);

	/*if(glGetError() != GL_NO_ERROR)
		return false;*/

	if(!m_p_bound_color_texture[n_index].n_texture_id && n_texture)
		m_n_bound_color_texture_num ++;
	else if(m_p_bound_color_texture[n_index].n_texture_id && !n_texture)
		m_n_bound_color_texture_num --;
	// maintain number of bound textures

	m_p_bound_color_texture[n_index].n_texture_id = n_texture;
	m_p_bound_color_texture[n_index].n_target = n_texture_type;

	return true;
}

/*
 *	virtual bool CGLFrameBuffer_FBO::BindColorTexture_3D(GLuint n_texture,
 *		int n_z_offset, Glenum int n_index = 0)
 *		- binds OpenGL texture n_texture as target for color output
 *		- n_z_offset is index of 2D slice to be rendered to
 *		- n_index is index of one of draw buffers texture is to be bound to
 *		- binding texture with id 0 releases previously bound texture
 *		- returns true on success or false on failure
 */
bool CGLFrameBuffer_FBO::BindColorTexture_3D(GLuint n_texture, int n_z_offset, int n_index)
{
	__FuncGuard("CGLFrameBuffer_FBO::BindColorTexture_3D");

	if(!m_b_status || !m_b_active || !m_n_draw_buffer_num)
		return false;
	if(n_index < 0 || n_index >= m_n_draw_buffer_num)
		return false;

	if(m_p_bound_color_texture[n_index].n_texture_id == n_texture)
		return true;
	// bound already

	glFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT,
		GL_COLOR_ATTACHMENT0_EXT + n_index, GL_TEXTURE_3D, n_texture, 0, n_z_offset);

	/*if(glGetError() != GL_NO_ERROR)
		return false;*/

	if(!m_p_bound_color_texture[n_index].n_texture_id && n_texture)
		m_n_bound_color_texture_num ++;
	else if(m_p_bound_color_texture[n_index].n_texture_id && !n_texture)
		m_n_bound_color_texture_num --;
	// maintain number of bound textures

	m_p_bound_color_texture[n_index].n_texture_id = n_texture;
	m_p_bound_color_texture[n_index].n_target = GL_TEXTURE_3D;
	//m_p_bound_color_texture[n_index].n_3d_tex_slice = n_z_offset;

	return true;
}

/*
 *	virtual bool CGLFrameBuffer_FBO::BindDepthTexture_2D(GLuint n_texture,
 *		GLenum n_texture_type)
 *		- binds OpenGL texture n_texture as target for depth output
 *		- n_texture_type is either GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE
 *		- binding texture with id 0 releases previously bound texture
 *		- returns true on success or false on failure
 */
bool CGLFrameBuffer_FBO::BindDepthTexture_2D(GLuint n_texture, GLenum n_texture_type)
{
	__FuncGuard("CGLFrameBuffer_FBO::BindDepthTexture_2D");

	if(!m_b_status || !m_b_active || !m_b_depth_buffer || !m_b_depth_texture_target)
		return false;

	if(m_n_bound_depth_texture == n_texture)
		return true;
	// bound already

	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
		GL_DEPTH_ATTACHMENT_EXT, n_texture_type, n_texture, 0);

	/*if(glGetError() != GL_NO_ERROR)
		return false;*/

	m_n_bound_depth_texture = n_texture;

	return true;
}

/*
 *	virtual bool CGLFrameBuffer_FBO::BindStencilTexture_2D(GLuint n_texture,
 *		GLenum n_texture_type)
 *		- binds OpenGL texture n_texture as target for stencil output
 *		- n_texture_type is either GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE,
 *		  GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
 *		  GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
 *		  GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, or GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
 *		- binding texture with id 0 releases previously bound texture
 *		- returns true on success or false on failure
 */
bool CGLFrameBuffer_FBO::BindStencilTexture_2D(GLuint n_texture, GLenum n_texture_type)
{
	__FuncGuard("CGLFrameBuffer_FBO::BindStencilTexture_2D");

	if(!m_b_status || !m_b_active || !m_b_stencil_buffer || !m_b_stencil_texture_target)
		return false;

	if(m_n_bound_stencil_texture == n_texture)
		return true;
	// bound already

	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
		GL_STENCIL_ATTACHMENT_EXT, n_texture_type, n_texture, 0);

	/*if(glGetError() != GL_NO_ERROR)
		return false;*/

	m_n_bound_stencil_texture = n_texture;

	return true;
}

/*
 *	virtual bool CGLFrameBuffer_FBO::b_DirectRenderToTexture() const
 *		- returns true in case direct rendering to all textures, being bound is supported,
 *		  otherwise false
 *		- note in this implementation it always returns true
 */
bool CGLFrameBuffer_FBO::b_DirectRenderToTexture() const
{
	__FuncGuard("CGLFrameBuffer_FBO::b_DirectRenderToTexture");

	return true;
}

/*
 *	virtual bool CGLFrameBuffer_FBO::CopyTextureData(bool b_release_textures)
 *		- copies texture data to textures it wasn't possible to directly render to
 *		- in case b_release_textures is true, all currently bound textures are released
 *		- returns true on success or false on failure
 *		- note in this implementation it does not copy no data and always returns true
 */
bool CGLFrameBuffer_FBO::CopyTextureData(bool b_release_textures)
{
	__FuncGuard("CGLFrameBuffer_FBO::CopyTextureData");

	if(!m_b_status || !m_b_active)
		return false;

	if(b_release_textures) {
		for(int i = 0; i < m_n_draw_buffer_num && m_n_bound_color_texture_num > 0; ++ i) {
			if(m_p_bound_color_texture[i].n_texture_id) {
				if(m_p_bound_color_texture[i].n_target == GL_TEXTURE_3D) {
					glFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT,
						GL_COLOR_ATTACHMENT0_EXT + i, GL_TEXTURE_3D, 0, 0, 0);
				} else {
					glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
						GL_COLOR_ATTACHMENT0_EXT + i, m_p_bound_color_texture[i].n_target, 0, 0);
				}
				m_p_bound_color_texture[i].n_texture_id = 0;
				m_n_bound_color_texture_num --;
			}
		}
		_ASSERTE(!m_n_bound_color_texture_num);
		if(m_b_depth_buffer && m_b_depth_texture_target && m_n_bound_depth_texture) {
			glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
				GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0);
			m_n_bound_depth_texture = 0;
		}
		if(m_b_stencil_buffer && m_b_stencil_texture_target && m_n_bound_stencil_texture) {
			glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
				GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0);
			m_n_bound_stencil_texture = 0;
		}
	}

	return true;
}

/*
 *	virtual bool CGLFrameBuffer_FBO::b_Status() const
 *		- returns true in case render buffer, specified by constructor parameters
 *		  was successfuly created and is ready to use
 */
bool CGLFrameBuffer_FBO::b_Status() const
{
	__FuncGuard("CGLFrameBuffer_FBO::b_Status");

	if(!m_b_active)
		return m_b_status;
	int n_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
	return n_status == GL_FRAMEBUFFER_COMPLETE_EXT;
}

/*
 *	GLenum CGLFrameBuffer_FBO::n_Status() const
 *		- returns result of glCheckFramebufferStatusEXT() (GL_FRAMEBUFFER_COMPLETE_EXT)
 *		- returns 0 in case FBO isn't currently bound
 */
GLenum CGLFrameBuffer_FBO::n_Status() const
{
	__FuncGuard("CGLFrameBuffer_FBO::n_Status");

	if(!m_b_active)
		return 0;
	return glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
}

/*
 *								=== ~CGLFrameBuffer_FBO ===
 */
