/*
								+--------------------------------+
								|                                |
								|     ***   OpenGL 4.0   ***     |
								|                                |
								|  Copyright © -tHE SWINe- 2009  |
								|                                |
								|           Texture.h            |
								|                                |
								+--------------------------------+
*/

#pragma once
#ifndef __TEXTURE_MANAGER4_INCLUDED
#define __TEXTURE_MANAGER4_INCLUDED

/**
 *	@file gl4/Texture.h
 *	@author -tHE SWINe-
 *	@date 2009
 *	@brief OpenGL 4.0 textures
 *
 *	@todo Write documentation for this, make sure all useful extensions are implemented.
 *	@todo Implement GL_ARB_texture_multisample, GL_ARB_texture_cube_map_array, GL_EXT_texture_buffer_object.
 *
 *	Done:
 *		- Implement GL_EXT_texture_array.
 *
 *	@date 2012-06-19
 *
 *	Added \#pragma once.
 *
 */

#include "OpenGL40.h"

/**
 *	@def __GL_TEXTURE_STORE_INTERNAL_FORMAT
 *	@brief if defined, all texture classes (derived from CGLTexture) store internal
 *		texture image format in a member variable; otherwise CGLTexture::n_Internal_Format()
 *		is not available
 */
//#define __GL_TEXTURE_STORE_INTERNAL_FORMAT

/**
 *	@def b_IsTexture1D
 *	@brief determines whether a given texture target specifies a 1D texture
 *	@param[in] n_tex_target is OpenGL texture target name
 */
#define b_IsTexture1D(n_tex_target) ((n_tex_target) == GL_TEXTURE_1D)

/**
 *	@def b_IsTextureCubeFace
 *	@brief determines whether a given texture target specifies a cube-map texture face
 *	@param[in] n_tex_target is OpenGL texture target name
 */
#define b_IsTextureCubeFace(n_tex_target) ( \
	(n_tex_target) == GL_TEXTURE_CUBE_MAP_NEGATIVE_X || \
	(n_tex_target) == GL_TEXTURE_CUBE_MAP_POSITIVE_X || \
	(n_tex_target) == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y || \
	(n_tex_target) == GL_TEXTURE_CUBE_MAP_POSITIVE_Y || \
	(n_tex_target) == GL_TEXTURE_CUBE_MAP_NEGATIVE_Z || \
	(n_tex_target) == GL_TEXTURE_CUBE_MAP_POSITIVE_Z)

/**
 *	@def b_IsTextureFace
 *	@brief determines whether a given texture target specifies a texture face
 *	@param[in] n_tex_target is OpenGL texture target name
 *	@note At the moment, only cube map textures do have faces.
 *		This is here for future extensibility only.
 */
#define b_IsTextureFace(n_tex_target) (b_IsTextureCubeFace(n_tex_target))

/**
 *	@def b_IsTexture2D
 *	@brief determines whether a given texture target specifies a 2D texture
 *	@param[in] n_tex_target is OpenGL texture target name
 */
#define b_IsTexture2D(n_tex_target) ((n_tex_target) == GL_TEXTURE_2D || \
	(n_tex_target) == GL_TEXTURE_1D_ARRAY || \
	(n_tex_target) == GL_TEXTURE_RECTANGLE || b_IsTextureCubeFace(n_tex_target))

/**
 *	@def b_IsTexture3D
 *	@brief determines whether a given texture target specifies a 3D texture
 *	@param[in] n_tex_target is OpenGL texture target name
 */
#define b_IsTexture3D(n_tex_target) ((n_tex_target) == GL_TEXTURE_3D || \
	(n_tex_target) == GL_TEXTURE_2D_ARRAY)

/**
 *	@brief base class for OpenGL texture
 */
class CGLTexture {
protected:
	GLuint m_n_id;
#ifdef __GL_TEXTURE_STORE_INTERNAL_FORMAT
	GLenum m_n_internal_format; // GL_RGB8
#endif // __GL_TEXTURE_STORE_INTERNAL_FORMAT
	GLenum m_n_target; // GL_TEXTURE_2D

public:
	/**
	 *	@brief default constructor; stores the texture parameters only
	 *
	 *	@param[in] n_internal_format is internal format name
	 *	@param[in] n_target is texture target
	 *
	 *	@note n_internal_format is only stored if __GL_TEXTURE_STORE_INTERNAL_FORMAT is defined
	 *		(the parameter is retained for implementation simplicity).
	 */
	CGLTexture(GLenum n_internal_format, GLenum n_target);

	/**
	 *	@brief destructor; deletes OpenGL texture object in case it was created
	 */
	~CGLTexture();

	/**
	 *	@brief gets texture status
	 *	@return Returns true in case texture was successfuly created
	 *		and can be used for texturing, otherwise returns false.
	 */
	bool b_Status() const;

	/**
	 *	@brief binds the texture to the current texturing unit
	 */
	inline void Bind() const
	{
		glBindTexture(m_n_target, m_n_id);
	}

	/**
	 *	@brief makes the specified texturing unit active and binds the texture to it
	 *	@param[in] n_texture_unit is name of the terget texturing unit (eg. GL_TEXTURE0)
	 */
	inline void Bind(GLenum n_texture_unit) const
	{
		glActiveTexture(n_texture_unit);
		glBindTexture(m_n_target, m_n_id);
	}

	/**
	 *	@brief binds the texture to the specified texturing unit (without making it active)
	 *	@param[in] n_texture_unit is name of the terget texturing unit (eg. GL_TEXTURE0)
	 *	@note This requires the GL_ARB_direct_state_access extension.
	 */
	inline void BindTo(GLenum n_texture_unit) const
	{
		_ASSERTE(GLEH_ARB_direct_state_access); // the extension must be present
		glBindTextureUnit(n_texture_unit, m_n_id);
	}

	/**
	 *	@brief gets texture target
	 *	@return Returns texture target (eg. GL_TEXTURE_2D).
	 */
	inline GLenum n_Target() const
	{
		return m_n_target;
	}

#ifdef __GL_TEXTURE_STORE_INTERNAL_FORMAT
	/**
	 *	@brief gets texture internal format
	 *
	 *	@return Returns the stored texture internal format.
	 *
	 *	@note This function is only available if __GL_TEXTURE_STORE_INTERNAL_FORMAT is defined.
	 *	@note This assumes all the texture levels have the same format
	 *		and that the format did not change by texture image respecification.
	 */
	inline GLenum n_Internal_Format() const
	{
		return m_n_internal_format;

		/*int n_internal_format;
		glGetTextureParameterivEXT(m_n_id, m_n_target, GL_TEXTURE_INTERNAL_FORMAT, &n_internal_format);
		return n_internal_format;*/
		// doesn't work; GL_TEXTURE_INTERNAL_FORMAT is not a valid texture parameter target

		/*int n_internal_format;
		glGetTexLevelParameteriv(m_n_target, 0, GL_TEXTURE_INTERNAL_FORMAT, &n_internal_format);
		return n_internal_format;*/
		// does work, at least for level 0 but disturbs the state

		/*int n_internal_format;
		glGetTextureLevelParameterivEXT(m_n_id, m_n_target, 0, GL_TEXTURE_INTERNAL_FORMAT, &n_internal_format);
		return n_internal_format;*/
		// does work, at least for level 0 but requires GL_EXT_direct_state_access
	}
#endif // __GL_TEXTURE_STORE_INTERNAL_FORMAT

	// texture parameter getters; texture must be bound to use them
	GLenum n_Get_Wrap_S() const;
	GLenum n_Get_Wrap_T() const;
	GLenum n_Get_Wrap_R() const;
	GLenum n_Get_Min_Filter() const;
	GLenum n_Get_Mag_Filter() const;
	float f_Get_Min_LOD() const;
	float f_Get_Max_LOD() const;
	int n_Get_Base_Level() const;
	int n_Get_Max_Level() const;
	GLenum n_Get_Compare_Mode() const;
	GLenum n_Get_Compare_Func() const;
	float f_Get_Anisotropy() const;

	// texture parameter setters; texture must be bound to use them
	// note those involve calling glGetIntegerv() / glGetFloatv(),
	// and possibly unwanted GPU / CPU synchronisation
	void Set_Wrap_S(GLenum n_wrap_mode) const;
	void Set_Wrap_T(GLenum n_wrap_mode) const;
	void Set_Wrap_R(GLenum n_wrap_mode) const;
	void Set_Min_Filter(GLenum n_minify_filter) const;
	void Set_Mag_Filter(GLenum n_magnify_filter) const;
	void Set_Min_LOD(float f_min_lod) const;
	void Set_Max_LOD(float f_max_lod) const;
	void Set_Base_Level(int n_base_level) const;
	void Set_Max_Level(int n_max_level) const;
	void Set_Compare_Mode(GLenum n_compare_mode) const;
	void Set_Compare_Func(GLenum n_compare_func) const;
	void Set_Anisotropy(float f_anisotropy) const;

	/**
	 *	@brief gets maximal texture size
	 *
	 *	@return Returns maximal texture size.
	 *
	 *	@note This involves calling glGetIntegerv(), and possibly unwanted GPU / CPU synchronisation.
	 */
	static int n_Max_Size();

	/**
	 *	@brief gets maximal texture anisotropy
	 *
	 *	@return Returns maximal texture anisotropy.
	 *
	 *	@note This involves calling glGetFloatv(), and possibly unwanted GPU / CPU synchronisation.
	 */
	static float f_Max_Anisotropy();

	inline void FramebufferTexture(GLenum n_target, GLenum n_attachment, int n_level) const
	{
		glFramebufferTexture(n_target, n_attachment, m_n_id, n_level);
	}

	inline void FramebufferTextureLayer(GLenum n_target,
		GLenum n_attachment, int n_level, int n_layer) const
	{
		glFramebufferTextureLayer(n_target, n_attachment, m_n_id, n_level, n_layer);
	}

	inline void FramebufferTextureFace(GLenum n_target,
		GLenum n_attachment, int n_level, GLenum n_face) const
	{
		glFramebufferTexture2D(n_target, n_attachment, n_face, m_n_id, n_level);
	}

private:
	CGLTexture(const CGLTexture &r_tex); /**< @brief copy-constructor (cannot be used) */
	CGLTexture &operator =(const CGLTexture &r_tex); /**< @brief copy-operator (cannot be used) */
};

class CGLTexture_1D_Base : public CGLTexture {
public:
	inline CGLTexture_1D_Base(GLenum n_internal_format, GLenum n_target)
		:CGLTexture(n_internal_format, n_target)
	{
		_ASSERTE(b_IsTexture1D(n_target));
	}

	inline void FramebufferTexture1D(GLenum n_target = GL_DRAW_FRAMEBUFFER,
		GLenum n_attachment = GL_COLOR_ATTACHMENT0, int n_level = 0) const
	{
		glFramebufferTexture1D(n_target, n_attachment, m_n_target, m_n_id, n_level);
	}

	inline void FramebufferTexture1D(GLenum n_target, GLenum n_attachment,
		GLenum n_tex_target, int n_level) const
	{
		glFramebufferTexture1D(n_target, n_attachment, n_tex_target, m_n_id, n_level);
	}
};

class CGLTexture_2D_Base : public CGLTexture {
public:
	inline CGLTexture_2D_Base(GLenum n_internal_format, GLenum n_target)
		:CGLTexture(n_internal_format, n_target)
	{
		_ASSERTE(b_IsTexture2D(n_target) && !b_IsTextureCubeFace(n_target));
	}

	inline void FramebufferTexture2D(GLenum n_target = GL_DRAW_FRAMEBUFFER,
		GLenum n_attachment = GL_COLOR_ATTACHMENT0, int n_level = 0) const
	{
		glFramebufferTexture2D(n_target, n_attachment, m_n_target, m_n_id, n_level);
	}

	inline void FramebufferTexture2D(GLenum n_target, GLenum n_attachment,
		GLenum n_tex_target, int n_level) const
	{
		glFramebufferTexture2D(n_target, n_attachment, n_tex_target, m_n_id, n_level);
	}
};

class CGLTexture_3D_Base : public CGLTexture {
public:
	inline CGLTexture_3D_Base(GLenum n_internal_format, GLenum n_target)
		:CGLTexture(n_internal_format, n_target)
	{
		_ASSERTE(b_IsTexture3D(n_target));
	}

	inline void FramebufferTexture3D(GLenum n_target,
		GLenum n_attachment, int n_level, int n_layer) const
	{
		glFramebufferTexture3D(n_target, n_attachment, m_n_target, m_n_id, n_level, n_layer);
	}

	inline void FramebufferTexture2D(GLenum n_target, GLenum n_attachment,
		GLenum n_tex_target, int n_level, int n_layer) const
	{
		glFramebufferTexture3D(n_target, n_attachment, n_tex_target, m_n_id, n_level, n_layer);
	}
};

class CGLTexture_1D : public CGLTexture_1D_Base {
protected:
	int m_n_width;

public:
	/**
	 *	@brief default constructor
	 *
	 *	@param[in] n_width is texture width, in pixels
	 *	@param[in] n_internal_format is internal format, e.g. \ref GL_RGBA8
	 *	@param[in] b_create_mipmaps is mipmap creation flag (if set, the mipmaps are allocated,
	 *		the mip chain is built and the minification filter is set to \ref GL_LINEAR_MIPMAP_LINEAR;
	 *		otherwise the minification filter is set to \ref GL_LINEAR)
	 *	@param[in] n_format is bitmap pixel format, e.f. \ref GL_RGBA
	 *	@param[in] n_data_type is bitmap data type, e.f. \ref GL_UNSIGNED_BYTE
	 *	@param[in] p_src_data is pointer to source image data (if null, the texture contents
	 *		are not specified)
	 *
	 *	@note Call \ref b_Status() to find out wheter constructor succeeded.
	 *	@note This calls glGetError() and so it fails in case there are some
	 *		uncaught errors despite texture creation is successful.
	 */
	CGLTexture_1D(int n_width, GLenum n_internal_format,
		bool b_create_mipmaps = true,
		GLenum n_format = GL_RGB, GLenum n_data_type = GL_UNSIGNED_BYTE,
		const void *p_src_data = 0);

	/**
	 *	@brief texture image re-specification; deletes the old content, potentially changes texture size
	 *
	 *	@param[in] n_width is texture width, in pixels
	 *	@param[in] n_internal_format is internal format, e.g. \ref GL_RGBA8
	 *	@param[in] b_redo_mipmaps is mipmap refresh flag (if set, the the mip
	 *		chain is re-built; otherwise nothing is done; note that this does not
	 *		affect the minification filter setting for this texture)
	 *	@param[in] n_format is bitmap pixel format, e.f. \ref GL_RGBA
	 *	@param[in] n_data_type is bitmap data type, e.f. \ref GL_UNSIGNED_BYTE
	 *	@param[in] p_src_data is pointer to source image data
	 *
	 *	@note The caller must make sure this texture is bound before calling this function.
	 *	@note This potentially changes texture size.
	 *	@note This never changes texture filtering options (even if the mip-chain is re-built).
	 *	@note Call \ref b_Status() to find out wheter constructor succeeded.
	 */
	void TexImage(int n_width, GLenum n_internal_format, bool b_redo_mipmaps,
		GLenum n_format, GLenum n_data_type, const void *p_src_data);

	/**
	 *	@brief texture image re-specification; deletes the old content, potentially changes texture size
	 *
	 *	@param[in] n_width is texture width, in pixels
	 *	@param[in] n_mip_level is level in the mip-map chain (base level is 0)
	 *	@param[in] n_internal_format is internal format, e.g. \ref GL_RGBA8
	 *	@param[in] b_redo_mipmaps is mipmap refresh flag (if set, the the mip
	 *		chain is re-built; otherwise nothing is done; note that this does not
	 *		affect the minification filter setting for this texture)
	 *	@param[in] n_format is bitmap pixel format, e.f. \ref GL_RGBA
	 *	@param[in] n_data_type is bitmap data type, e.f. \ref GL_UNSIGNED_BYTE
	 *	@param[in] p_src_data is pointer to source image data
	 *
	 *	@note The caller must make sure this texture is bound before calling this function.
	 *	@note This potentially changes texture size but only if <tt>n_mip_level</tt> is zero.
	 *	@note This never changes texture filtering options (even if the mip-chain is re-built).
	 *	@note Call \ref b_Status() to find out wheter constructor succeeded.
	 */
	void TexImage(int n_width, int n_mip_level, GLenum n_internal_format,
		bool b_redo_mipmaps, GLenum n_format, GLenum n_data_type, const void *p_src_data);

	inline int n_Width() const { return m_n_width; }
};

class CGLTexture_2D : public CGLTexture_2D_Base {
protected:
	int m_n_width;
	int m_n_height;

public:
	/**
	 *	@brief default constructor
	 *
	 *	@param[in] n_width is texture width, in pixels
	 *	@param[in] n_height is texture height, in pixels
	 *	@param[in] n_internal_format is internal format, e.g. \ref GL_RGBA8
	 *	@param[in] b_create_mipmaps is mipmap creation flag (if set, the mipmaps are allocated,
	 *		the mip chain is built and the minification filter is set to \ref GL_LINEAR_MIPMAP_LINEAR;
	 *		otherwise the minification filter is set to \ref GL_LINEAR)
	 *	@param[in] n_format is bitmap pixel format, e.f. \ref GL_RGBA
	 *	@param[in] n_data_type is bitmap data type, e.f. \ref GL_UNSIGNED_BYTE
	 *	@param[in] p_src_data is pointer to source image data (if null, the texture contents
	 *		are not specified)
	 *
	 *	@note Call \ref b_Status() to find out wheter constructor succeeded.
	 *	@note This calls glGetError() and so it fails in case there are some
	 *		uncaught errors despite texture creation is successful.
	 */
	CGLTexture_2D(int n_width, int n_height, GLenum n_internal_format,
		bool b_create_mipmaps = true,
		GLenum n_format = GL_RGB, GLenum n_data_type = GL_UNSIGNED_BYTE,
		const void *p_src_data = 0);

	/**
	 *	@brief texture image re-specification; deletes the old content, potentially changes texture size
	 *
	 *	@param[in] n_width is texture width, in pixels
	 *	@param[in] n_height is texture height, in pixels
	 *	@param[in] n_internal_format is internal format, e.g. \ref GL_RGBA8
	 *	@param[in] b_redo_mipmaps is mipmap refresh flag (if set, the the mip
	 *		chain is re-built; otherwise nothing is done; note that this does not
	 *		affect the minification filter setting for this texture)
	 *	@param[in] n_format is bitmap pixel format, e.f. \ref GL_RGBA
	 *	@param[in] n_data_type is bitmap data type, e.f. \ref GL_UNSIGNED_BYTE
	 *	@param[in] p_src_data is pointer to source image data
	 *
	 *	@note The caller must make sure this texture is bound before calling this function.
	 *	@note This potentially changes texture size.
	 *	@note This never changes texture filtering options (even if the mip-chain is re-built).
	 *	@note Call \ref b_Status() to find out wheter constructor succeeded.
	 */
	void TexImage(int n_width, int n_height, GLenum n_internal_format,
		bool b_redo_mipmaps, GLenum n_format, GLenum n_data_type, const void *p_src_data);

	/**
	 *	@brief texture image re-specification; deletes the old content, potentially changes texture size
	 *
	 *	@param[in] n_width is texture width, in pixels
	 *	@param[in] n_height is texture height, in pixels
	 *	@param[in] n_mip_level is level in the mip-map chain (base level is 0)
	 *	@param[in] n_internal_format is internal format, e.g. \ref GL_RGBA8
	 *	@param[in] b_redo_mipmaps is mipmap refresh flag (if set, the the mip
	 *		chain is re-built; otherwise nothing is done; note that this does not
	 *		affect the minification filter setting for this texture)
	 *	@param[in] n_format is bitmap pixel format, e.f. \ref GL_RGBA
	 *	@param[in] n_data_type is bitmap data type, e.f. \ref GL_UNSIGNED_BYTE
	 *	@param[in] p_src_data is pointer to source image data
	 *
	 *	@note The caller must make sure this texture is bound before calling this function.
	 *	@note This potentially changes texture size but only if <tt>n_mip_level</tt> is zero.
	 *	@note This never changes texture filtering options (even if the mip-chain is re-built).
	 *	@note Call \ref b_Status() to find out wheter constructor succeeded.
	 */
	void TexImage(int n_width, int n_height, int n_mip_level, GLenum n_internal_format,
		bool b_redo_mipmaps, GLenum n_format, GLenum n_data_type, const void *p_src_data);

	inline int n_Width() const { return m_n_width; }
	inline int n_Height() const { return m_n_height; }
};

class CGLTexture_Rect : public CGLTexture_2D_Base {
protected:
	int m_n_width;
	int m_n_height;

public:
	/**
	 *	@brief default constructor
	 *
	 *	@param[in] n_width is texture width, in pixels
	 *	@param[in] n_height is texture height, in pixels
	 *	@param[in] n_internal_format is internal format, e.g. \ref GL_RGBA8
	 *	@param[in] n_format is bitmap pixel format, e.f. \ref GL_RGBA
	 *	@param[in] n_data_type is bitmap data type, e.f. \ref GL_UNSIGNED_BYTE
	 *	@param[in] p_src_data is pointer to source image data (if null, the texture contents
	 *		are not specified)
	 *
	 *	@note Call \ref b_Status() to find out wheter constructor succeeded.
	 *	@note This calls glGetError() and so it fails in case there are some
	 *		uncaught errors despite texture creation is successful.
	 */
	CGLTexture_Rect(int n_width, int n_height, GLenum n_internal_format,
		GLenum n_format = GL_RGB, GLenum n_data_type = GL_UNSIGNED_BYTE,
		const void *p_src_data = 0);

	/**
	 *	@brief texture image re-specification; deletes the old content, potentially changes texture size
	 *
	 *	@param[in] n_width is texture width, in pixels
	 *	@param[in] n_height is texture height, in pixels
	 *	@param[in] n_internal_format is internal format, e.g. \ref GL_RGBA8
	 *	@param[in] n_format is bitmap pixel format, e.f. \ref GL_RGBA
	 *	@param[in] n_data_type is bitmap data type, e.f. \ref GL_UNSIGNED_BYTE
	 *	@param[in] p_src_data is pointer to source image data
	 *
	 *	@note The caller must make sure this texture is bound before calling this function.
	 *	@note This potentially changes texture size.
	 *	@note Call \ref b_Status() to find out wheter constructor succeeded.
	 */
	void TexImage(int n_width, int n_height, GLenum n_internal_format,
		GLenum n_format, GLenum n_data_type, const void *p_src_data);

	inline int n_Width() const { return m_n_width; }
	inline int n_Height() const { return m_n_height; }
};

class CGLTexture_3D : public CGLTexture_3D_Base {
protected:
	int m_n_width;
	int m_n_height;
	int m_n_depth;

public:
	/**
	 *	@brief default constructor
	 *
	 *	@param[in] n_width is texture width, in pixels
	 *	@param[in] n_height is texture height, in pixels
	 *	@param[in] n_depth is texture depth, in pixels
	 *	@param[in] n_internal_format is internal format, e.g. \ref GL_RGBA8
	 *	@param[in] b_create_mipmaps is mipmap creation flag (if set, the mipmaps are allocated,
	 *		the mip chain is built and the minification filter is set to \ref GL_LINEAR_MIPMAP_LINEAR;
	 *		otherwise the minification filter is set to \ref GL_LINEAR)
	 *	@param[in] n_format is bitmap pixel format, e.f. \ref GL_RGBA
	 *	@param[in] n_data_type is bitmap data type, e.f. \ref GL_UNSIGNED_BYTE
	 *	@param[in] p_src_data is pointer to source image data (if null, the texture contents
	 *		are not specified)
	 *
	 *	@note Call \ref b_Status() to find out wheter constructor succeeded.
	 *	@note This calls glGetError() and so it fails in case there are some
	 *		uncaught errors despite texture creation is successful.
	 */
	CGLTexture_3D(int n_width, int n_height, int n_depth,
		GLenum n_internal_format, bool b_create_mipmaps = true,
		GLenum n_format = GL_RGB, GLenum n_data_type = GL_UNSIGNED_BYTE,
		const void *p_src_data = 0);

	/**
	 *	@brief texture image re-specification; deletes the old content, potentially changes texture size
	 *
	 *	@param[in] n_width is texture width, in pixels
	 *	@param[in] n_height is texture height, in pixels
	 *	@param[in] n_depth is texture depth, in pixels
	 *	@param[in] n_internal_format is internal format, e.g. \ref GL_RGBA8
	 *	@param[in] b_redo_mipmaps is mipmap refresh flag (if set, the the mip
	 *		chain is re-built; otherwise nothing is done; note that this does not
	 *		affect the minification filter setting for this texture)
	 *	@param[in] n_format is bitmap pixel format, e.f. \ref GL_RGBA
	 *	@param[in] n_data_type is bitmap data type, e.f. \ref GL_UNSIGNED_BYTE
	 *	@param[in] p_src_data is pointer to source image data
	 *
	 *	@note The caller must make sure this texture is bound before calling this function.
	 *	@note This potentially changes texture size.
	 *	@note This never changes texture filtering options (even if the mip-chain is re-built).
	 *	@note Call \ref b_Status() to find out wheter constructor succeeded.
	 */
	void TexImage(int n_width, int n_height, int n_depth, GLenum n_internal_format,
		bool b_redo_mipmaps, GLenum n_format, GLenum n_data_type, const void *p_src_data);

	/**
	 *	@brief texture image re-specification; deletes the old content, potentially changes texture size
	 *
	 *	@param[in] n_width is texture width, in pixels
	 *	@param[in] n_height is texture height, in pixels
	 *	@param[in] n_depth is texture depth, in pixels
	 *	@param[in] n_mip_level is level in the mip-map chain (base level is 0)
	 *	@param[in] n_internal_format is internal format, e.g. \ref GL_RGBA8
	 *	@param[in] b_redo_mipmaps is mipmap refresh flag (if set, the the mip
	 *		chain is re-built; otherwise nothing is done; note that this does not
	 *		affect the minification filter setting for this texture)
	 *	@param[in] n_format is bitmap pixel format, e.f. \ref GL_RGBA
	 *	@param[in] n_data_type is bitmap data type, e.f. \ref GL_UNSIGNED_BYTE
	 *	@param[in] p_src_data is pointer to source image data
	 *
	 *	@note The caller must make sure this texture is bound before calling this function.
	 *	@note This potentially changes texture size but only if <tt>n_mip_level</tt> is zero.
	 *	@note This never changes texture filtering options (even if the mip-chain is re-built).
	 *	@note Call \ref b_Status() to find out wheter constructor succeeded.
	 */
	void TexImage(int n_width, int n_height, int n_depth, int n_mip_level, GLenum n_internal_format,
		bool b_redo_mipmaps, GLenum n_format, GLenum n_data_type, const void *p_src_data);

	inline int n_Width() const { return m_n_width; }
	inline int n_Height() const { return m_n_height; }
	inline int n_Depth() const { return m_n_depth; }
};

class CGLTexture_1D_Array : public CGLTexture_2D_Base {
protected:
	int m_n_width;
	int m_n_layer_num;

public:
	/**
	 *	@brief default constructor
	 *
	 *	@param[in] n_width is texture width, in pixels
	 *	@param[in] n_layer_num is number of texture layers
	 *	@param[in] n_internal_format is internal format, e.g. \ref GL_RGBA8
	 *	@param[in] b_create_mipmaps is mipmap creation flag (if set, the mipmaps are allocated,
	 *		the mip chain is built and the minification filter is set to \ref GL_LINEAR_MIPMAP_LINEAR;
	 *		otherwise the minification filter is set to \ref GL_LINEAR)
	 *	@param[in] n_format is bitmap pixel format, e.f. \ref GL_RGBA
	 *	@param[in] n_data_type is bitmap data type, e.f. \ref GL_UNSIGNED_BYTE
	 *	@param[in] p_src_data is pointer to source image data (if null, the texture contents
	 *		are not specified)
	 *
	 *	@note Call \ref b_Status() to find out wheter constructor succeeded.
	 *	@note This calls glGetError() and so it fails in case there are some
	 *		uncaught errors despite texture creation is successful.
	 */
	CGLTexture_1D_Array(int n_width, int n_layer_num,
		GLenum n_internal_format, bool b_create_mipmaps = true,
		GLenum n_format = GL_RGB, GLenum n_data_type = GL_UNSIGNED_BYTE,
		const void *p_src_data = 0);

	/**
	 *	@brief texture image re-specification; deletes the old content, potentially changes texture size
	 *
	 *	@param[in] n_width is texture width, in pixels
	 *	@param[in] n_layer_num is number of texture layers
	 *	@param[in] n_internal_format is internal format, e.g. \ref GL_RGBA8
	 *	@param[in] b_redo_mipmaps is mipmap refresh flag (if set, the the mip
	 *		chain is re-built; otherwise nothing is done; note that this does not
	 *		affect the minification filter setting for this texture)
	 *	@param[in] n_format is bitmap pixel format, e.f. \ref GL_RGBA
	 *	@param[in] n_data_type is bitmap data type, e.f. \ref GL_UNSIGNED_BYTE
	 *	@param[in] p_src_data is pointer to source image data
	 *
	 *	@note The caller must make sure this texture is bound before calling this function.
	 *	@note This potentially changes texture size.
	 *	@note This never changes texture filtering options (even if the mip-chain is re-built).
	 *	@note Call \ref b_Status() to find out wheter constructor succeeded.
	 */
	void TexImage(int n_width, int n_layer_num, GLenum n_internal_format,
		bool b_redo_mipmaps, GLenum n_format, GLenum n_data_type, const void *p_src_data);

	/**
	 *	@brief texture image re-specification; deletes the old content, potentially changes texture size
	 *
	 *	@param[in] n_width is texture width, in pixels
	 *	@param[in] n_layer_num is number of texture layers
	 *	@param[in] n_mip_level is level in the mip-map chain (base level is 0)
	 *	@param[in] n_internal_format is internal format, e.g. \ref GL_RGBA8
	 *	@param[in] b_redo_mipmaps is mipmap refresh flag (if set, the the mip
	 *		chain is re-built; otherwise nothing is done; note that this does not
	 *		affect the minification filter setting for this texture)
	 *	@param[in] n_format is bitmap pixel format, e.f. \ref GL_RGBA
	 *	@param[in] n_data_type is bitmap data type, e.f. \ref GL_UNSIGNED_BYTE
	 *	@param[in] p_src_data is pointer to source image data
	 *
	 *	@note The caller must make sure this texture is bound before calling this function.
	 *	@note This potentially changes texture size but only if <tt>n_mip_level</tt> is zero.
	 *	@note This never changes texture filtering options (even if the mip-chain is re-built).
	 *	@note Call \ref b_Status() to find out wheter constructor succeeded.
	 */
	void TexImage(int n_width, int n_layer_num, int n_mip_level, GLenum n_internal_format,
		bool b_redo_mipmaps, GLenum n_format, GLenum n_data_type, const void *p_src_data);

	inline int n_Width() const { return m_n_width; }
	inline int n_Layer_Num() const { return m_n_layer_num; }
};

class CGLTexture_2D_Array : public CGLTexture_3D_Base {
protected:
	int m_n_width;
	int m_n_height;
	int m_n_layer_num;

public:
	/**
	 *	@brief default constructor
	 *
	 *	@param[in] n_width is texture width, in pixels
	 *	@param[in] n_height is texture height, in pixels
	 *	@param[in] n_layer_num is number of texture layers
	 *	@param[in] n_internal_format is internal format, e.g. \ref GL_RGBA8
	 *	@param[in] b_create_mipmaps is mipmap creation flag (if set, the mipmaps are allocated,
	 *		the mip chain is built and the minification filter is set to \ref GL_LINEAR_MIPMAP_LINEAR;
	 *		otherwise the minification filter is set to \ref GL_LINEAR)
	 *	@param[in] n_format is bitmap pixel format, e.f. \ref GL_RGBA
	 *	@param[in] n_data_type is bitmap data type, e.f. \ref GL_UNSIGNED_BYTE
	 *	@param[in] p_src_data is pointer to source image data (if null, the texture contents
	 *		are not specified)
	 *
	 *	@note Call \ref b_Status() to find out wheter constructor succeeded.
	 *	@note This calls glGetError() and so it fails in case there are some
	 *		uncaught errors despite texture creation is successful.
	 */
	CGLTexture_2D_Array(int n_width, int n_height, int n_layer_num,
		GLenum n_internal_format, bool b_create_mipmaps = true,
		GLenum n_format = GL_RGB, GLenum n_data_type = GL_UNSIGNED_BYTE,
		const void *p_src_data = 0);

	/**
	 *	@brief texture image re-specification; deletes the old content, potentially changes texture size
	 *
	 *	@param[in] n_width is texture width, in pixels
	 *	@param[in] n_height is texture height, in pixels
	 *	@param[in] n_layer_num is number of texture layers
	 *	@param[in] n_internal_format is internal format, e.g. \ref GL_RGBA8
	 *	@param[in] b_redo_mipmaps is mipmap refresh flag (if set, the the mip
	 *		chain is re-built; otherwise nothing is done; note that this does not
	 *		affect the minification filter setting for this texture)
	 *	@param[in] n_format is bitmap pixel format, e.f. \ref GL_RGBA
	 *	@param[in] n_data_type is bitmap data type, e.f. \ref GL_UNSIGNED_BYTE
	 *	@param[in] p_src_data is pointer to source image data
	 *
	 *	@note The caller must make sure this texture is bound before calling this function.
	 *	@note This potentially changes texture size.
	 *	@note This never changes texture filtering options (even if the mip-chain is re-built).
	 *	@note Call \ref b_Status() to find out wheter constructor succeeded.
	 */
	void TexImage(int n_width, int n_height, int n_layer_num, GLenum n_internal_format,
		bool b_redo_mipmaps, GLenum n_format, GLenum n_data_type, const void *p_src_data);

	/**
	 *	@brief texture image re-specification; deletes the old content, potentially changes texture size
	 *
	 *	@param[in] n_width is texture width, in pixels
	 *	@param[in] n_height is texture height, in pixels
	 *	@param[in] n_layer_num is number of texture layers
	 *	@param[in] n_mip_level is level in the mip-map chain (base level is 0)
	 *	@param[in] n_internal_format is internal format, e.g. \ref GL_RGBA8
	 *	@param[in] b_redo_mipmaps is mipmap refresh flag (if set, the the mip
	 *		chain is re-built; otherwise nothing is done; note that this does not
	 *		affect the minification filter setting for this texture)
	 *	@param[in] n_format is bitmap pixel format, e.f. \ref GL_RGBA
	 *	@param[in] n_data_type is bitmap data type, e.f. \ref GL_UNSIGNED_BYTE
	 *	@param[in] p_src_data is pointer to source image data
	 *
	 *	@note The caller must make sure this texture is bound before calling this function.
	 *	@note This potentially changes texture size but only if <tt>n_mip_level</tt> is zero.
	 *	@note This never changes texture filtering options (even if the mip-chain is re-built).
	 *	@note Call \ref b_Status() to find out wheter constructor succeeded.
	 */
	void TexImage(int n_width, int n_height, int n_layer_num, int n_mip_level,
		GLenum n_internal_format, bool b_redo_mipmaps, GLenum n_format,
		GLenum n_data_type, const void *p_src_data);

	inline int n_Width() const { return m_n_width; }
	inline int n_Height() const { return m_n_height; }
	inline int n_Layer_Num() const { return m_n_layer_num; }
};

class CGLTexture_Cube : public CGLTexture {
protected:
	static const GLenum p_cube_face[6];
	int m_n_width;

public:
	/**
	 *	@brief default constructor
	 *
	 *	@param[in] n_width is texture width (and height), in pixels
	 *	@param[in] n_internal_format is internal format, e.g. \ref GL_RGBA8
	 *	@param[in] b_create_mipmaps is mipmap creation flag (if set, the mipmaps are allocated,
	 *		the mip chain is built and the minification filter is set to \ref GL_LINEAR_MIPMAP_LINEAR;
	 *		otherwise the minification filter is set to \ref GL_LINEAR)
	 *	@param[in] b_software_mipmaps is mipmap creation flag (currently ignored, was meant to create
	 *		seamless mip-maps but this is now supported in hardware)
	 *	@param[in] n_format is bitmap pixel format, e.f. \ref GL_RGBA
	 *	@param[in] n_data_type is bitmap data type, e.f. \ref GL_UNSIGNED_BYTE
	 *	@param[in] p_src_data is array of six pointers to source image data (if null,
	 *		the texture contents are not specified)
	 *
	 *	@note Call \ref b_Status() to find out wheter constructor succeeded.
	 *	@note This calls glGetError() and so it fails in case there are some
	 *		uncaught errors despite texture creation is successful.
	 */
	CGLTexture_Cube(int n_width, GLenum n_internal_format,
		bool b_create_mipmaps = true, bool b_software_mipmaps = false,
		GLenum n_format = GL_RGB, GLenum n_data_type = GL_UNSIGNED_BYTE,
		const void *p_src_data[6] = 0);

	/**
	 *	@brief texture image re-specification; deletes the old content, potentially changes texture size
	 *
	 *	@param[in] n_width is texture width (and height), in pixels
	 *	@param[in] n_face is texture cube face being specified (one of GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
	 *		GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
	 *		GL_TEXTURE_CUBE_MAP_NEGATIVE_Z or GL_TEXTURE_CUBE_MAP_POSITIVE_Z)
	 *	@param[in] n_internal_format is internal format, e.g. \ref GL_RGBA8
	 *	@param[in] b_redo_mipmaps is mipmap refresh flag (if set, the the mip
	 *		chain is re-built; otherwise nothing is done; note that this does not
	 *		affect the minification filter setting for this texture)
	 *	@param[in] n_format is bitmap pixel format, e.f. \ref GL_RGBA
	 *	@param[in] n_data_type is bitmap data type, e.f. \ref GL_UNSIGNED_BYTE
	 *	@param[in] p_src_data is pointer to source image data
	 *
	 *	@note The caller must make sure this texture is bound before calling this function.
	 *	@note This potentially changes texture size.
	 *	@note This never changes texture filtering options (even if the mip-chain is re-built).
	 *	@note Call \ref b_Status() to find out wheter constructor succeeded.
	 */
	void TexImage(int n_width, GLenum n_face, GLenum n_internal_format,
		bool b_redo_mipmaps, GLenum n_format, GLenum n_data_type, const void *p_src_data);

	/**
	 *	@brief texture image re-specification; deletes the old content, potentially changes texture size
	 *
	 *	@param[in] n_width is texture width (and height), in pixels
	 *	@param[in] n_face is texture cube face being specified (one of GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
	 *		GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
	 *		GL_TEXTURE_CUBE_MAP_NEGATIVE_Z or GL_TEXTURE_CUBE_MAP_POSITIVE_Z)
	 *	@param[in] n_mip_level is level in the mip-map chain (base level is 0)
	 *	@param[in] n_internal_format is internal format, e.g. \ref GL_RGBA8
	 *	@param[in] b_redo_mipmaps is mipmap refresh flag (if set, the the mip
	 *		chain is re-built; otherwise nothing is done; note that this does not
	 *		affect the minification filter setting for this texture)
	 *	@param[in] n_format is bitmap pixel format, e.f. \ref GL_RGBA
	 *	@param[in] n_data_type is bitmap data type, e.f. \ref GL_UNSIGNED_BYTE
	 *	@param[in] p_src_data is pointer to source image data
	 *
	 *	@note The caller must make sure this texture is bound before calling this function.
	 *	@note This potentially changes texture size but only if <tt>n_mip_level</tt> is zero.
	 *	@note This never changes texture filtering options (even if the mip-chain is re-built).
	 *	@note Call \ref b_Status() to find out wheter constructor succeeded.
	 */
	void TexImage(int n_width, GLenum n_face, int n_mip_level, GLenum n_internal_format,
		bool b_redo_mipmaps, GLenum n_format, GLenum n_data_type, const void *p_src_data);

	inline int n_Width() const { return m_n_width; }
	inline int n_Height() const { return m_n_width; }
	inline int n_Depth() const { return m_n_width; }
};

#endif // !__TEXTURE_MANAGER4_INCLUDED
