/*
								+---------------------------------+
								|                                 |
								| ***   OpenGL 2.0 textures   *** |
								|                                 |
								|  Copyright  © -tHE SWINe- 2006  |
								|                                 |
								|           Texture.cpp           |
								|                                 |
								+---------------------------------+
*/

/**
 *	@file gl2/Texture.cpp
 *	@date 2006
 *	@author -tHE SWINe-
 *	@brief OpenGL 2.0 textures
 *
 *	@date 2006-01-11
 *
 *	passed code revision
 *
 *	bool CGLTexture::b_State() const renamed to bool CGLTexture::b_Status() const
 *	(want to have unified naming over the whole OpenGL framework)
 *
 *	@date 2007-02-05
 *
 *	passed code revision
 *
 *	"static GLenum CGLTexture_Cube::p_cube_face[6]" is now
 *	"static const GLenum CGLTexture_Cube::p_cube_face[6]"
 *
 *	@date 2007-05-10
 *
 *	added CGLState::NotifyDeleteTexture() to texture destructor to prevent
 *	"unbindable" textures with id of currently bound texture which was destroyed
 *
 *	@date 2007-07-14
 *
 *	added CGLTexture_Rect class (encapsulating GL_ARB_texture_rectangle extension textures)
 *	removed target from texture constructors
 *	changed __inline to inline
 *	added comments to texture constructors
 *	changed order of texture faces in cube-map texture constructor (swapped positive and
 *	negative ones)
 *
 *	@date 2007-10-29
 *
 *	added extension support flags to CGLTextureParams so it doesn't use features that may
 *	not be supported on older hardware. this applies to CGLTextureParams::UpdateState which
 *	is called everytim texture is created as well as both versions of CGLTextureParams::SetState
 *	and all other CGLTextureParams::Set_* functions
 *
 *	note extensions are determined in CGLTextureParams constructors as there could be more
 *	contexts with different capabilities (but the operation is quite fast, on new machines
 *	it should reduce to conversion of gl version string to number and several comparisons)
 *
 *	added texture state caching to all CGLTextureParams::Set_* functions
 *
 *	removed texture target from all CGLTextureParams functions, target is now set via
 *	CGLTextureParams constructor or CGLTextureParams::SetTarget. reason was awkward construct
 *	CTexture::r_Params(CGLState*).Set_*(value, CTexture::n_Target()) which required passing target
 *	as second parameter and was quite error prone because different target could be easily
 *	supplied by mistake
 *
 *	added support for anisotropic filtering to CGLTextureParams
 *
 *	@date 2007-11-09
 *
 *	texture extension checking is conditional when GL_STATE_SINGLE_CONTEXT_ONLY is defined
 *	so texture constructors aren't slowed-down anymore
 *
 *	@date 2007-11-10
 *
 *	improved linux compatibility
 *
 *	@date 2008-08-08
 *
 *	added \#ifdef for windows 64
 *
 *	@date 2009-05-03
 *
 *	added CGLTexture::n_Max_Size() static function
 *
 *	@date 2009-05-04
 *
 *	fixed mixed windows / linux line endings
 *
 *	using glTexParameterf() instead of glTexParameteri() for setting GL_TEXTURE_MAX_ANISOTROPY_EXT
 *
 *	@date 2009-10-20
 *
 *	added assertions to check if internal format and format, passed to glTexImage* corresponds.
 *	for example, if creating texture with internal format GL_DEPTH_COMPONENT16 while format
 *	is GL_RGBA (default), OpenGL error is generated, even if no texture data are supplied.
 *	this will hopefully save some headaches.
 *
 *	fixed some warnings when compiling under VC 2005, implemented "Security
 *	Enhancements in the CRT" for VC 2008. compare against MyProjects_2009-10-19_
 *
 *	@date 2010-02-06
 *
 *	changed behavior of CGLTextureParams::Set_*() where value if target isn't set to internal variable,
 *	if target isn't supported.
 *
 *	improved compatibility of CGLTexture_* constructors, they caused errors in systems where
 *	GL_SGIS_generate_mipmap (or it's core variant) wasn't supported
 *
 */

#include "../NewFix.h"

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

/*
 *								=== CGLTextureParams ===
 */

const float CGLTextureParams::m_f_compare_epsilon = 1e-3f;

#ifdef GL_STATE_SINGLE_CONTEXT_ONLY
int CGLTextureParams::m_n_support_flags = 0;
#endif // GL_STATE_SINGLE_CONTEXT_ONLY

/*
 *	CGLTextureParams::CGLTextureParams(GLenum n_target = GL_TEXTURE_2D)
 *		- default constructor
 *		- fill itself with default texture parameters
 */
CGLTextureParams::CGLTextureParams(GLenum n_target)
	:m_n_target(n_target), m_n_minify_filter(GL_NEAREST_MIPMAP_LINEAR),
	m_n_magnify_filter(GL_LINEAR), m_f_priority(1), m_f_min_lod(-1000), m_f_max_lod(1000),
	m_f_lod_bias(0), m_n_base_level(0), m_n_max_level(1000), m_n_depth_mode(GL_LUMINANCE),
	m_n_compare_mode(GL_NONE), m_n_compare_func(GL_LEQUAL), m_f_anisotropy(1),
	m_b_generate_mipmap(false)
{
	__FuncGuard("CGLTextureParams::CGLTextureParams");

	m_n_wrap_mode[coord_S] = GL_REPEAT;
	m_n_wrap_mode[coord_T] = GL_REPEAT;
	m_n_wrap_mode[coord_R] = GL_REPEAT;
	m_p_border_color[0] = 0;
	m_p_border_color[1] = 0;
	m_p_border_color[2] = 0;
	m_p_border_color[3] = 0;

#ifdef GL_STATE_SINGLE_CONTEXT_ONLY
	if(!m_n_support_flags)
#endif // GL_STATE_SINGLE_CONTEXT_ONLY
	{ // this code is conditional for single-context builds to run only once
		m_n_support_flags = support_InitFlag;
		int n_gl_version = CGLExtensionHandler::n_OpenGL_Version();
		if(n_gl_version >= 12 || CGLExtensionHandler::b_SupportedExtension("GL_EXT_texture3D"))
			m_n_support_flags |= support_EXT_Tex3D;
		if(n_gl_version >= 12 || CGLExtensionHandler::b_SupportedExtension("GL_SGIS_texture_lod"))
			m_n_support_flags |= support_SGIS_TexLod;
		if(n_gl_version >= 14 || CGLExtensionHandler::b_SupportedExtension("GL_EXT_texture_lod_bias"))
			m_n_support_flags |= support_EXT_LodBias;
		if(n_gl_version >= 14 || CGLExtensionHandler::b_SupportedExtension("GL_ARB_depth_texture"))
			m_n_support_flags |= support_ARB_DepthTex;
		if(n_gl_version >= 14 || CGLExtensionHandler::b_SupportedExtension("GL_ARB_shadow"))
			m_n_support_flags |= support_ARB_Shadow;
		if(n_gl_version >= 14 || CGLExtensionHandler::b_SupportedExtension("GL_SGIS_generate_mipmap"))
			m_n_support_flags |= support_SGIS_MipMap;
		if(CGLExtensionHandler::b_SupportedExtension("GL_EXT_texture_filter_anisotropic"))
			m_n_support_flags |= support_EXT_FilterAniso;
		// set OpenGL extension support flags
	}
}

/*
 *	void CGLTextureParams::SetTarget(GLenum n_target = GL_TEXTURE_2D)
 *		- sets texture target (default value is GL_TEXTURE_2D)
 *		  so it doesn't need to be passed to functions below
 */
void CGLTextureParams::SetTarget(GLenum n_target)
{
	m_n_target = n_target;
}

/*
 *	void CGLTextureParams::UpdateState()
 *		- get texture parameters from OpenGL
 *		- note texture must be bound and enabled
 *		- OpenGL error(s) may be generated, call glGetError() afterwards
 */
void CGLTextureParams::UpdateState()
{
	__FuncGuard("CGLTextureParams::UpdateState");

	glGetTexParameteriv(m_n_target, GL_TEXTURE_WRAP_S, (int*)&m_n_wrap_mode[coord_S]);
	glGetTexParameteriv(m_n_target, GL_TEXTURE_WRAP_T, (int*)&m_n_wrap_mode[coord_T]);
	if(m_n_support_flags & support_EXT_Tex3D)
		glGetTexParameteriv(m_n_target, GL_TEXTURE_WRAP_R, (int*)&m_n_wrap_mode[coord_R]);
	else
		m_n_wrap_mode[coord_R] = GL_REPEAT;
	glGetTexParameteriv(m_n_target, GL_TEXTURE_MIN_FILTER, (int*)&m_n_minify_filter);
	glGetTexParameteriv(m_n_target, GL_TEXTURE_MAG_FILTER, (int*)&m_n_magnify_filter);
	glGetTexParameterfv(m_n_target, GL_TEXTURE_BORDER_COLOR, m_p_border_color);
	glGetTexParameterfv(m_n_target, GL_TEXTURE_PRIORITY, &m_f_priority);
	if(m_n_support_flags & support_SGIS_TexLod) {
		glGetTexParameterfv(m_n_target, GL_TEXTURE_MIN_LOD, &m_f_min_lod);
		glGetTexParameterfv(m_n_target, GL_TEXTURE_MAX_LOD, &m_f_max_lod);
		glGetTexParameteriv(m_n_target, GL_TEXTURE_BASE_LEVEL, &m_n_base_level);
		glGetTexParameteriv(m_n_target, GL_TEXTURE_MAX_LEVEL, &m_n_max_level);
	} else {
		m_f_min_lod = -1000;
		m_f_max_lod = 1000;
		m_n_base_level = 0;
		m_n_max_level = 1000;
	}
	if(m_n_support_flags & support_EXT_LodBias)
		glGetTexParameterfv(m_n_target, GL_TEXTURE_LOD_BIAS, &m_f_lod_bias);
	else
		m_f_lod_bias = 0;
	if(m_n_support_flags & support_ARB_DepthTex)
		glGetTexParameteriv(m_n_target, GL_DEPTH_TEXTURE_MODE, (int*)&m_n_depth_mode);
	else
		m_n_depth_mode = GL_LUMINANCE;
	if(m_n_support_flags & support_ARB_Shadow) {
		glGetTexParameteriv(m_n_target, GL_TEXTURE_COMPARE_MODE, (int*)&m_n_compare_mode);
		glGetTexParameteriv(m_n_target, GL_TEXTURE_COMPARE_FUNC, (int*)&m_n_compare_func);
	} else {
		m_n_compare_mode = GL_NONE;
		m_n_compare_func = GL_LEQUAL; // f_ixme?
	}
	if(m_n_support_flags & support_SGIS_MipMap) {
		int n_temp;
		glGetTexParameteriv(m_n_target, GL_GENERATE_MIPMAP, &n_temp); // note this requires OpenGL 1.4 or GL_SGIS_generate_mipmap
		m_b_generate_mipmap = (n_temp == GL_TRUE);
	} else
		m_b_generate_mipmap = false;
	if(m_n_support_flags & support_EXT_FilterAniso) {
		glGetTexParameterfv(m_n_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, &m_f_anisotropy);
	} else
		m_f_anisotropy = 1;
}

/*
 *	void CGLTextureParams::SetState() const
 *		- set texture parameters to OpenGL
 *		- note texture must be bound and enabled
 *		- OpenGL error(s) may be generated, call glGetError() afterwards
 */
void CGLTextureParams::SetState() const
{
	__FuncGuard("CGLTextureParams::SetState");

	glTexParameteri(m_n_target, GL_TEXTURE_WRAP_S, m_n_wrap_mode[coord_S]);
	glTexParameteri(m_n_target, GL_TEXTURE_WRAP_T, m_n_wrap_mode[coord_T]);
	if(m_n_support_flags & support_EXT_Tex3D)
		glTexParameteri(m_n_target, GL_TEXTURE_WRAP_R, m_n_wrap_mode[coord_R]);
	glTexParameteri(m_n_target, GL_TEXTURE_MIN_FILTER, m_n_minify_filter);
	glTexParameteri(m_n_target, GL_TEXTURE_MAG_FILTER, m_n_magnify_filter);
	glTexParameterfv(m_n_target, GL_TEXTURE_BORDER_COLOR, m_p_border_color);
	glTexParameterf(m_n_target, GL_TEXTURE_PRIORITY, m_f_priority);
	if(m_n_support_flags & support_SGIS_TexLod) {
		glTexParameterf(m_n_target, GL_TEXTURE_MIN_LOD, m_f_min_lod);
		glTexParameterf(m_n_target, GL_TEXTURE_MAX_LOD, m_f_max_lod);
		glTexParameteri(m_n_target, GL_TEXTURE_BASE_LEVEL, m_n_base_level);
		glTexParameteri(m_n_target, GL_TEXTURE_MAX_LEVEL, m_n_max_level);
	}
	if(m_n_support_flags & support_EXT_LodBias)
		glTexParameterf(m_n_target, GL_TEXTURE_LOD_BIAS, m_f_lod_bias);
	if(m_n_support_flags & support_ARB_DepthTex)
		glTexParameteri(m_n_target, GL_DEPTH_TEXTURE_MODE, m_n_depth_mode);
	if(m_n_support_flags & support_ARB_Shadow) {
		glTexParameteri(m_n_target, GL_TEXTURE_COMPARE_MODE, m_n_compare_mode);
		glTexParameteri(m_n_target, GL_TEXTURE_COMPARE_FUNC, m_n_compare_func);
	}
	if(m_n_support_flags & support_SGIS_MipMap)
		glTexParameteri(m_n_target, GL_GENERATE_MIPMAP, (m_b_generate_mipmap)? GL_TRUE : GL_FALSE);
	if(m_n_support_flags & support_EXT_FilterAniso)
		glTexParameterf(m_n_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, m_f_anisotropy);
}

/*
 *	void CGLTextureParams::SetState(const CGLTextureParams &r_state) const
 *		- set texture parameters different from corresponding parameters in r_state to OpenGL
 *		  (effect is the same as calling r_state.SetState() but equal values aren't set
 *		  so OpenGL call overhead is lower which should result in better performance)
 *		- note floating-point number comparison is done with epsilon = 1e-3
 *		- note texture must be bound and enabled
 *		- OpenGL error(s) may be generated, call glGetError() afterwards
 */
void CGLTextureParams::SetState(const CGLTextureParams &r_state) const
{
	__FuncGuard("CGLTextureParams::SetState");

	if(m_n_wrap_mode[coord_S] != r_state.m_n_wrap_mode[coord_S])
		glTexParameteri(m_n_target, GL_TEXTURE_WRAP_S, m_n_wrap_mode[coord_S]);
	if(m_n_wrap_mode[coord_T] != r_state.m_n_wrap_mode[coord_T])
		glTexParameteri(m_n_target, GL_TEXTURE_WRAP_T, m_n_wrap_mode[coord_T]);
	if((m_n_support_flags & support_EXT_Tex3D) &&
	   m_n_wrap_mode[coord_R] != r_state.m_n_wrap_mode[coord_R])
		glTexParameteri(m_n_target, GL_TEXTURE_WRAP_R, m_n_wrap_mode[coord_R]);
	if(m_n_minify_filter != r_state.m_n_minify_filter)
		glTexParameteri(m_n_target, GL_TEXTURE_MIN_FILTER, m_n_minify_filter);
	if(m_n_magnify_filter != r_state.m_n_magnify_filter)
		glTexParameteri(m_n_target, GL_TEXTURE_MAG_FILTER, m_n_magnify_filter);
	if(fabs(m_p_border_color[0] - r_state.m_p_border_color[0]) > m_f_compare_epsilon ||
	   fabs(m_p_border_color[1] - r_state.m_p_border_color[1]) > m_f_compare_epsilon ||
	   fabs(m_p_border_color[2] - r_state.m_p_border_color[2]) > m_f_compare_epsilon ||
	   fabs(m_p_border_color[3] - r_state.m_p_border_color[3]) > m_f_compare_epsilon)
		glTexParameterfv(m_n_target, GL_TEXTURE_BORDER_COLOR, m_p_border_color);
	if(fabs(m_f_priority - r_state.m_f_priority) > m_f_compare_epsilon)
		glTexParameterf(m_n_target, GL_TEXTURE_PRIORITY, m_f_priority);
	if(m_n_support_flags & support_SGIS_TexLod) {
		if(fabs(m_f_min_lod - r_state.m_f_min_lod) > m_f_compare_epsilon)
			glTexParameterf(m_n_target, GL_TEXTURE_MIN_LOD, m_f_min_lod);
		if(fabs(m_f_max_lod - r_state.m_f_max_lod) > m_f_compare_epsilon)
			glTexParameterf(m_n_target, GL_TEXTURE_MAX_LOD, m_f_max_lod);
		if(m_n_max_level != r_state.m_n_max_level)
			glTexParameteri(m_n_target, GL_TEXTURE_MAX_LEVEL, m_n_max_level);
		if(m_n_base_level != r_state.m_n_base_level)
			glTexParameteri(m_n_target, GL_TEXTURE_BASE_LEVEL, m_n_base_level);
	}
	if((m_n_support_flags & support_EXT_LodBias) &&
	   fabs(m_f_lod_bias - r_state.m_f_lod_bias) > m_f_compare_epsilon)
		glTexParameterf(m_n_target, GL_TEXTURE_LOD_BIAS, m_f_lod_bias);
	if((m_n_support_flags & support_ARB_DepthTex) &&
	   m_n_depth_mode != r_state.m_n_depth_mode)
		glTexParameteri(m_n_target, GL_DEPTH_TEXTURE_MODE, m_n_depth_mode);
	if(m_n_support_flags & support_ARB_Shadow) {
		if(m_n_compare_mode != r_state.m_n_compare_mode)
			glTexParameteri(m_n_target, GL_TEXTURE_COMPARE_MODE, m_n_compare_mode);
		if(m_n_compare_func != r_state.m_n_compare_func)
			glTexParameteri(m_n_target, GL_TEXTURE_COMPARE_FUNC, m_n_compare_func);
	}
	if((m_n_support_flags & support_SGIS_MipMap) &&
	   m_b_generate_mipmap != r_state.m_b_generate_mipmap)
		glTexParameteri(m_n_target, GL_GENERATE_MIPMAP, (m_b_generate_mipmap)? GL_TRUE : GL_FALSE);
	if((m_n_support_flags & support_EXT_FilterAniso) &&
	   fabs(m_f_anisotropy - r_state.m_f_anisotropy) > m_f_compare_epsilon)
		glTexParameterf(m_n_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, m_f_anisotropy);
}

/*
 *	bool CGLTextureParams::operator ==(const CGLTextureParams &r_state) const
 *		- compare two texture parameters objects, return true if equal, otherwise false
 *		- does no changes to OpenGL state, needs no particular state nor generates any errors
 *		- note floating-point number comparison is done with epsilon = 1e-3
 */
bool CGLTextureParams::operator ==(const CGLTextureParams &r_state) const
{
	__FuncGuard("CGLTextureParams::operator ==");

	if(m_n_wrap_mode[coord_S] != r_state.m_n_wrap_mode[coord_S] ||
	   m_n_wrap_mode[coord_T] != r_state.m_n_wrap_mode[coord_T] ||
	   m_n_wrap_mode[coord_R] != r_state.m_n_wrap_mode[coord_R] ||
	   m_n_minify_filter != r_state.m_n_minify_filter ||
	   m_n_magnify_filter != r_state.m_n_magnify_filter ||
	   m_n_max_level != r_state.m_n_max_level ||
	   m_n_base_level != r_state.m_n_base_level ||
	   m_n_depth_mode != r_state.m_n_depth_mode ||
	   m_n_compare_mode != r_state.m_n_compare_mode ||
	   m_n_compare_func != r_state.m_n_compare_func ||
	   m_b_generate_mipmap != r_state.m_b_generate_mipmap)
		return false;
	if(fabs(m_f_lod_bias - r_state.m_f_lod_bias) > m_f_compare_epsilon ||
	   fabs(m_f_priority - r_state.m_f_priority) > m_f_compare_epsilon ||
	   fabs(m_f_min_lod - r_state.m_f_min_lod) > m_f_compare_epsilon ||
	   fabs(m_f_max_lod - r_state.m_f_max_lod) > m_f_compare_epsilon ||
	   fabs(m_p_border_color[0] - r_state.m_p_border_color[0]) > m_f_compare_epsilon ||
	   fabs(m_p_border_color[1] - r_state.m_p_border_color[1]) > m_f_compare_epsilon ||
	   fabs(m_p_border_color[2] - r_state.m_p_border_color[2]) > m_f_compare_epsilon ||
	   fabs(m_p_border_color[3] - r_state.m_p_border_color[3]) > m_f_compare_epsilon ||
	   fabs(m_f_anisotropy - r_state.m_f_anisotropy) > m_f_compare_epsilon)
		return false;
	return true;
}

void CGLTextureParams::Set_Texture_Wrap_S(GLenum n_wrap_mode)
{
	if(m_n_wrap_mode[coord_S] != n_wrap_mode) {
		glTexParameteri(m_n_target, GL_TEXTURE_WRAP_S, n_wrap_mode);
		m_n_wrap_mode[coord_S] = n_wrap_mode;
	}
}

void CGLTextureParams::Set_Texture_Wrap_T(GLenum n_wrap_mode)
{
	if(m_n_wrap_mode[coord_T] != n_wrap_mode) {
		glTexParameteri(m_n_target, GL_TEXTURE_WRAP_T, n_wrap_mode);
		m_n_wrap_mode[coord_T] = n_wrap_mode;
	}
}

void CGLTextureParams::Set_Texture_Wrap_R(GLenum n_wrap_mode)
{
	if(m_n_wrap_mode[coord_R] != n_wrap_mode) {
		if(m_n_support_flags & support_EXT_Tex3D) {
			glTexParameteri(m_n_target, GL_TEXTURE_WRAP_R, n_wrap_mode);
			m_n_wrap_mode[coord_R] = n_wrap_mode;
		}
	}
}

void CGLTextureParams::Set_Texture_Min_Filter(GLenum n_minify_filter)
{
	if(m_n_minify_filter != n_minify_filter) {
		glTexParameteri(m_n_target, GL_TEXTURE_MIN_FILTER, n_minify_filter);
		m_n_minify_filter = n_minify_filter;
	}
}

void CGLTextureParams::Set_Texture_Mag_Filter(GLenum n_magnify_filter)
{
	if(m_n_magnify_filter != n_magnify_filter) {
		glTexParameteri(m_n_target, GL_TEXTURE_MAG_FILTER, n_magnify_filter);
		m_n_magnify_filter = n_magnify_filter;
	}
}

void CGLTextureParams::Set_Texture_Border_Color(const float *p_border_color)
{
	if(memcmp(m_p_border_color, p_border_color, 4 * sizeof(float))) {
		glTexParameterfv(m_n_target, GL_TEXTURE_BORDER_COLOR, p_border_color);
		memcpy(m_p_border_color, p_border_color, 4 * sizeof(float));
	}
}

void CGLTextureParams::Set_Texture_Priority(float f_priority)
{
	if(m_f_priority != f_priority) {
		glTexParameterf(m_n_target, GL_TEXTURE_PRIORITY, f_priority);
		m_f_priority = f_priority;
	}
}

void CGLTextureParams::Set_Texture_Min_LOD(float f_min_lod)
{
	if(m_f_min_lod != f_min_lod) {
		if(m_n_support_flags & support_SGIS_TexLod) {
			glTexParameterf(m_n_target, GL_TEXTURE_MIN_LOD, f_min_lod);
			m_f_min_lod = f_min_lod;
		}
	}
}

void CGLTextureParams::Set_Texture_Max_LOD(float f_max_lod)
{
	if(m_f_max_lod != f_max_lod) {
		if(m_n_support_flags & support_SGIS_TexLod) {
			glTexParameterf(m_n_target, GL_TEXTURE_MAX_LOD, f_max_lod);
			m_f_max_lod = f_max_lod;
		}
	}
}

void CGLTextureParams::Set_Texture_Base_Level(int n_base_level)
{
	if(m_n_base_level != n_base_level) {
		if(m_n_support_flags & support_SGIS_TexLod) {
			glTexParameteri(m_n_target, GL_TEXTURE_BASE_LEVEL, n_base_level);
			m_n_base_level = n_base_level;
		}
	}
}

void CGLTextureParams::Set_Texture_Max_Level(int n_max_level)
{
	if(m_n_max_level != n_max_level) {
		if(m_n_support_flags & support_SGIS_TexLod) {
			glTexParameteri(m_n_target, GL_TEXTURE_MAX_LEVEL, n_max_level);
			m_n_max_level = n_max_level;
		}
	}
}

void CGLTextureParams::Set_Texture_LOD_Bias(float f_lod_bias)
{
	if(m_f_lod_bias != f_lod_bias) {
		if(m_n_support_flags & support_EXT_LodBias) {
			glTexParameterf(m_n_target, GL_TEXTURE_LOD_BIAS, f_lod_bias);
			m_f_lod_bias = f_lod_bias;
		}
	}
}

void CGLTextureParams::Set_Depth_Texture_Mode(GLenum n_depth_mode)
{
	if(m_n_depth_mode != n_depth_mode) {
		if(m_n_support_flags & support_ARB_DepthTex) {
			glTexParameteri(m_n_target, GL_DEPTH_TEXTURE_MODE, n_depth_mode);
			m_n_depth_mode = n_depth_mode;
		}
	}
}

void CGLTextureParams::Set_Texture_Compare_Mode(GLenum n_compare_mode)
{
	if(m_n_compare_mode != n_compare_mode) {
		if(m_n_support_flags & support_ARB_Shadow) {
			glTexParameteri(m_n_target, GL_TEXTURE_COMPARE_MODE, n_compare_mode);
			m_n_compare_mode = n_compare_mode;
		}
	}
}

void CGLTextureParams::Set_Texture_Compare_Func(GLenum n_compare_func)
{
	if(m_n_compare_func != n_compare_func) {
		if(m_n_support_flags & support_ARB_Shadow) {
			glTexParameteri(m_n_target, GL_TEXTURE_COMPARE_FUNC, n_compare_func);
			m_n_compare_func = n_compare_func;
		}
	}
}

void CGLTextureParams::Set_Generate_Mipmap(bool b_generate_mipmap)
{
	if(m_b_generate_mipmap != b_generate_mipmap) {
		if(m_n_support_flags & support_SGIS_MipMap) {
			glTexParameteri(m_n_target, GL_GENERATE_MIPMAP, (b_generate_mipmap)? GL_TRUE : GL_FALSE);
			m_b_generate_mipmap = b_generate_mipmap;
		}
	}
}

void CGLTextureParams::Set_Texture_Anisotropy(float f_anisotropy)
{
	if(m_f_anisotropy != f_anisotropy) {
		if(m_n_support_flags & support_EXT_FilterAniso) {
			glTexParameterf(m_n_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, f_anisotropy);
			m_f_anisotropy = f_anisotropy;
		}
	}
}

/*
 *								=== ~CGLTextureParams ===
 */

/*
 *								=== CGLTexture ===
 */

#define Check_InternalFormat_Format(n_internal_format,n_format) do { \
	_ASSERTE(!(n_internal_format == GL_DEPTH_COMPONENT || \
		(n_internal_format >= GL_DEPTH_COMPONENT16 && \
		n_internal_format <= GL_DEPTH_COMPONENT32)) || \
		n_format == GL_DEPTH_COMPONENT); \
	_ASSERTE(!(n_internal_format == GL_DEPTH_STENCIL_EXT || \
		n_internal_format == GL_DEPTH24_STENCIL8_EXT) || \
		n_format == GL_DEPTH_STENCIL_EXT); \
	} while(false)
// if internal format is one of depth formats, then format must
// not be default GL_RGBA, even if no data is specified. same goes
// for packed depth / stencil formats. it's better to assert it,
// than wonder why glTexImage generates errors ...

/*
 *	CGLTexture::CGLTexture()
 *		- default constructor
 *		- creates no texture object
 */
/*CGLTexture::CGLTexture()
	:m_n_id(0), m_tex_parameters(0)
{
	__FuncGuard("CGLTexture::CGLTexture");
}*/

/*
 *	CGLTexture::CGLTexture(GLenum n_internal_format, GLenum n_target, int n_border_width)
 *		- constructor accepting some of texture properties
 *		- creates no texture object
 */
CGLTexture::CGLTexture(GLenum n_internal_format, GLenum n_target, int n_border_width)
	:m_n_id(0), m_n_internal_format(n_internal_format),
	m_n_target(n_target), m_n_border_width(n_border_width), m_tex_parameters(n_target)
{
	__FuncGuard("CGLTexture::CGLTexture");
}

/*
 *	CGLTexture::~CGLTexture()
 *		- default destructor
 *		- deletes OpenGL texture object in case it was created
 */
CGLTexture::~CGLTexture()
{
	__FuncGuard("CGLTexture::~CGLTexture");

	if(m_n_id) {
		glDeleteTextures(1, &m_n_id);
		CGLState::NotifyDeleteTexture(m_n_id); // !!
	}
}

/*
 *	bool CGLTexture::b_Status() const
 *		- returns true in case texture was successfuly created and can be used for texturing
 */
bool CGLTexture::b_Status() const
{
	__FuncGuard("CGLTexture::b_Status");

	return m_n_id > 0 && glIsTexture(m_n_id);
}

/*
 *	void CGLTexture::Bind(CGLState *p_state) const
 *		- binds texture object to OpenGL state as active texture in current texture unit
 */
void CGLTexture::Bind(CGLState *p_state) const
{
	__FuncGuard("CGLTexture::Bind");

	p_state->BindTexture(m_n_target, m_n_id);
}

/*
 *	void CGLTexture::Bind_Enable(CGLState *p_state) const
 *		- binds texture object to OpenGL state as active texture in current texture unit
 *		- enables application of texture target (i.e. GL_TEXTURE_2D or similar)
 */
void CGLTexture::Bind_Enable(CGLState *p_state) const
{
	__FuncGuard("CGLTexture::Bind_Enable");

	p_state->BindTexture(m_n_target, m_n_id);
	p_state->EnableTexture(m_n_target);
}

/*
 *	void CGLTexture::Disable(CGLState *p_state) const
 *		- disables application of texture target (i.e. GL_TEXTURE_2D or similar)
 */
void CGLTexture::Disable(CGLState *p_state) const
{
	__FuncGuard("CGLTexture::Disable");

	p_state->DisableTexture(m_n_target);
}

/*
 *	static int CGLTexture::n_Max_Size()
 *		- returns maximal texture size
 *		- note this involves calling glGetIntegerv()
 */
int CGLTexture::n_Max_Size()
{
	__FuncGuard("CGLTexture::n_Max_Size");

	int n_size;
	glGetIntegerv(GL_MAX_TEXTURE_SIZE, &n_size);
	return n_size;
}

/*
 *	CGLTextureParams &CGLTexture::r_Parameters(CGLState *p_state)
 *		- enables texture parameters to be changed
 *		- binds and enables texture first (necessary for OpenGL texture parameter access)
 */
CGLTextureParams &CGLTexture::r_Parameters(CGLState *p_state)
{
	__FuncGuard("CGLTexture::r_Parameters");

	m_tex_parameters.SetTarget(m_n_target);
	p_state->BindTexture(m_n_target, m_n_id);
	p_state->EnableTexture(m_n_target);
	return m_tex_parameters;
}

/*
 *								=== ~CGLTexture ===
 */

/*
 *								=== CGLTexture_1D ===
 */

/*
 *	CGLTexture_1D::CGLTexture_1D(CGLState *p_state, int n_width, GLenum n_internal_format,
 *		bool b_create_mipmaps = true, int n_border_width = 0,
 *		GLenum n_format = GL_RGB, GLenum n_data_type = GL_UNSIGNED_BYTE,
 *		const void *p_src_data = 0)
 *		- default constructor
 *		- creates one-dimensional texture of size n_width and color format n_internal format
 *		  with border n_border_width pixels wide
 *		- texture can be initialized with image of color format n_format stored in
 *		  data type n_data_type in array p_src_data
 *		- call 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::CGLTexture_1D(CGLState *p_state, int n_width, GLenum n_internal_format,
	bool b_create_mipmaps, int n_border_width,
	GLenum n_format, GLenum n_data_type, const void *p_src_data)
	:CGLTexture(n_internal_format, GL_TEXTURE_1D, n_border_width), m_n_width(n_width)
{
	__FuncGuard("CGLTexture_1D::CGLTexture_1D");

	Check_InternalFormat_Format(n_internal_format, n_format);

	glGenTextures(1, &m_n_id);
	if(m_n_id > 0) {
		p_state->EnableTexture1D();
		//p_state->DisableTexture2D();
		//p_state->DisableTexture3D();
		//p_state->DisableTextureCubeMap();

		p_state->BindTexture1D(m_n_id);

		m_tex_parameters.UpdateState();

		if(b_create_mipmaps)
			m_tex_parameters.Set_Generate_Mipmap(true); // note this requires OpenGL 1.4 or GL_SGIS_generate_mipmap

		if(!b_create_mipmaps || !m_tex_parameters.b_Generate_Mipmap()) {
			m_tex_parameters.Set_Texture_Min_Filter(GL_LINEAR);
			m_tex_parameters.Set_Texture_Mag_Filter(GL_LINEAR);
		} else {
			m_tex_parameters.Set_Texture_Min_Filter(GL_LINEAR_MIPMAP_LINEAR);
			m_tex_parameters.Set_Texture_Mag_Filter(GL_LINEAR);
		}

		glTexImage1D(m_n_target, 0, m_n_internal_format, m_n_width,
			m_n_border_width, n_format, n_data_type, (p_src_data)? p_src_data : NULL);

		if(glGetError() != GL_NO_ERROR) {
			glDeleteTextures(1, &m_n_id);
			m_n_id = 0;
		}
	}
}

/*
 *	void CGLTexture_1D::Bind(CGLState *p_state) const
 *		- binds texture object to OpenGL state as active texture in current texture unit
 */
void CGLTexture_1D::Bind(CGLState *p_state) const
{
	__FuncGuard("CGLTexture_1D::Bind");

	p_state->BindTexture1D(m_n_id);
}

/*
 *	void CGLTexture_1D::Bind_Enable(CGLState *p_state) const
 *		- binds texture object to OpenGL state as active texture in current texture unit
 *		- enables application of texture target (i.e. GL_TEXTURE_1D or similar)
 */
void CGLTexture_1D::Bind_Enable(CGLState *p_state) const
{
	__FuncGuard("CGLTexture_1D::Bind_Enable");

	p_state->EnableTexture1D();
	p_state->BindTexture1D(m_n_id);
}

/*
 *	void CGLTexture_1D::Disable(CGLState *p_state) const
 *		- disables application of texture target (i.e. GL_TEXTURE_1D or similar)
 */
void CGLTexture_1D::Disable(CGLState *p_state) const
{
	__FuncGuard("CGLTexture_1D::Disable");

	p_state->DisableTexture1D();
}

/*
 *	CGLTextureParams &CGLTexture_1D::r_Parameters(CGLState *p_state)
 *		- enables texture parameters to be changed
 *		- binds and enables texture first (necessary for OpenGL texture parameter access)
 */
CGLTextureParams &CGLTexture_1D::r_Parameters(CGLState *p_state)
{
	__FuncGuard("CGLTexture_1D::r_Parameters");

	p_state->EnableTexture1D();
	p_state->BindTexture1D(m_n_id);
	return m_tex_parameters;
}

/*
 *								=== ~CGLTexture_1D ===
 */

/*
 *								=== CGLTexture_2D ===
 */

/*
 *	CGLTexture_2D::CGLTexture_2D(CGLState *p_state, int n_width, int n_height,
 *		GLenum n_internal_format, bool b_create_mipmaps = true, int n_border_width = 0,
 *		GLenum n_format = GL_RGB, GLenum n_data_type = GL_UNSIGNED_BYTE,
 *		const void *p_src_data = 0)
 *		- default constructor
 *		- p_state is OpenGL state guard
 *		- creates two-dimensional texture of size n_width per n_height and color format
 *		  n_internal format with border n_border_width pixels wide
 *		- texture can be initialized with image of color format n_format stored in
 *		  data type n_data_type in array p_src_data
 *		- call 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::CGLTexture_2D(CGLState *p_state, int n_width, int n_height,
	GLenum n_internal_format, bool b_create_mipmaps, int n_border_width,
	GLenum n_format, GLenum n_data_type, const void *p_src_data)
	:CGLTexture(n_internal_format, GL_TEXTURE_2D, n_border_width),
	m_n_width(n_width), m_n_height(n_height)
{
	__FuncGuard("CGLTexture_2D::CGLTexture_2D");

	Check_InternalFormat_Format(n_internal_format, n_format);

	glGenTextures(1, &m_n_id);
	if(m_n_id > 0) {
		//p_state->DisableTexture1D();
		p_state->EnableTexture2D();
		//p_state->DisableTexture3D();
		//p_state->DisableTextureCubeMap();

		p_state->BindTexture2D(m_n_id);

		m_tex_parameters.UpdateState();

		if(b_create_mipmaps)
			m_tex_parameters.Set_Generate_Mipmap(true); // note this requires OpenGL 1.4 or GL_SGIS_generate_mipmap

		if(!b_create_mipmaps || !m_tex_parameters.b_Generate_Mipmap()) {
			m_tex_parameters.Set_Texture_Min_Filter(GL_LINEAR);
			m_tex_parameters.Set_Texture_Mag_Filter(GL_LINEAR);
		} else {
			m_tex_parameters.Set_Texture_Min_Filter(GL_LINEAR_MIPMAP_LINEAR);
			m_tex_parameters.Set_Texture_Mag_Filter(GL_LINEAR);
		}
		// t_odo - see if this is necessary - seems to be ok

		glTexImage2D(m_n_target, 0, m_n_internal_format, m_n_width, m_n_height,
			m_n_border_width, n_format, n_data_type, (p_src_data)? p_src_data : NULL);

		if(glGetError() != GL_NO_ERROR) {
			glDeleteTextures(1, &m_n_id);
			m_n_id = 0;
		}
	}
}

/*
 *	void CGLTexture_2D::Bind(CGLState *p_state) const
 *		- binds texture object to OpenGL state as active texture in current texture unit
 */
void CGLTexture_2D::Bind(CGLState *p_state) const
{
	__FuncGuard("CGLTexture_2D::Bind");

	p_state->BindTexture2D(m_n_id);
}

/*
 *	void CGLTexture_2D::Bind_Enable(CGLState *p_state) const
 *		- binds texture object to OpenGL state as active texture in current texture unit
 *		- enables application of texture target (i.e. GL_TEXTURE_1D or similar)
 */
void CGLTexture_2D::Bind_Enable(CGLState *p_state) const
{
	__FuncGuard("CGLTexture_2D::Bind_Enable");

	p_state->EnableTexture2D();
	p_state->BindTexture2D(m_n_id);
}

/*
 *	void CGLTexture_2D::Disable(CGLState *p_state) const
 *		- disables application of texture target (i.e. GL_TEXTURE_1D or similar)
 */
void CGLTexture_2D::Disable(CGLState *p_state) const
{
	__FuncGuard("CGLTexture_2D::Disable");

	p_state->DisableTexture2D();
}

/*
 *	CGLTextureParams &CGLTexture_2D::r_Parameters(CGLState *p_state)
 *		- enables texture parameters to be changed
 *		- binds and enables texture first (necessary for OpenGL texture parameter access)
 */
CGLTextureParams &CGLTexture_2D::r_Parameters(CGLState *p_state)
{
	__FuncGuard("CGLTexture_2D::r_Parameters");

	p_state->EnableTexture2D();
	p_state->BindTexture2D(m_n_id);

	return m_tex_parameters;
}

/*
 *								=== ~CGLTexture_2D ===
 */

/*
 *								=== CGLTexture_Rect ===
 */

/*
 *	CGLTexture_Rect::CGLTexture_Rect(CGLState *p_state, 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)
 *		- default constructor
 *		- p_state is OpenGL state guard
 *		- creates two-dimensional texture of size n_width per n_height and color format
 *		  n_internal format (no border and no mip-mapping allowed for rectangle textures)
 *		- texture can be initialized with image of color format n_format stored in
 *		  data type n_data_type in array p_src_data
 *		- call 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::CGLTexture_Rect(CGLState *p_state, int n_width, int n_height,
	GLenum n_internal_format, GLenum n_format, GLenum n_data_type, const void *p_src_data)
	:CGLTexture(n_internal_format, GL_TEXTURE_RECTANGLE_ARB, 0),
	m_n_width(n_width), m_n_height(n_height)
{
	__FuncGuard("CGLTexture_Rect::CGLTexture_Rect");

	Check_InternalFormat_Format(n_internal_format, n_format);

	glGenTextures(1, &m_n_id);
	if(m_n_id > 0) {
		//p_state->DisableTexture1D();
		p_state->EnableTextureRect();
		//p_state->DisableTexture3D();
		//p_state->DisableTextureCubeMap();

		p_state->BindTextureRect(m_n_id);

		//if(b_create_mipmaps)
		//	glTexParameteri(m_n_target, GL_GENERATE_MIPMAP, GL_TRUE); // note this requires OpenGL 1.4 or GL_SGIS_generate_mipmap

		glTexImage2D(m_n_target, 0, m_n_internal_format, m_n_width, m_n_height,
			0, n_format, n_data_type, (p_src_data)? p_src_data : NULL);

		//if(!b_create_mipmaps) {
			glTexParameteri(m_n_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
			glTexParameteri(m_n_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		/*} else {
			glTexParameteri(m_n_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
			glTexParameteri(m_n_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		}*/
		// t_odo - see if this is necessary - seems to be ok

		m_tex_parameters.UpdateState();

		if(glGetError() != GL_NO_ERROR) {
			glDeleteTextures(1, &m_n_id);
			m_n_id = 0;
		}
	}
}

/*
 *	void CGLTexture_Rect::Bind(CGLState *p_state) const
 *		- binds texture object to OpenGL state as active texture in current texture unit
 */
void CGLTexture_Rect::Bind(CGLState *p_state) const
{
	__FuncGuard("CGLTexture_Rect::Bind");

	p_state->BindTextureRect(m_n_id);
}

/*
 *	void CGLTexture_Rect::Bind_Enable(CGLState *p_state) const
 *		- binds texture object to OpenGL state as active texture in current texture unit
 *		- enables application of texture target (i.e. GL_TEXTURE_1D or similar)
 */
void CGLTexture_Rect::Bind_Enable(CGLState *p_state) const
{
	__FuncGuard("CGLTexture_Rect::Bind_Enable");

	p_state->EnableTextureRect();
	p_state->BindTextureRect(m_n_id);
}

/*
 *	void CGLTexture_Rect::Disable(CGLState *p_state) const
 *		- disables application of texture target (i.e. GL_TEXTURE_1D or similar)
 */
void CGLTexture_Rect::Disable(CGLState *p_state) const
{
	__FuncGuard("CGLTexture_Rect::Disable");

	p_state->DisableTextureRect();
}

/*
 *	CGLTextureParams &CGLTexture_Rect::r_Parameters(CGLState *p_state)
 *		- enables texture parameters to be changed
 *		- binds and enables texture first (necessary for OpenGL texture parameter access)
 */
CGLTextureParams &CGLTexture_Rect::r_Parameters(CGLState *p_state)
{
	__FuncGuard("CGLTexture_Rect::r_Parameters");

	p_state->EnableTextureRect();
	p_state->BindTextureRect(m_n_id);

	return m_tex_parameters;
}

/*
 *								=== ~CGLTexture_Rect ===
 */

/*
 *								=== CGLTexture_3D ===
 */

/*
 *	CGLTexture_3D::CGLTexture_3D(CGLState *p_state, int n_width, int n_height, int n_depth,
 *		GLenum n_internal_format, bool b_create_mipmaps = true, int n_border_width = 0,
 *		GLenum n_format = GL_RGB, GLenum n_data_type = GL_UNSIGNED_BYTE,
 *		const void *p_src_data = 0)
 *		- default constructor
 *		- p_state is OpenGL state guard
 *		- creates three-dimensional texture of size n_width per n_height per n_depth
 *		  and color format n_internal format with border n_border_width pixels wide
 *		- texture can be initialized with image of color format n_format stored in
 *		  data type n_data_type in array p_src_data
 *		- call 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::CGLTexture_3D(CGLState *p_state, int n_width, int n_height, int n_depth,
	GLenum n_internal_format, bool b_create_mipmaps, int n_border_width,
	GLenum n_format, GLenum n_data_type, const void *p_src_data)
	:CGLTexture(n_internal_format, GL_TEXTURE_3D, n_border_width),
	m_n_width(n_width), m_n_height(n_height), m_n_depth(n_depth)
{
	__FuncGuard("CGLTexture_3D::CGLTexture_3D");

	Check_InternalFormat_Format(n_internal_format, n_format);

	glGenTextures(1, &m_n_id);
	if(m_n_id > 0) {
		//p_state->DisableTexture1D();
		//p_state->DisableTexture2D();
		p_state->EnableTexture3D();
		//p_state->DisableTextureCubeMap();

		p_state->BindTexture3D(m_n_id);
		
		m_tex_parameters.UpdateState();

		if(b_create_mipmaps)
			m_tex_parameters.Set_Generate_Mipmap(true); // note this requires OpenGL 1.4 or GL_SGIS_generate_mipmap

		if(!b_create_mipmaps || !m_tex_parameters.b_Generate_Mipmap()) {
			m_tex_parameters.Set_Texture_Min_Filter(GL_LINEAR);
			m_tex_parameters.Set_Texture_Mag_Filter(GL_LINEAR);
		} else {
			m_tex_parameters.Set_Texture_Min_Filter(GL_LINEAR_MIPMAP_LINEAR);
			m_tex_parameters.Set_Texture_Mag_Filter(GL_LINEAR);
		}

		glTexImage3D(m_n_target, 0, m_n_internal_format, m_n_width, m_n_height, m_n_depth,
			m_n_border_width, n_format, n_data_type, (p_src_data)? p_src_data : NULL);

		if(glGetError() != GL_NO_ERROR) {
			glDeleteTextures(1, &m_n_id);
			m_n_id = 0;
		}
	}
}

/*
 *	void CGLTexture_3D::Bind(CGLState *p_state) const
 *		- binds texture object to OpenGL state as active texture in current texture unit
 */
void CGLTexture_3D::Bind(CGLState *p_state) const
{
	__FuncGuard("CGLTexture_3D::Bind");

	p_state->BindTexture3D(m_n_id);
}

/*
 *	void CGLTexture_3D::Bind_Enable(CGLState *p_state) const
 *		- binds texture object to OpenGL state as active texture in current texture unit
 *		- enables application of texture target (i.e. GL_TEXTURE_1D or similar)
 */
void CGLTexture_3D::Bind_Enable(CGLState *p_state) const
{
	__FuncGuard("CGLTexture_3D::Bind_Enable");

	p_state->EnableTexture3D();
	p_state->BindTexture3D(m_n_id);
}

/*
 *	void CGLTexture_3D::Disable(CGLState *p_state) const
 *		- disables application of texture target (i.e. GL_TEXTURE_1D or similar)
 */
void CGLTexture_3D::Disable(CGLState *p_state) const
{
	__FuncGuard("CGLTexture_3D::Disable");

	p_state->DisableTexture3D();
}

/*
 *	CGLTextureParams &CGLTexture_3D::r_Parameters(CGLState *p_state)
 *		- enables texture parameters to be changed
 *		- binds and enables texture first (necessary for OpenGL texture parameter access)
 */
CGLTextureParams &CGLTexture_3D::r_Parameters(CGLState *p_state)
{
	__FuncGuard("CGLTexture_3D::r_Parameters");

	p_state->EnableTexture3D();
	p_state->BindTexture3D(m_n_id);
	return m_tex_parameters;
}

/*
 *								=== ~CGLTexture_3D ===
 */

/*
 *								=== CGLTexture_Cube ===
 */

const GLenum CGLTexture_Cube::p_cube_face[6] = {
	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,
	GL_TEXTURE_CUBE_MAP_POSITIVE_Z
};

/*
 *	CGLTexture_Cube::CGLTexture_Cube(CGLState *p_state, int n_width, GLenum n_internal_format,
 *		bool b_create_mipmaps = true, bool b_software_mipmaps = false, int n_border_width = 0,
 *		GLenum n_format = GL_RGB, GLenum n_data_type = GL_UNSIGNED_BYTE,
 *		const void *p_src_data[6] = 0)
 *		- default constructor
 *		- p_state is OpenGL state guard
 *		- creates cube-map texture of size n_width per n_width per n_width
 *		  and color format n_internal format with border n_border_width pixels wide
 *		- texture can be initialized with six images image of color format n_format stored in
 *		  data type n_data_type in array p_src_data (in order x- x+ y- y+ z- z+)
 *		- call 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::CGLTexture_Cube(CGLState *p_state, int n_width, GLenum n_internal_format,
	bool b_create_mipmaps, bool b_software_mipmaps, int n_border_width,
	GLenum n_format, GLenum n_data_type, const void *p_src_data[6])
	:CGLTexture(n_internal_format, GL_TEXTURE_CUBE_MAP, n_border_width), m_n_width(n_width)
{
	__FuncGuard("CGLTexture_Cube::CGLTexture_Cube");

	Check_InternalFormat_Format(n_internal_format, n_format);

	glGenTextures(1, &m_n_id);
	if(m_n_id > 0) {
		//p_state->DisableTexture1D();
		//p_state->DisableTexture2D();
		//p_state->DisableTexture3D();
		p_state->EnableTextureCubeMap();

		p_state->BindTextureCubeMap(m_n_id);

		m_tex_parameters.UpdateState();

		if(b_create_mipmaps)
			m_tex_parameters.Set_Generate_Mipmap(true); // note this requires OpenGL 1.4 or GL_SGIS_generate_mipmap

		if(!b_create_mipmaps || !m_tex_parameters.b_Generate_Mipmap()) {
			m_tex_parameters.Set_Texture_Min_Filter(GL_LINEAR);
			m_tex_parameters.Set_Texture_Mag_Filter(GL_LINEAR);
		} else {
			m_tex_parameters.Set_Texture_Min_Filter(GL_LINEAR_MIPMAP_LINEAR);
			m_tex_parameters.Set_Texture_Mag_Filter(GL_LINEAR);
		}

		for(int i = 0; i < 6; ++ i) {
			glTexImage2D(p_cube_face[i], 0, m_n_internal_format, m_n_width, m_n_width,
				m_n_border_width, n_format, n_data_type, (p_src_data)? p_src_data[i] : NULL);
		}

		if(glGetError() != GL_NO_ERROR) {
			glDeleteTextures(1, &m_n_id);
			m_n_id = 0;
		}
	}
}

/*
 *	void CGLTexture_Cube::Bind(CGLState *p_state) const
 *		- binds texture object to OpenGL state as active texture in current texture unit
 */
void CGLTexture_Cube::Bind(CGLState *p_state) const
{
	__FuncGuard("CGLTexture_Cube::Bind");

	p_state->BindTextureCubeMap(m_n_id);
}

/*
 *	void CGLTexture_Cube::Bind_Enable(CGLState *p_state) const
 *		- binds texture object to OpenGL state as active texture in current texture unit
 *		- enables application of texture target (i.e. GL_TEXTURE_1D or similar)
 */
void CGLTexture_Cube::Bind_Enable(CGLState *p_state) const
{
	__FuncGuard("CGLTexture_Cube::Bind_Enable");

	p_state->EnableTextureCubeMap();
	p_state->BindTextureCubeMap(m_n_id);
}

/*
 *	void CGLTexture_Cube::Disable(CGLState *p_state) const
 *		- disables application of texture target (i.e. GL_TEXTURE_1D or similar)
 */
void CGLTexture_Cube::Disable(CGLState *p_state) const
{
	__FuncGuard("CGLTexture_Cube::Disable");

	p_state->DisableTextureCubeMap();
}

/*
 *	CGLTextureParams &CGLTexture_Cube::r_Parameters(CGLState *p_state)
 *		- enables texture parameters to be changed
 *		- binds and enables texture first (necessary for OpenGL texture parameter access)
 */
CGLTextureParams &CGLTexture_Cube::r_Parameters(CGLState *p_state)
{
	__FuncGuard("CGLTexture_Cube::r_Parameters");

	p_state->EnableTextureCubeMap();
	p_state->BindTextureCubeMap(m_n_id);
	return m_tex_parameters;
}

/*
 *								=== ~CGLTexture_Cube ===
 */
