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

#pragma once
#ifndef __RENDER_BUFFER2_INCLUDED
#define __RENDER_BUFFER2_INCLUDED

/**
 *	@file gl2/RenderBuffer2.h
 *	@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 CGLRenderBuffer_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 CGLRenderBuffer_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
 *
 *	@date 2012-06-19
 *
 *	Moved multiple inclusion guard before file documentation comment.
 *
 */

/*
 *	__RENDER_BUFFER2_DISABLE_VIRTUAL
 *		- if defined, CGLFrameBuffer and CGLFrameBuffer_FBO are the same class,
 *		  without virtual functions (they aren't really needed, since there's no
 *		  other CGLFrameBuffer implementation at the time (considering PBuffer
 *		  implementaiton, but they will likely not be supported))
 */
#define __RENDER_BUFFER2_DISABLE_VIRTUAL

/*
 *	class diagram with virtual functions enabled:
 *
 *	CGLFrameBuffer_Base (constructors and some inline getters)
 *
 *		A
 *		|
 *
 *	CGLFrameBuffer === CGLFrameBuffer_Root (virtual functions)
 *
 *							A
 *							|
 *
 *					   CGLFrameBuffer_FBO (implementation of virtual functions)
 *
 *	class diagram with virtual functions disabled:
 *
 *	CGLFrameBuffer_Base === CGLFrameBuffer_Root (constructors and some inline getters)
 *
 *								A
 *								|
 *
 *							CGLFrameBuffer_FBO (implementation without virtual functions)
 *
 */

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

/*
 *	class CGLFrameBuffer_Base
 *		- do NOT use this class, it's incomplete
 *		- its base from where virtual or non-virtual framebuffer class is inherited from
 */
class CGLFrameBuffer_Base {
protected:
	CGLState *m_p_state;
	int m_n_width;
	int m_n_height;

	int m_n_draw_buffer_num;
	GLenum m_n_color_internal_format;

	bool m_b_depth_buffer;
	GLenum m_n_depth_internal_format;

	bool m_b_stencil_buffer;
	GLenum m_n_stencil_internal_format;

	bool m_b_color_texture_target;
	bool m_b_depth_texture_target;
	bool m_b_stencil_texture_target;

	struct TColorTextureBinding {
		GLenum n_target; // GL_TEXTURE_2D, GL_TEXTURE_CUBE_FACE_POSITIVE_X, GL_TEXTURE_3D, ...
		GLuint n_texture_id;
	};

	TColorTextureBinding m_p_bound_color_texture[16];
	int m_n_bound_color_texture_num; // number of textures, being currently bound
	GLuint m_n_bound_depth_texture;
	GLuint m_n_bound_stencil_texture; // current bound texture or 0

	bool m_b_status;
	bool m_b_active;

public:
	/*
	 *	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)
	 *		- 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_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);

	/*
	 *	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)
	 *		- 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_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);

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

	/*
	 *	virtual CGLState *CGLFrameBuffer_Base::p_State()
	 *		- returns render-buffer OpenGL state guard (should be identic to
	 *		  global state guard for FBO, different for PBO)
	 *		- returns 0 in case render buffer is not initialized / ready
	 */
	inline CGLState *p_State()
	{
		return m_p_state;
	}

	/*
	 *	inline int CGLFrameBuffer_Base::n_Width() const
	 *		- returns width of the render buffer
	 */
	inline int n_Width() const
	{
		return m_n_width;
	}

	/*
	 *	inline int CGLFrameBuffer_Base::n_Height() const
	 *		- returns height of the render buffer
	 */
	inline int n_Height() const
	{
		return m_n_height;
	}

	/*
	 *	inline int CGLFrameBuffer_Base::n_Draw_Buffer_Num() const
	 *		- returns number of draw buffers
	 */
	inline int n_Draw_Buffer_Num() const
	{
		return m_n_draw_buffer_num;
	}

	/*
	 *	inline GLenum CGLFrameBuffer_Base::n_Color_Format() const
	 *		- returns color format
	 */
	inline GLenum n_Color_Format() const
	{
		return m_n_color_internal_format;
	}

	/*
	 *	inline bool CGLFrameBuffer_Base::b_Depth_Buffer() const
	 *		- returns true in case render buffer features depth buffer, otherwise false
	 */
	inline bool b_Depth_Buffer() const
	{
		return m_b_depth_buffer;
	}

	/*
	 *	inline GLenum CGLFrameBuffer_Base::n_Depth_Format() const
	 *		- returns depth buffer format (only valid in case depth buffer is present)
	 */
	inline GLenum n_Depth_Format() const
	{
		return m_n_depth_internal_format;
	}

	/*
	 *	inline bool CGLFrameBuffer_Base::b_Stencil_Buffer() const
	 *		- returns true in case render buffer features stencil buffer, otherwise false
	 */
	inline bool b_Stencil_Buffer() const
	{
		return m_b_stencil_buffer;
	}

	/*
	 *	inline GLenum CGLFrameBuffer_Base::n_Stencil_Format() const
	 *		- returns stencil buffer format (only valid in case stencil buffer is present)
	 */
	inline GLenum n_Stencil_Format() const
	{
		return m_n_stencil_internal_format;
	}

	/*
	 *	inline bool CGLFrameBuffer_Base::b_Color_TextureTarget() const
	 *		- returns true in case color is to be rendered to texture(s),
	 *		  otherwise false (color is rendered to render-buffer)
	 */
	inline bool b_Color_TextureTarget() const
	{
		return m_b_color_texture_target;
	}

	/*
	 *	inline bool CGLFrameBuffer_Base::b_Depth_TextureTarget() const
	 *		- returns true in case depth is to be rendered to depth texture,
	 *		  otherwise false (depth is either not present or rendered to depth-buffer)
	 */
	inline bool b_Depth_TextureTarget() const
	{
		return m_b_depth_texture_target;
	}

	/*
	 *	inline bool CGLFrameBuffer_Base::b_Stencil_TextureTarget() const
	 *		- returns true in case stencil is to be rendered to stencil texture,
	 *		  otherwise false (stencil is either not present or rendered to stencil-buffer)
	 */
	inline bool b_Stencil_TextureTarget() const
	{
		return m_b_stencil_texture_target;
	}

protected:
	static GLenum n_InternalColorFormat(GLenum n_color_format, int n_bit_num, bool b_float);
};

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

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

#ifndef __RENDER_BUFFER2_DISABLE_VIRTUAL

class CGLFrameBuffer : public CGLFrameBuffer_Base {
public:
	/*
	 *	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)
	 *		- 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(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::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(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);

	/*
	 *	virtual CGLFrameBuffer::~CGLFrameBuffer()
	 *		- destructor
	 *		- takes care of cleaning up
	 */
	virtual ~CGLFrameBuffer() {}

	/*
	 *	virtual int CGLFrameBuffer::n_Max_DrawBuffer_Num()
	 *		- returns maximal number of OpenGL draw buffers (1 where not supported, otherwise
	 *		  1, 2, 4; 8 on GeForce 8800, up to 16 in future)
	 */
	virtual int n_Max_DrawBuffer_Num() = 0;

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

	/*
	 *	virtual bool CGLFrameBuffer::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())
	 */
	virtual bool HandleModeSwitch() = 0;

	/*
	 *	virtual bool CGLFrameBuffer::Bind()
	 *		- binds the render buffer as OpenGL output buffer
	 *		- returns true on success or false on failure
	 */
	virtual bool Bind() = 0;

	/*
	 *	virtual GLenum CGLFrameBuffer::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
	 */
	virtual GLenum n_Draw_Buffer(int n_index) const = 0;

	/*
	 *	virtual bool CGLFrameBuffer::BindColorTexture_2D(const CGLTexture &r_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
	 */
	virtual bool BindColorTexture_2D(const CGLTexture &r_texture,
		GLenum n_texture_type, int n_index = 0) = 0;

	/*
	 *	virtual bool CGLFrameBuffer::BindColorTexture_3D(const CGLTexture &r_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
	 */
	virtual bool BindColorTexture_3D(const CGLTexture &r_texture,
		int n_z_offset, int n_index = 0) = 0;

	/*
	 *	virtual bool CGLFrameBuffer::BindDepthTexture_2D(const CGLTexture &r_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
	 */
	virtual bool BindDepthTexture_2D(const CGLTexture &r_texture, GLenum n_texture_type) = 0;

	/*
	 *	virtual bool CGLFrameBuffer::BindStencilTexture_2D(const CGLTexture &r_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
	 */
	virtual bool BindStencilTexture_2D(const CGLTexture &r_texture, GLenum n_texture_type) = 0;

	/*
	 *	virtual bool CGLFrameBuffer::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
	 */
	virtual bool BindColorTexture_2D(GLuint n_texture, GLenum n_texture_type, int n_index = 0) = 0;

	/*
	 *	virtual bool CGLFrameBuffer::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
	 */
	virtual bool BindColorTexture_3D(GLuint n_texture, int n_z_offset, int n_index = 0) = 0;

	/*
	 *	virtual bool CGLFrameBuffer::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
	 */
	virtual bool BindDepthTexture_2D(GLuint n_texture, GLenum n_texture_type) = 0;

	/*
	 *	virtual bool CGLFrameBuffer::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
	 */
	virtual bool BindStencilTexture_2D(GLuint n_texture, GLenum n_texture_type) = 0;

	/*
	 *	virtual bool CGLFrameBuffer::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
	 */
	virtual bool CopyTextureData(bool b_release_textures) = 0;

	/*
	 *	virtual bool CGLFrameBuffer::b_DirectRenderToTexture() const
	 *		- returns true in case direct rendering to all textures, being bound is supported,
	 *		  otherwise false
	 */
	virtual bool b_DirectRenderToTexture() const = 0;

	/*
	 *	virtual bool CGLFrameBuffer::Release()
	 *		- releases the render buffer from OpenGL output buffer binding
	 *		- returns true on success or false on failure
	 */
	virtual bool Release() = 0;

	/*
	 *	inline bool CGLFrameBuffer::BindDepthTexture_2D(const CGLTexture &r_texture,
	 *		GLenum n_texture_type)
	 *		- binds OpenGL texture n_texture as target for depth output
	 *		- note this can't be used for binding cube-map textures (no target face specified)
	 *		- binding texture with id 0 releases previously bound texture
	 *		- returns true on success or false on failure
	 */
	inline bool BindDepthTexture_2D(const CGLTexture &r_texture)
	{
		return BindDepthTexture_2D(r_texture, r_texture.n_Target());
	}

	/*
	 *	inline bool CGLFrameBuffer::BindStencilTexture_2D(const CGLTexture &r_texture)
	 *		- binds OpenGL texture n_texture as target for stencil output
	 *		- note this can't be used for binding cube-map textures (no target face specified)
	 *		- binding texture with id 0 releases previously bound texture
	 *		- returns true on success or false on failure
	 */
	inline bool BindStencilTexture_2D(const CGLTexture &r_texture)
	{
		return BindStencilTexture_2D(r_texture, r_texture.n_Target());
	}
};

typedef CGLFrameBuffer CGLFrameBuffer_Root;
#else // __RENDER_BUFFER2_DISABLE_VIRTUAL
typedef CGLFrameBuffer_Base CGLFrameBuffer_Root;
#endif // __RENDER_BUFFER2_DISABLE_VIRTUAL

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

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

#ifdef __RENDER_BUFFER2_DISABLE_VIRTUAL
#define _Virtual_ 
#else
#define _Virtual_ virtual
#endif

class CGLFrameBuffer_FBO : public CGLFrameBuffer_Root {
protected:
	GLuint m_n_framebuffer;
	GLuint m_p_color_rb[16];
	GLuint m_n_depth_rb;
	GLuint m_n_stencil_rb; // FBO objects

	int m_n_max_draw_buffer_num; // number of draw-buffer names to be saved
	GLuint m_p_draw_buffers[16]; // draw-buffers names, saved when Bind() and
	// restored when Release() in case more than one draw-buffer is used

	int m_n_my_max_draw_buffer_num; // number of this framebuffer's draw buffers

public:
	/*
	 *	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(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_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)
	 *		- 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(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);

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

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

	/*
	 *	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)
	 */
	static int n_Max_Size();

	/*
	 *	virtual int CGLFrameBuffer_FBO::n_Max_DrawBuffer_Num() const
	 *		- returns maximal number of OpenGL draw buffers (1 where not supported, otherwise
	 *		  1, 2, 4; 8 on GeForce 8800, up to 16 in future)
	 *		- note the value is cached so this is fast
	 */
	_Virtual_ int n_Max_DrawBuffer_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())
	 */
	_Virtual_ bool HandleModeSwitch();

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

	/*
	 *	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
	 */
	_Virtual_ GLenum n_Draw_Buffer(int n_index) const;

	/*
	 *	virtual bool CGLFrameBuffer_FBO::BindColorTexture_2D(const CGLTexture &r_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
	 */
	_Virtual_ bool BindColorTexture_2D(const CGLTexture &r_texture,
		GLenum n_texture_type, int n_index = 0);

	/*
	 *	virtual bool CGLFrameBuffer_FBO::BindColorTexture_3D(const CGLTexture &r_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
	 */
	_Virtual_ bool BindColorTexture_3D(const CGLTexture &r_texture, int n_z_offset, int n_index = 0);

	/*
	 *	virtual bool CGLFrameBuffer_FBO::BindDepthTexture_2D(const CGLTexture &r_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
	 */
	_Virtual_ bool BindDepthTexture_2D(const CGLTexture &r_texture, GLenum n_texture_type);

	/*
	 *	virtual bool CGLFrameBuffer_FBO::BindStencilTexture_2D(const CGLTexture &r_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
	 */
	_Virtual_ bool BindStencilTexture_2D(const CGLTexture &r_texture, GLenum n_texture_type);

	/*
	 *	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
	 */
	_Virtual_ bool BindColorTexture_2D(GLuint n_texture, GLenum n_texture_type, int n_index = 0);

	/*
	 *	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
	 */
	_Virtual_ bool BindColorTexture_3D(GLuint n_texture, int n_z_offset, int n_index = 0);

	/*
	 *	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
	 */
	_Virtual_ bool BindDepthTexture_2D(GLuint n_texture, GLenum n_texture_type);

	/*
	 *	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
	 */
	_Virtual_ bool BindStencilTexture_2D(GLuint n_texture, GLenum n_texture_type);

	/*
	 *	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
	 */
	_Virtual_ bool b_Status() const;

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

	/*
	 *	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
	 */
	_Virtual_ bool CopyTextureData(bool b_release_textures);

	/*
	 *	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
	 */
	_Virtual_ bool b_DirectRenderToTexture() const;

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

#ifdef __RENDER_BUFFER2_DISABLE_VIRTUAL
	/*
	 *	the following functions are implemented in virtual superclass CGLFrameBuffer,
	 *	they have to be implemented here, in case we do not inherit from CGLFrameBuffer
	 */

	/*
	 *	inline bool CGLFrameBuffer_FBO::BindDepthTexture_2D(const CGLTexture &r_texture,
	 *		GLenum n_texture_type)
	 *		- binds OpenGL texture n_texture as target for depth output
	 *		- note this can't be used for binding cube-map textures (no target face specified)
	 *		- binding texture with id 0 releases previously bound texture
	 *		- returns true on success or false on failure
	 */
	inline bool BindDepthTexture_2D(const CGLTexture &r_texture)
	{
		return BindDepthTexture_2D(r_texture, r_texture.n_Target());
	}

	/*
	 *	inline bool CGLFrameBuffer_FBO::BindStencilTexture_2D(const CGLTexture &r_texture)
	 *		- binds OpenGL texture n_texture as target for stencil output
	 *		- note this can't be used for binding cube-map textures (no target face specified)
	 *		- binding texture with id 0 releases previously bound texture
	 *		- returns true on success or false on failure
	 */
	inline bool BindStencilTexture_2D(const CGLTexture &r_texture)
	{
		return BindStencilTexture_2D(r_texture, r_texture.n_Target());
	}
#endif // __RENDER_BUFFER2_DISABLE_VIRTUAL

protected:
	bool Create();
};

#ifdef __RENDER_BUFFER2_DISABLE_VIRTUAL
typedef CGLFrameBuffer_FBO CGLFrameBuffer;
#endif
// in case virtual functions are disabled, CGLFrameBuffer is equivalent to CGLFrameBuffer_FBO

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

#endif // !__RENDER_BUFFER2_INCLUDED
