/*
								+---------------------------------+
								|                                 |
								|   ***   OGL state guard   ***   |
								|                                 |
								|  Copyright  © -tHE SWINe- 2005  |
								|                                 |
								|         OpenGLState.cpp         |
								|                                 |
								+---------------------------------+
*/

/**
 *	@file gl2/OpenGLState.cpp
 *	@author -tHE SWINe-
 *	@date 2005
 *	@brief OpenGL state guard
 *
 *	@date 2006-05-16
 *
 *	passed code revision
 *
 *  integers used to store just true or false were changed to bool
 *	fixed some minor errors with stencil write-mask
 *  body of CGLState::Update_States moved to TGLState::Update where it belongs
 *
 *	@date 2006-07-15
 *
 *	modified PolygonOffset support to match OpenGL 1.1 (EXT is actualy older)
 *
 *	@date 2006-07-25
 *
 *	files GlState.cpp and GlState.h renamed to OpenGLState.cpp and OpenGLState.h
 *
 *	@date 2006-08-13
 *
 *	fixed "CallStack.h" and <vector> include order
 *
 *	@date 2006-10-12
 *
 *	minor modifications and improvements in using std::vector
 *
 *	@date 2007-02-20
 *
 *	fixed some confusing comments about functions argument values
 *
 *	@date 2007-03-06
 *
 *	removed __declspec(dllexport)
 *
 *	@date 2007-04-02
 *
 *	added support for glBlendEquation, glBlendEquationSeparate and glBlendFuncSeparate
 *	note calling one of blending functions invalidates state cache for the other ones
 *	note these functions are extensions. be sure to initialize properly them before using
 *
 *	@date 2007-05-10
 *
 *	added TexGenObjectPlane and TexGenEyePlane functions (uncached at the moment)
 *	added delete notifiaction for textures and shader / program objects
 *	added state caching for buffer objects (including delete notification)
 *	removed __fastcall calling convention as compiller wouldn't inline such a functions
 *	in release mode, losing some speed
 *
 *	@date 2007-05-16
 *
 *	TexGenObjectPlane and TexGenEyePlane is now cached as it should be
 *	removed some old TexGen_*_fv functions
 *	added couple of assertions on function parameters that can be easily confused
 *	(GL_S versus 0, GL_TEXTURE0 versus 0, etc)
 *  some integer parameters with boolean significance were changed to bool
 *
 *	@date 2007-07-16
 *
 *	fixed error in Color3f and Color3ub where alpha channel variable
 *	wasn't set to 1 as it should be according to OpenGL specs
 *
 *	@date 2007-07-29
 *
 *	found error in caching policy: texcoord eye plane, clip planes, light positions and light
 *	directions are dependent on model-view matrix in time they are set and must be invalidated
 *	once model-view matrix is changed; possible sollutions involve not to cache them or to add
 *	matix-op functions and invalidate values everytime modelview changes (which is inefficient
 *	because modelview matrix will likely be invalidated several times every frame), again and
 *	again so the choice is not to cache them
 *	renamed __MULTITEXTURE_ENABLED to GL_STATE_MULTITEXTURE_ENABLED
 *	changed behavior of multi-coord texgen*fv commands so they take multiple quadruples of floats
 *	as input and sets each texgen plane to corresponding quadruple (before they set all planes
 *	to the same single coordinate which is mostly useless)
 *
 *	@date 2007-09-25
 *
 *	deprecated support for unsigned byte colors
 *	added functions for entering constant blend color (available with imaging subset only)
 *	renamed some array members of TGLState to begin with p_ prefix
 *
 *	@date 2007-10-28
 *
 *	fixed some minor bugs that emerged on very old OpenGL implementations
 *	(debugged on S3 Trio 64V+ and OpenGL 1.2.1)
 *	don't forget to switch-off multitexturing support using GL_STATE_MULTITEXTURE_ENABLED \#define
 *	added runtime multitexture support detection to TGLState::Update() so even if
 *	GL_STATE_MULTITEXTURE_ENABLED is defined and implementation doesn't support OpenGL,
 *	application doesn't crash in case it isn't directly using multitexture functions such
 *	as ActiveTextureUnit or MultiTexCoord
 *
 *	@date 2007-10-29
 *
 *	improved linux compatibility
 *
 *	@date 2007-11-09
 *
 *	created single-context interface as in most of today's code frmabuffers win over P-Buffers
 *	so the application really don't get to have more than single context
 *	antialiassed CGLState functions
 *
 *	@date 2007-11-10
 *
 *	improved linux compatibility
 *
 *	@date 2007-12-30
 *
 *	fixed error causing null pointer dereference when all OpenGL state managers are deleted and
 *	some OpenGL object (like CGLTexture_2D) is dealocated and calls CGLState::NotifyDelete*
 *
 *	@date 2008-03-11
 *
 *	added functions CGLState::PolygonModeFront() and CGLState::PolygonModeBack()
 *
 *	@date 2008-08-08
 *
 *	added \#ifdef for windows 64
 *
 *	@date 2008-08-19
 *
 *	fixed state caching inconsistencies in CGLState::Enable() and CGLState::Disable() (stencil test
 *	and vertex / fragment program state caching was missing there)
 *	disabled vertex color caching (use GL_STATE_FORCE_COLOR_CACHING if necessary)
 *	behavior of generic Enable, Disable changed - must not be used for enabling / disabling of
 *	states that are cached by CGLState - performance feature, avoiding switch in CGLState code,
 *	followed by similar switch in OpenGL driver (use GL_STATE_CACHE_GENERIC_ENABLE_DISABLE)
 *
 *	@date 2009-05-04
 *
 *	fixed mixed windows / linux line endings
 *
 */

#include "../NewFix.h"

#include "../CallStack.h"
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <vector>
#include <algorithm>
#include "OpenGL20.h"

#if defined(_WIN32) || defined(_WIN64)
#include <GL/wglext.h>
#else // _WIN32 || _WIN64
void *wglGetCurrentDC() { return NULL; }
void *wglGetCurrentContext() { return NULL; }
void wglMakeCurrent(void *h_dc, void *h_glrc)
{
	__FuncGuard("wglMakeCurrent impostor");
	h_dc = h_glrc = 0; // dummy op so pedantic compiler shuts up
	_ASSERTE(0); // shouldn't be called under linux ... stick to single state
}
#endif // _WIN32 || _WIN64

#include "OpenGLState.h"

#if defined(_MSC_VER) && !defined(__MWERKS__) && !defined(for) && _MSC_VER <= 1200
#define for if(0) {} else for
#endif // _MSC_VER && !__MWERKS__ && !for && _MSC_VER <= 1200
// msvc 'for' scoping hack

/*
 *								=== TGLState ===
 */

/*
 *	void TGLState::Update()
 *		- read current gl-state into itself
 *		- note it may take a few milliseconds, not a candidate to be called every frame
 */
void TGLState::Update()
{
	__FuncGuard("TGLState::Update");

	_ASSERTE(glGetError() == GL_NO_ERROR);

#ifdef GL_STATE_FORCE_COLOR_CACHING
	glGetFloatv(GL_CURRENT_COLOR, p_color);
	// color
#endif // GL_STATE_FORCE_COLOR_CACHING

	b_blend = GL_TRUE == glIsEnabled(GL_BLEND);
	glGetIntegerv(GL_BLEND_SRC, (int*)&p_blend_func[0]);
	glGetIntegerv(GL_BLEND_DST, (int*)&p_blend_func[1]);
	if(/*CGLExtensionHandler::b_SupportedExtension("GL_EXT_blend_equation_separate") ||*/
	   CGLExtensionHandler::b_Support_OpenGL(2, 0) &&
	   !CGLExtensionHandler::n_GetGL20FuncPointers()) {
		glGetIntegerv(GL_BLEND_EQUATION_RGB, (int*)&p_blend_equation[0]);
		glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (int*)&p_blend_equation[1]);
	} else if(((CGLExtensionHandler::b_SupportedExtension("GL_EXT_blend_minmax") ||
	   CGLExtensionHandler::b_SupportedExtension("GL_EXT_blend_subtract")) &&
	   !CGLExtensionHandler::n_GetBlendMinMaxEXTFuncPointers()) ||
	   (CGLExtensionHandler::b_Support_OpenGL(1, 2) &&
	   !CGLExtensionHandler::n_GetGL12FuncPointers())) {
		glGetIntegerv(GL_BLEND_EQUATION, (int*)&p_blend_equation[0]);
		p_blend_equation[1] = p_blend_equation[0];
	} else
		p_blend_equation[0] = p_blend_equation[1] = (GLenum)-1;
	if(/*CGLExtensionHandler::b_SupportedExtension("GL_EXT_blend_func_separate") ||*/
	   CGLExtensionHandler::b_Support_OpenGL(1, 4) &&
	   !CGLExtensionHandler::n_GetGL14FuncPointers()) {
		glGetIntegerv(GL_BLEND_SRC_ALPHA, (int*)&p_blend_func_alpha[0]);
		glGetIntegerv(GL_BLEND_DST_ALPHA, (int*)&p_blend_func_alpha[1]);
	} else
		p_blend_func_alpha[0] = p_blend_func_alpha[1] = (GLenum)-1;
	// blending

	_ASSERTE(glGetError() == GL_NO_ERROR);

	if(CGLExtensionHandler::b_SupportedExtension("GL_ARB_imaging"))
		glGetFloatv(GL_BLEND_COLOR, p_blend_color);
	// blending color

	glGetIntegerv(GL_FRONT_FACE, (int*)&n_front_face);
	b_cull_face = GL_TRUE == glIsEnabled(GL_CULL_FACE);
	glGetIntegerv(GL_CULL_FACE_MODE, (int*)&n_cull_face);
	// face culling

	GLboolean b_tmp_quad[4];
	glGetBooleanv(GL_DEPTH_WRITEMASK, b_tmp_quad);
	b_depth_write = GL_TRUE == b_tmp_quad[0];
	glGetBooleanv(GL_COLOR_WRITEMASK, b_tmp_quad);
	p_color_write[0] = (GL_TRUE == b_tmp_quad[0]);
	p_color_write[1] = (GL_TRUE == b_tmp_quad[1]);
	p_color_write[2] = (GL_TRUE == b_tmp_quad[2]);
	p_color_write[3] = (GL_TRUE == b_tmp_quad[3]);
	glGetIntegerv(GL_STENCIL_WRITEMASK, (int*)&p_stencil_write[1]); // integer - bit mask really
	// write masks (updated - bool might not be the size of GLboolean)

	glGetFloatv(GL_COLOR_CLEAR_VALUE, p_clr_color);
	glGetDoublev(GL_DEPTH_CLEAR_VALUE, &f_clr_depth);
	glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &n_clr_stencil);
	// clear color

	b_alpha_test = GL_TRUE == glIsEnabled(GL_ALPHA_TEST);
	glGetIntegerv(GL_ALPHA_TEST_FUNC, (int*)&n_alpha_func);
	glGetFloatv(GL_ALPHA_TEST_REF, &f_alpha_tresh);
	// alpha test

	b_depth_test = GL_TRUE == glIsEnabled(GL_DEPTH_TEST);
	glGetIntegerv(GL_DEPTH_FUNC, (int*)&n_depth_func);
	// depth test

	_ASSERTE(glGetError() == GL_NO_ERROR);

	CGLExtensionHandler::n_GetGL20FuncPointers();
	b_separate_gl2_stencil =
		CGLExtensionHandler::b_Support_OpenGL(2, 0) &&
		glStencilFuncSeparate && glStencilOpSeparate && glStencilMaskSeparate;
	b_stencil_test = GL_TRUE == glIsEnabled(GL_STENCIL_TEST);
	glGetIntegerv(GL_STENCIL_FUNC, (int*)&p_stencil_func[1]);
	glGetIntegerv(GL_STENCIL_REF, &p_stencil_ref[1]);
	glGetIntegerv(GL_STENCIL_VALUE_MASK, (int*)&p_stencil_mask[1]);
	glGetIntegerv(GL_STENCIL_FAIL, (int*)&p_stencil_op_sfail[1]);
	glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, (int*)&p_stencil_op_dfail[1]);
	glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, (int*)&p_stencil_op_dpass[1]);
	if(b_separate_gl2_stencil) {
		glGetIntegerv(GL_STENCIL_BACK_FUNC, (int*)&p_stencil_func[0]);
		glGetIntegerv(GL_STENCIL_BACK_REF, &p_stencil_ref[0]);
		glGetIntegerv(GL_STENCIL_BACK_VALUE_MASK, (int*)&p_stencil_mask[0]);
		glGetIntegerv(GL_STENCIL_BACK_FAIL, (int*)&p_stencil_op_sfail[0]);
		glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_FAIL,
			(int*)&p_stencil_op_dfail[0]);
		glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_PASS,
			(int*)&p_stencil_op_dpass[0]);
		glGetIntegerv(GL_STENCIL_BACK_WRITEMASK, (int*)&p_stencil_write[0]);
	} else {
		p_stencil_func[0] = p_stencil_func[1];
		p_stencil_ref[0] = p_stencil_ref[1];
		p_stencil_mask[0] = p_stencil_mask[1];
		p_stencil_op_sfail[0] = p_stencil_op_sfail[1];
		p_stencil_op_dfail[0] = p_stencil_op_dfail[1];
		p_stencil_op_dpass[0] = p_stencil_op_dpass[1];
		p_stencil_write[0] = p_stencil_write[1];
	}
	// stencil test

	_ASSERTE(glGetError() == GL_NO_ERROR);

	bool b_multitexture_support = CGLExtensionHandler::b_Support_OpenGL(1, 3) &&
	   !CGLExtensionHandler::n_GetMultitextureFuncPointers();
	// is multitexture supported?

	if(b_multitexture_support) {
		glGetIntegerv(GL_MAX_TEXTURE_UNITS, &n_max_texture_units);
		glGetIntegerv(GL_ACTIVE_TEXTURE, &n_active_tex_unit);
		n_active_tex_unit -= GL_TEXTURE0;
		_ASSERTE(n_max_texture_units <= 32);
	} else {
		n_max_texture_units = 1;
		n_active_tex_unit = 0;
	}

	bool b_have_3d_textures = CGLExtensionHandler::b_Support_OpenGL(1, 2) ||
		CGLExtensionHandler::b_SupportedExtension("GL_EXT_texture3D");
	bool b_have_cubemap_textures = CGLExtensionHandler::b_Support_OpenGL(1, 3) ||
		CGLExtensionHandler::b_SupportedExtension("GL_ARB_texture_cube_map");
	bool b_have_rectangle_textures =
		CGLExtensionHandler::b_SupportedExtension("GL_ARB_texture_rectangle");
	for(int i = 0; i < n_max_texture_units; ++ i) {
		if(b_multitexture_support && (i || n_active_tex_unit != 0))
			glActiveTexture(GL_TEXTURE0 + i);

		p_texture1d_enabled[i] = GL_TRUE == glIsEnabled(GL_TEXTURE_1D);
		p_texture2d_enabled[i] = GL_TRUE == glIsEnabled(GL_TEXTURE_2D);
		glGetIntegerv(GL_TEXTURE_1D, (int*)&p_texture1d[i]);
		glGetIntegerv(GL_TEXTURE_2D, (int*)&p_texture2d[i]);

		if(b_have_rectangle_textures) {
			p_texture_rect_enabled[i] = GL_TRUE == glIsEnabled(GL_TEXTURE_RECTANGLE_ARB);
			glGetIntegerv(GL_TEXTURE_RECTANGLE_ARB, (int*)&p_texture_rect[i]);
		} else {
			p_texture_rect_enabled[i] = false;
			p_texture_rect[i] = 0;
		}
		if(b_have_3d_textures) {
			p_texture3d_enabled[i] = GL_TRUE == glIsEnabled(GL_TEXTURE_3D);
			glGetIntegerv(GL_TEXTURE_3D, (int*)&p_texture3d[i]);
		} else {
			p_texture3d_enabled[i] = false;
			p_texture3d[i] = 0;
		}
		if(b_have_cubemap_textures) {
			p_texture_cubemap_enabled[i] = GL_TRUE == glIsEnabled(GL_TEXTURE_CUBE_MAP);
			glGetIntegerv(GL_TEXTURE_CUBE_MAP, (int*)&p_texture_cubemap[i]);
		} else {
			p_texture_cubemap_enabled[i] = false;
			p_texture_cubemap[i] = 0;
		}
		// rect / 3d / cube textures might not be supported by some kinds of hardware
	}
	if(b_multitexture_support && n_active_tex_unit != n_max_texture_units - 1)
		glActiveTexture(n_active_tex_unit + GL_TEXTURE0);
	// texture units

	_ASSERTE(glGetError() == GL_NO_ERROR);

	b_lighting = GL_TRUE == glIsEnabled(GL_LIGHTING);
	glGetIntegerv(GL_MAX_LIGHTS, &n_max_lights);
	_ASSERTE(n_max_lights <=32);
	for(int i = 0; i < n_max_lights; ++ i) {
		p_light_enabled[i] = GL_TRUE == glIsEnabled(GL_LIGHT0 + i);

		glGetLightfv(GL_LIGHT0 + i, GL_AMBIENT, p_light_data[i].p_ambient);
		glGetLightfv(GL_LIGHT0 + i, GL_DIFFUSE, p_light_data[i].p_diffuse);
		glGetLightfv(GL_LIGHT0 + i, GL_SPECULAR, p_light_data[i].p_specular);

		/*glGetLightfv(GL_LIGHT0 + i, GL_POSITION, p_light_data[i].p_position);
		glGetLightfv(GL_LIGHT0 + i, GL_SPOT_DIRECTION, p_light_data[i].p_spot_direction);*/
		// caching disabled, depends on current modelview

		glGetLightfv(GL_LIGHT0 + i, GL_SPOT_EXPONENT, &p_light_data[i].f_spot_exponent);
		glGetLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &p_light_data[i].f_spot_cutoff);
		glGetLightfv(GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION,
			&p_light_data[i].f_constant_attenuation);
		glGetLightfv(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, &p_light_data[i].f_linear_attenuation);
		glGetLightfv(GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION,
			&p_light_data[i].f_quadratic_attenuation);
	}
	// lights
	
	_ASSERTE(glGetError() == GL_NO_ERROR);

	glGetFloatv(GL_LIGHT_MODEL_AMBIENT, p_model_ambient);
	glGetBooleanv(GL_LIGHT_MODEL_LOCAL_VIEWER, &b_model_local_viewer);
	glGetBooleanv(GL_LIGHT_MODEL_TWO_SIDE, &b_model_two_side);
	if(CGLExtensionHandler::b_SupportedExtension("EXT_separate_specular_color") ||
	   CGLExtensionHandler::b_Support_OpenGL(1, 2))
		glGetIntegerv(GL_LIGHT_MODEL_COLOR_CONTROL, (int*)&n_model_color_control);
	else
		n_model_color_control = GL_SINGLE_COLOR_EXT;
	// lighting model
	
	_ASSERTE(glGetError() == GL_NO_ERROR);

	for(int i = 0; i < 2; ++ i) {
		glGetMaterialfv((i)? GL_FRONT : GL_BACK, GL_AMBIENT, p_material_ambient[i]);
		glGetMaterialfv((i)? GL_FRONT : GL_BACK, GL_DIFFUSE, p_material_diffuse[i]);
		glGetMaterialfv((i)? GL_FRONT : GL_BACK, GL_SPECULAR, p_material_specular[i]);
		glGetMaterialfv((i)? GL_FRONT : GL_BACK, GL_EMISSION, p_material_emission[i]);
		glGetMaterialfv((i)? GL_FRONT : GL_BACK, GL_SHININESS, &p_material_shininess[i]);
	}
	// material
	
	_ASSERTE(glGetError() == GL_NO_ERROR);

	b_fog = GL_TRUE == glIsEnabled(GL_FOG);
	glGetIntegerv(GL_FOG_MODE, (int*)&n_fog_type);
	glGetFloatv(GL_FOG_COLOR, p_fog_color);
	glGetFloatv(GL_FOG_START, &f_fog_start);
	glGetFloatv(GL_FOG_DENSITY, &f_fog_density);
	glGetFloatv(GL_FOG_END, &f_fog_end);
	// fog
	
	_ASSERTE(glGetError() == GL_NO_ERROR);

	glGetIntegerv(GL_SHADE_MODEL, (int*)&n_shade_model);
	// shade model
	
	_ASSERTE(glGetError() == GL_NO_ERROR);

	glGetIntegerv(GL_POLYGON_MODE, (int*)n_polygon_mode);
	glGetFloatv(GL_LINE_WIDTH, &f_line_width);
	glGetFloatv(GL_POINT_SIZE, &f_point_size);
	// rasterizer props

	_ASSERTE(glGetError() == GL_NO_ERROR);

	for(int j = 0; j < n_max_texture_units; ++ j) {
		if(b_multitexture_support && (j || n_active_tex_unit != 0))
			glActiveTexture(j + GL_TEXTURE0);

		for(int i = 0; i < 4; ++ i) {
			p_texgen_enabled[j][i] = GL_TRUE == glIsEnabled(GL_TEXTURE_GEN_S + i);

			glGetTexGeniv(GL_S + i, GL_TEXTURE_GEN_MODE, (int*)&p_texgen_mode[j][i]);

			//glGetTexGenfv(GL_S + i, GL_EYE_PLANE, p_texgen_eye_plane[j][i]);
			// caching disabled, depends on current modelview

			glGetTexGenfv(GL_S + i, GL_OBJECT_PLANE, p_texgen_object_plane[j][i]);
		}
	}
	if(b_multitexture_support && n_active_tex_unit != n_max_texture_units - 1)
		glActiveTexture(n_active_tex_unit + GL_TEXTURE0);
	// texgen props

	_ASSERTE(glGetError() == GL_NO_ERROR);

	glGetIntegerv(GL_MAX_CLIP_PLANES, &n_max_clip_planes);
	for(int i = 0; i < n_max_clip_planes; ++ i) {
		p_clip_plane_enabled[i] = GL_TRUE == glIsEnabled(GL_CLIP_PLANE0 + i);
		//glGetClipPlane(GL_CLIP_PLANE0 + i, p_clip_plane[i]);
		// caching disabled, depends on current modelview
	}
	// clip planes

	_ASSERTE(glGetError() == GL_NO_ERROR);

	b_polygon_offset_support = CGLExtensionHandler::b_Support_OpenGL(1, 1);/*
		CGLExtensionHandler::b_SupportedExtension("GL_ARB_polygon_offset") &&
		!CGLExtensionHandler::n_GetPolygonOffsetARBFuncPointers();*/
	//
	if(b_polygon_offset_support) {
		p_polygon_offset_enabled[0] = (GL_TRUE == glIsEnabled(GL_POLYGON_OFFSET_FILL));
		p_polygon_offset_enabled[1] = (GL_TRUE == glIsEnabled(GL_POLYGON_OFFSET_LINE));
		p_polygon_offset_enabled[2] = (GL_TRUE == glIsEnabled(GL_POLYGON_OFFSET_POINT));
		f_polygon_offset_factor = 0;
		f_polygon_offset_bias = 0; // what to do?
		/*glGetFloatv(GL_POLYGON_OFFSET_FACTOR_EXT, &f_polygon_offset_factor);
		glGetFloatv(GL_POLYGON_OFFSET_BIAS_EXT, &f_polygon_offset_bias);*/
	} else {
		p_polygon_offset_enabled[0] = false;
		p_polygon_offset_enabled[1] = false;
		p_polygon_offset_enabled[2] = false;
	}

	_ASSERTE(glGetError() == GL_NO_ERROR);

	b_fragment_program_support =
		CGLExtensionHandler::b_SupportedExtension("GL_ARB_fragment_program") &&
		!CGLExtensionHandler::n_GetFragmentProgramARBFuncPointers();
	b_vertex_program_support =
		CGLExtensionHandler::b_SupportedExtension("GL_ARB_vertex_program") &&
		!CGLExtensionHandler::n_GetVertexProgramARBFuncPointers();
	if(b_vertex_program_support) {
		b_fragment_program_enabled = GL_TRUE == glIsEnabled(GL_VERTEX_PROGRAM_ARB);
		glGetIntegerv(GL_VERTEX_PROGRAM_ARB, (int*)&n_vertex_program);
	} else {
		n_vertex_program = 0;
		b_vertex_program_enabled = false;
	}
	if(b_fragment_program_support) {
		b_fragment_program_enabled = GL_TRUE == glIsEnabled(GL_FRAGMENT_PROGRAM_ARB);
		glGetIntegerv(GL_FRAGMENT_PROGRAM_ARB, (int*)&n_fragment_program);
	} else {
		n_fragment_program = 0;
		b_fragment_program_enabled = false;
	}
	// low-level shading programmability

	_ASSERTE(glGetError() == GL_NO_ERROR);

	b_shader_support =
		(CGLExtensionHandler::b_SupportedExtension("GL_ARB_fragment_shader") ||
		(CGLExtensionHandler::b_SupportedExtension("GL_ARB_vertex_shader") &&
		!CGLExtensionHandler::n_GetVertexShaderARBFuncPointers())) &&
		CGLExtensionHandler::b_SupportedExtension("GL_ARB_shader_objects") &&
		CGLExtensionHandler::b_SupportedExtension("GL_ARB_shading_language_100") &&
		!CGLExtensionHandler::n_GetShaderObjectsARBFuncPointers();
	b_shader_gl2_support =
		CGLExtensionHandler::b_Support_OpenGL(2, 0) &&
		(CGLExtensionHandler::b_SupportedExtension("GL_ARB_fragment_shader") ||
		CGLExtensionHandler::b_SupportedExtension("GL_ARB_vertex_shader")) &&
		CGLExtensionHandler::b_SupportedExtension("GL_ARB_shading_language_100") &&
		!CGLExtensionHandler::n_GetGL20FuncPointers();
	if(b_shader_gl2_support) {
		glGetIntegerv(GL_CURRENT_PROGRAM, (int*)&n_program_object);
	} else if(b_shader_support) {
		n_program_object = glGetHandleARB(GL_PROGRAM_OBJECT_ARB);
	} else
		n_program_object = 0;
	// high-level ARB shading programmability
	// high-level GL20 shading programmability

	_ASSERTE(glGetError() == GL_NO_ERROR);

	b_vertex_buffer_support =
		CGLExtensionHandler::b_SupportedExtension("GL_ARB_vertex_buffer_object") &&
		!CGLExtensionHandler::n_GetVertexBufferObjectARBFuncPointers();
	b_pixel_buffer_support = b_vertex_buffer_support &&
		CGLExtensionHandler::b_SupportedExtension("GL_ARB_pixel_buffer_object");
	if(b_vertex_buffer_support) {
		glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, (GLint*)&n_vertex_array_buffer);
		glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, (GLint*)&n_vertex_element_array_buffer);
	} else {
		n_vertex_array_buffer = 0;
		n_vertex_element_array_buffer = 0;
	}
	if(b_pixel_buffer_support) {
		glGetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING_ARB, (GLint*)&n_pixel_pack_buffer);
		glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING_ARB, (GLint*)&n_pixel_unpack_buffer);
	} else {
		n_pixel_pack_buffer = 0;
		n_pixel_unpack_buffer = 0;
	}
	// buffer objects

	_ASSERTE(glGetError() == GL_NO_ERROR);
}

/*
 *								=== ~TGLState ===
 */

/*
 *								=== CGLState ===
 */

#ifdef GL_STATE_SINGLE_CONTEXT_ONLY

TGLState *CGLState::m_p_cur_state;

CGLState::CGLState()
{
	__FuncGuard("CGLState::CGLState");

	if(!m_p_cur_state) {
		if(!(m_p_cur_state = new(std::nothrow) TGLState))
			return;
		m_p_cur_state->n_reference_num = 1;
		Update_States();
	} else
		++ m_p_cur_state->n_reference_num;
}

CGLState::~CGLState()
{
	__FuncGuard("CGLState::~CGLState");

	if(m_p_cur_state && !(-- m_p_cur_state->n_reference_num)) {
		delete m_p_cur_state;
		m_p_cur_state = 0;
	}
}

#else // GL_STATE_SINGLE_CONTEXT_ONLY

std::vector<TGLState*> *CGLState::m_p_state = 0;
int CGLState::m_n_state_reference_num = 0;

CGLState::CGLState(HDC h_dc, HGLRC h_glrc)
	:m_h_dc(h_dc), m_h_glrc(h_glrc), m_b_init(false)
{
	__FuncGuard("CGLState::CGLState");

	if(!m_p_state && !(m_p_state = new(std::nothrow) std::vector<TGLState*>)) {
		m_h_dc = 0;
		m_h_glrc = 0;
		return;
	}
	m_n_state_reference_num ++;
	// first class

	std::vector<TGLState*>::iterator p_state = std::find_if(m_p_state->begin(),
		m_p_state->end(), CFindState(h_glrc));
	// try to find state that was already set for this context

	if(p_state != m_p_state->end()) {
		m_p_cur_state = *p_state;
		m_p_cur_state->n_reference_num ++;
	} else {
		if(!(m_p_cur_state = new(std::nothrow) TGLState))
			return;

		m_p_cur_state->h_glrc = m_h_glrc;
		m_p_cur_state->n_reference_num = 1;

		if(!stl_ut::Reserve_1More(*m_p_state)) {
			delete m_p_cur_state;
			m_p_cur_state = 0;
			return;
		}
		m_p_state->push_back(m_p_cur_state);

		HDC h_prev_dc = wglGetCurrentDC();
		HGLRC h_prev_glrc = wglGetCurrentContext();
		if(h_prev_dc != m_h_dc || h_prev_glrc != m_h_glrc)
			wglMakeCurrent(m_h_dc, m_h_glrc);

		Update_States();

		if(h_prev_dc != m_h_dc || h_prev_glrc != m_h_glrc)
			wglMakeCurrent(h_prev_dc, h_prev_glrc);
	}
	// create my state and store current opengl state isnide

	m_b_init = true;
}

CGLState::~CGLState()
{
	__FuncGuard("CGLState::~CGLState");

	if(m_b_init && !(-- m_n_state_reference_num) && m_p_state) {
		std::for_each(m_p_state->begin(), m_p_state->end(), DeleteState);
		delete m_p_state;
		m_p_state = 0;
	}
}

HDC CGLState::h_DeviceContext()
{
	__FuncGuard("CGLState::h_DeviceContext");

	return m_h_dc;
}

HGLRC CGLState::h_RenderingContext()
{
	__FuncGuard("CGLState::h_RenderingContext");

	return m_h_glrc;
}


#endif // GL_STATE_SINGLE_CONTEXT_ONLY

void CGLState::Update_States()
{
	__FuncGuard("CGLState::Update_States");

	_ASSERTE(m_p_cur_state);

	m_p_cur_state->Update();

	_ASSERTE(glGetError() == GL_NO_ERROR);
}

void CGLState::LineWidth(GLfloat f_width)
{
	__FuncGuard("CGLState::LineWidth");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->f_line_width != f_width)
		glLineWidth(p_cur_state->f_line_width = f_width);
}

void CGLState::PointSize(GLfloat f_size)
{
	__FuncGuard("CGLState::PointSize");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->f_point_size != f_size)
		glPointSize(p_cur_state->f_point_size = f_size);
}

void CGLState::PolygonMode(GLenum n_side, GLenum n_mode)
{
	__FuncGuard("CGLState::PolygonMode");

	_ASSERTE(n_side == GL_FRONT_AND_BACK || n_side == GL_FRONT || n_side == GL_BACK);
	_ASSERTE(n_mode == GL_FILL || n_mode == GL_LINE || n_mode == GL_POINT);

	TGLState *p_cur_state = m_p_cur_state;
	if(n_side == GL_FRONT_AND_BACK &&
	   (n_mode != p_cur_state->n_polygon_mode[0] ||
	   n_mode != p_cur_state->n_polygon_mode[1])) {
		glPolygonMode(GL_FRONT_AND_BACK, p_cur_state->n_polygon_mode[0] =
			p_cur_state->n_polygon_mode[1] = n_mode);
	} else if(n_side == GL_FRONT &&
	   n_mode != p_cur_state->n_polygon_mode[0])
		glPolygonMode(GL_FRONT, p_cur_state->n_polygon_mode[0] = n_mode);
	else if(n_side == GL_BACK &&
	   n_mode != p_cur_state->n_polygon_mode[1])
		glPolygonMode(GL_BACK, p_cur_state->n_polygon_mode[1] = n_mode);	
}

void CGLState::PolygonModeFront(GLenum n_mode)
{
	__FuncGuard("CGLState::PolygonModeFront");

	_ASSERTE(n_mode == GL_FILL || n_mode == GL_LINE || n_mode == GL_POINT);

	TGLState *p_cur_state = m_p_cur_state;
	if(n_mode != p_cur_state->n_polygon_mode[0])
		glPolygonMode(GL_FRONT, p_cur_state->n_polygon_mode[0] = n_mode);
}

void CGLState::PolygonModeBack(GLenum n_mode)
{
	__FuncGuard("CGLState::PolygonModeBack");

	_ASSERTE(n_mode == GL_FILL || n_mode == GL_LINE || n_mode == GL_POINT);

	TGLState *p_cur_state = m_p_cur_state;
	if(n_mode != p_cur_state->n_polygon_mode[1])
		glPolygonMode(GL_BACK, p_cur_state->n_polygon_mode[1] = n_mode);
}

void CGLState::EnableFog()
{
	__FuncGuard("CGLState::EnableFog");

	TGLState *p_cur_state = m_p_cur_state;
	if(!p_cur_state->b_fog) {
		p_cur_state->b_fog = true;
		glEnable(GL_FOG);
	}
}

void CGLState::DisableFog()
{
	__FuncGuard("CGLState::DisableFog");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_fog) {
		p_cur_state->b_fog = false;
		glDisable(GL_FOG);
	}
}

void CGLState::FogMode(GLenum n_value)
{
	__FuncGuard("CGLState::FogMode");

	_ASSERTE(n_value == GL_LINEAR || n_value == GL_EXP || n_value == GL_EXP2);

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->n_fog_type != n_value)
		glFogi(GL_FOG_MODE, p_cur_state->n_fog_type = n_value);
}

void CGLState::FogDensity(GLfloat f_value)
{
	__FuncGuard("CGLState::FogDensity");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->f_fog_density != f_value)
		glFogf(GL_FOG_DENSITY, p_cur_state->f_fog_density = f_value);
}

void CGLState::FogColor(const GLfloat *p_fog_color4)
{
	__FuncGuard("CGLState::FogColor");

	TGLState *p_cur_state = m_p_cur_state;
	if(memcmp(p_cur_state->p_fog_color, p_fog_color4, 4 * sizeof(GLfloat))) {
		memcpy(p_cur_state->p_fog_color, p_fog_color4, 4 * sizeof(GLfloat));
		glFogfv(GL_FOG_COLOR, p_fog_color4);
	}
}

void CGLState::FogStart(GLfloat f_value)
{
	__FuncGuard("CGLState::FogStart");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->f_fog_start != f_value)
		glFogf(GL_FOG_START, p_cur_state->f_fog_start = f_value);
}

void CGLState::FogEnd(GLfloat f_value)
{
	__FuncGuard("CGLState::FogEnd");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->f_fog_end != f_value)
		glFogf(GL_FOG_END, p_cur_state->f_fog_end = f_value);
}

void CGLState::EnableLighting()
{
	__FuncGuard("CGLState::EnableLighting");

	TGLState *p_cur_state = m_p_cur_state;
	if(!p_cur_state->b_lighting) {
		glEnable(GL_LIGHTING);
		p_cur_state->b_lighting = true;
	}
}

void CGLState::DisableLighting()
{
	__FuncGuard("CGLState::DisableLighting");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_lighting) {
		glDisable(GL_LIGHTING);
		p_cur_state->b_lighting = false;
	}
}

void CGLState::EnableLight(int n_light)
{
	__FuncGuard("CGLState::EnableLight");

	TGLState *p_cur_state = m_p_cur_state;
	_ASSERTE(n_light >= 0 && n_light < p_cur_state->n_max_lights);

	if(!p_cur_state->p_light_enabled[n_light]) {
		glEnable(GL_LIGHT0 + n_light);
		p_cur_state->p_light_enabled[n_light] = true;
	}
}

void CGLState::DisableLight(int n_light)
{
	__FuncGuard("CGLState::DisableLight");

	TGLState *p_cur_state = m_p_cur_state;
	_ASSERTE(n_light >= 0 && n_light < p_cur_state->n_max_lights);

	if(p_cur_state->p_light_enabled[n_light]) {
		glDisable(GL_LIGHT0 + n_light);
		p_cur_state->p_light_enabled[n_light] = false;
	}
}

void CGLState::ShadeModel(GLenum n_model)
{
	__FuncGuard("CGLState::ShadeModel");

	_ASSERTE(n_model == GL_SMOOTH || n_model == GL_FLAT);

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->n_shade_model != n_model)
		glShadeModel(p_cur_state->n_shade_model = n_model);
}

void CGLState::LightAmbient(int n_light, const GLfloat *p_color4)
{
	__FuncGuard("CGLState::LightAmbient");

	TGLState *p_cur_state = m_p_cur_state;
	_ASSERTE(n_light >= 0 && n_light < p_cur_state->n_max_lights);

	if(memcmp(p_cur_state->p_light_data[n_light].p_ambient, p_color4, 4 * sizeof(GLfloat))) {
		memcpy(p_cur_state->p_light_data[n_light].p_ambient, p_color4, 4 * sizeof(GLfloat));
		glLightfv(GL_LIGHT0 + n_light, GL_AMBIENT, p_color4);
	}
}

void CGLState::LightDiffuse(int n_light, const GLfloat *p_color4)
{
	__FuncGuard("CGLState::LightDiffuse");

	TGLState *p_cur_state = m_p_cur_state;
	_ASSERTE(n_light >= 0 && n_light < p_cur_state->n_max_lights);

	if(memcmp(p_cur_state->p_light_data[n_light].p_diffuse, p_color4, 4 * sizeof(GLfloat))) {
		memcpy(p_cur_state->p_light_data[n_light].p_diffuse, p_color4, 4 * sizeof(GLfloat));
		glLightfv(GL_LIGHT0 + n_light, GL_DIFFUSE, p_color4);
	}
}

void CGLState::LightSpecular(int n_light, const GLfloat *p_color4)
{
	__FuncGuard("CGLState::LightSpecular");

	TGLState *p_cur_state = m_p_cur_state;
	_ASSERTE(n_light >= 0 && n_light < p_cur_state->n_max_lights);

	if(memcmp(p_cur_state->p_light_data[n_light].p_specular, p_color4, 4 * sizeof(GLfloat))) {
		memcpy(p_cur_state->p_light_data[n_light].p_specular, p_color4, 4 * sizeof(GLfloat));
		glLightfv(GL_LIGHT0 + n_light, GL_SPECULAR, p_color4);
	}
}

void CGLState::LightPosition(int n_light, const GLfloat *p_position4)
{
	__FuncGuard("CGLState::LightPosition");

	//TGLState *p_cur_state = m_p_cur_state;
	_ASSERTE(n_light >= 0 && n_light < m_p_cur_state->n_max_lights);

	//if(memcmp(p_cur_state->p_light_data[n_light].p_position, p_position4, 4 * sizeof(GLfloat))) {
		//memcpy(p_cur_state->p_light_data[n_light].p_position, p_position4, 4 * sizeof(GLfloat));
		glLightfv(GL_LIGHT0 + n_light, GL_POSITION, p_position4);
		// caching disabled, depends on current modelview
	//}
}

void CGLState::LightSpotDirection(int n_light, const GLfloat *p_direction3)
{
	__FuncGuard("CGLState::LightSpotDirection");

	//TGLState *p_cur_state = m_p_cur_state;
	_ASSERTE(n_light >= 0 && n_light < m_p_cur_state->n_max_lights);

	//if(memcmp(p_cur_state->p_light_data[n_light].p_spot_direction, p_direction3, 3 * sizeof(GLfloat))) {
		//memcpy(p_cur_state->p_light_data[n_light].p_spot_direction, p_direction3, 3 * sizeof(GLfloat));
		glLightfv(GL_LIGHT0 + n_light, GL_SPOT_DIRECTION, p_direction3);
		// caching disabled, depends on current modelview
	//}
}

void CGLState::LightSpotExponent(int n_light, GLfloat f_value)
{
	__FuncGuard("CGLState::LightSpotExponent");

	TGLState *p_cur_state = m_p_cur_state;
	_ASSERTE(n_light >= 0 && n_light < p_cur_state->n_max_lights);

	if(p_cur_state->p_light_data[n_light].f_spot_exponent != f_value) {
		glLightf(GL_LIGHT0 + n_light, GL_SPOT_EXPONENT,
			p_cur_state->p_light_data[n_light].f_spot_exponent = f_value);
	}
}

void CGLState::LightSpotCutoff(int n_light, GLfloat f_value)
{
	__FuncGuard("CGLState::LightSpotCutoff");

	TGLState *p_cur_state = m_p_cur_state;
	_ASSERTE(n_light >= 0 && n_light < p_cur_state->n_max_lights);

	if(p_cur_state->p_light_data[n_light].f_spot_cutoff != f_value) {
		glLightf(GL_LIGHT0 + n_light, GL_SPOT_CUTOFF,
			p_cur_state->p_light_data[n_light].f_spot_cutoff = f_value);
	}
}

void CGLState::LightConstantAttenuation(int n_light, GLfloat f_value)
{
	__FuncGuard("CGLState::LightConstantAttenuation");

	TGLState *p_cur_state = m_p_cur_state;
	_ASSERTE(n_light >= 0 && n_light < p_cur_state->n_max_lights);

	if(p_cur_state->p_light_data[n_light].f_constant_attenuation != f_value) {
		glLightf(GL_LIGHT0 + n_light, GL_CONSTANT_ATTENUATION,
			p_cur_state->p_light_data[n_light].f_constant_attenuation = f_value);
	}
}

void CGLState::LightLinearAttenuation(int n_light, GLfloat f_value)
{
	__FuncGuard("CGLState::LightLinearAttenuation");

	TGLState *p_cur_state = m_p_cur_state;
	_ASSERTE(n_light >= 0 && n_light < p_cur_state->n_max_lights);

	if(p_cur_state->p_light_data[n_light].f_linear_attenuation != f_value) {
		glLightf(GL_LIGHT0 + n_light, GL_LINEAR_ATTENUATION,
			p_cur_state->p_light_data[n_light].f_linear_attenuation = f_value);
	}
}

void CGLState::LightQuadraticAttenuation(int n_light, GLfloat f_value)
{
	__FuncGuard("CGLState::LightQuadraticAttenuation");

	TGLState *p_cur_state = m_p_cur_state;
	_ASSERTE(n_light >= 0 && n_light < p_cur_state->n_max_lights);

	if(p_cur_state->p_light_data[n_light].f_quadratic_attenuation != f_value) {
		glLightf(GL_LIGHT0 + n_light, GL_QUADRATIC_ATTENUATION,
			p_cur_state->p_light_data[n_light].f_quadratic_attenuation = f_value);
	}
}

void CGLState::EnableBlend()
{
	__FuncGuard("CGLState::EnableBlend");

	TGLState *p_cur_state = m_p_cur_state;
	if(!p_cur_state->b_blend) {
		glEnable(GL_BLEND);
		p_cur_state->b_blend = true;
	}
}

void CGLState::DisableBlend()
{
	__FuncGuard("CGLState::DisableBlend");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_blend) {
		glDisable(GL_BLEND);
		p_cur_state->b_blend = false;
	}
}

void CGLState::BlendFunc(GLenum n_src_op, GLenum n_dest_op)
{
	__FuncGuard("CGLState::BlendFunc");

	TGLState *p_cur_state = m_p_cur_state;
	p_cur_state->p_blend_equation[0] = p_cur_state->p_blend_equation[1] = (GLenum)-1;
	// must be reset so the next call to BlendEquation(Separate) calls glBlendEquation(Separate)

	if(p_cur_state->p_blend_func[0] != n_src_op ||
	   p_cur_state->p_blend_func[1] != n_dest_op ||
	   p_cur_state->p_blend_func_alpha[0] != n_src_op ||
	   p_cur_state->p_blend_func_alpha[1] != n_dest_op) {
		glBlendFunc(p_cur_state->p_blend_func_alpha[0] =
			p_cur_state->p_blend_func[0] = n_src_op,
			p_cur_state->p_blend_func_alpha[1] = p_cur_state->p_blend_func[1] = n_dest_op);
	}
}

void CGLState::BlendFuncSeparate(GLenum n_src_op_rgb,
	GLenum n_dest_op_rgb, GLenum n_src_op_a, GLenum n_dest_op_a)
{
	__FuncGuard("CGLState::BlendFuncSeparate");

	TGLState *p_cur_state = m_p_cur_state;
	p_cur_state->p_blend_equation[0] = p_cur_state->p_blend_equation[1] = (GLenum)-1;
	// must be reset so the next call to BlendEquation(Separate) calls glBlendEquation(Separate)

	if(p_cur_state->p_blend_func[0] != n_src_op_rgb ||
	   p_cur_state->p_blend_func[1] != n_dest_op_rgb ||
	   p_cur_state->p_blend_func_alpha[0] != n_src_op_a ||
	   p_cur_state->p_blend_func_alpha[1] != n_dest_op_a) {
		glBlendFuncSeparate(p_cur_state->p_blend_func[0] = n_src_op_rgb,
			p_cur_state->p_blend_func[1] = n_dest_op_rgb,
			p_cur_state->p_blend_func_alpha[0] = n_src_op_a,
			p_cur_state->p_blend_func_alpha[1] = n_dest_op_a);
	}
}

void CGLState::BlendEquation(GLenum n_equation)
{
	__FuncGuard("CGLState::BlendEquation");

	TGLState *p_cur_state = m_p_cur_state;
	p_cur_state->p_blend_func[0] = p_cur_state->p_blend_func[1] =
		p_cur_state->p_blend_func_alpha[0] = p_cur_state->p_blend_func_alpha[1] = (GLenum)-1;
	// must be reset so the next call to BlendFunc(Separate) calls glBlendFunc(Separate)

	if(p_cur_state->p_blend_equation[0] != n_equation ||
	   p_cur_state->p_blend_equation[1] != n_equation) {
		glBlendEquation(p_cur_state->p_blend_equation[0] =
			p_cur_state->p_blend_equation[1] = n_equation);
	}
}

void CGLState::BlendEquationSeparate(GLenum n_equation_rgb, GLenum n_equation_alpha)
{
	__FuncGuard("CGLState::BlendEquationSeparate");

	TGLState *p_cur_state = m_p_cur_state;
	p_cur_state->p_blend_func[0] = p_cur_state->p_blend_func[1] =
		p_cur_state->p_blend_func_alpha[0] = p_cur_state->p_blend_func_alpha[1] = (GLenum)-1;
	// must be reset so the next call to BlendFunc(Separate) calls glBlendFunc(Separate)

	if(p_cur_state->p_blend_equation[0] != n_equation_rgb ||
	   p_cur_state->p_blend_equation[1] != n_equation_alpha) {
		glBlendEquationSeparate(p_cur_state->p_blend_equation[0] = n_equation_rgb,
			p_cur_state->p_blend_equation[1] = n_equation_alpha);
	}
}

void CGLState::EnableDepthTest()
{
	__FuncGuard("CGLState::EnableDepthTest");

	TGLState *p_cur_state = m_p_cur_state;
	if(!p_cur_state->b_depth_test) {
		glEnable(GL_DEPTH_TEST);
		p_cur_state->b_depth_test = true;
	}
}

void CGLState::DisableDepthTest()
{
	__FuncGuard("CGLState::DisableDepthTest");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_depth_test) {
		glDisable(GL_DEPTH_TEST);
		p_cur_state->b_depth_test = false;
	}
}

void CGLState::DepthFunc(GLenum n_op)
{
	__FuncGuard("CGLState::DepthFunc");

	_ASSERTE(n_op == GL_ALWAYS || n_op == GL_NEVER || n_op == GL_LESS || n_op == GL_LEQUAL ||
		n_op == GL_EQUAL || n_op == GL_NOTEQUAL || n_op == GL_GEQUAL || n_op == GL_GREATER);

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->n_depth_func != n_op)
		glDepthFunc(p_cur_state->n_depth_func = n_op);
}

void CGLState::EnableStencilTest()
{
	__FuncGuard("CGLState::EnableStencilTest");

	TGLState *p_cur_state = m_p_cur_state;
	if(!p_cur_state->b_stencil_test) {
		p_cur_state->b_stencil_test = true;
		glEnable(GL_STENCIL_TEST);
	}
}

void CGLState::DisableStencilTest()
{
	__FuncGuard("CGLState::DisableStencilTest");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_stencil_test) {
		p_cur_state->b_stencil_test = false;
		glDisable(GL_STENCIL_TEST);
	}
}

void CGLState::StencilFunc(GLenum n_func, GLint n_ref, GLuint n_mask)
{
	__FuncGuard("CGLState::StencilFunc");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_stencil_func[0] != n_func ||
	   p_cur_state->p_stencil_func[1] != n_func ||
	   p_cur_state->p_stencil_ref[0] != n_ref ||
	   p_cur_state->p_stencil_ref[1] != n_ref ||
	   p_cur_state->p_stencil_mask[0] != n_mask ||
	   p_cur_state->p_stencil_mask[1] != n_mask) {
		if(p_cur_state->b_separate_gl2_stencil) {
			glStencilFuncSeparate(GL_FRONT_AND_BACK,
				p_cur_state->p_stencil_func[0] = p_cur_state->p_stencil_func[1] = n_func,
				p_cur_state->p_stencil_ref[0] = p_cur_state->p_stencil_ref[1] = n_ref,
				p_cur_state->p_stencil_mask[0] = p_cur_state->p_stencil_mask[1] = n_mask);
		} else {
			glStencilFunc(p_cur_state->p_stencil_func[0] =
				p_cur_state->p_stencil_func[1] = n_func,
				p_cur_state->p_stencil_ref[0] =
				p_cur_state->p_stencil_ref[1] = n_ref,
				p_cur_state->p_stencil_mask[0] =
				p_cur_state->p_stencil_mask[1] = n_mask);
		}
	}
}

void CGLState::StencilFunc(bool b_front, GLenum n_func, GLint n_ref, GLuint n_mask)
{
	__FuncGuard("CGLState::StencilFunc");

	_ASSERTE(b_front == !!b_front);
	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_stencil_func[b_front] != n_func ||
	   p_cur_state->p_stencil_ref[b_front] != n_ref ||
	   p_cur_state->p_stencil_mask[b_front] != n_mask) {
		_ASSERTE(p_cur_state->b_separate_gl2_stencil);
		glStencilFuncSeparate((b_front)? GL_FRONT : GL_BACK,
			p_cur_state->p_stencil_func[b_front] = n_func,
			p_cur_state->p_stencil_ref[b_front] = n_ref,
			p_cur_state->p_stencil_mask[b_front] = n_mask);
	}
}

void CGLState::StencilOp(GLenum n_s_fail, GLuint n_s_pass_d_fail, GLuint n_s_pass_d_pass)
{
	__FuncGuard("CGLState::StencilOp");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_stencil_op_sfail[0] != n_s_fail ||
	   p_cur_state->p_stencil_op_sfail[1] != n_s_fail ||
	   p_cur_state->p_stencil_op_dfail[0] != n_s_pass_d_fail ||
	   p_cur_state->p_stencil_op_dfail[1] != n_s_pass_d_fail ||
	   p_cur_state->p_stencil_op_dpass[0] != n_s_pass_d_pass ||
	   p_cur_state->p_stencil_op_dpass[1] != n_s_pass_d_pass) {
		if(p_cur_state->b_separate_gl2_stencil) {
			glStencilOpSeparate(GL_FRONT_AND_BACK,
				p_cur_state->p_stencil_op_sfail[0] =
				p_cur_state->p_stencil_op_sfail[1] = n_s_fail,
				p_cur_state->p_stencil_op_dfail[0] =
				p_cur_state->p_stencil_op_dfail[1] = n_s_pass_d_fail,
				p_cur_state->p_stencil_op_dpass[0] =
				p_cur_state->p_stencil_op_dpass[1] = n_s_pass_d_pass);
		} else {
			glStencilOp(p_cur_state->p_stencil_op_sfail[0] =
				p_cur_state->p_stencil_op_sfail[1] = n_s_fail,
				p_cur_state->p_stencil_op_dfail[0] =
				p_cur_state->p_stencil_op_dfail[1] = n_s_pass_d_fail,
				p_cur_state->p_stencil_op_dpass[0] =
				p_cur_state->p_stencil_op_dpass[1] = n_s_pass_d_pass);
		}
	}
}

void CGLState::StencilOp(bool b_front, GLenum n_s_fail, GLuint n_s_pass_d_fail, GLuint n_s_pass_d_pass)
{
	__FuncGuard("CGLState::StencilOp");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_stencil_op_sfail[b_front] != n_s_fail ||
	   p_cur_state->p_stencil_op_dfail[b_front] != n_s_pass_d_fail ||
	   p_cur_state->p_stencil_op_dpass[b_front] != n_s_pass_d_pass) {
		_ASSERTE(p_cur_state->b_separate_gl2_stencil);
		glStencilOpSeparate((b_front)? GL_FRONT : GL_BACK,
			p_cur_state->p_stencil_op_sfail[b_front] = n_s_fail,
			p_cur_state->p_stencil_op_dfail[b_front] = n_s_pass_d_fail,
			p_cur_state->p_stencil_op_dpass[b_front] = n_s_pass_d_pass);
	}
}

void CGLState::EnableAlphaTest()
{
	__FuncGuard("CGLState::EnableAlphaTest");

	TGLState *p_cur_state = m_p_cur_state;
	if(!p_cur_state->b_alpha_test) {
		glEnable(GL_ALPHA_TEST);
		p_cur_state->b_alpha_test = true;
	}
}

void CGLState::DisableAlphaTest()
{
	__FuncGuard("CGLState::DisableAlphaTest");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_alpha_test) {
		glDisable(GL_ALPHA_TEST);
		p_cur_state->b_alpha_test = false;
	}
}

void CGLState::AlphaFunc(GLenum n_op, GLclampf f_tresh)
{
	__FuncGuard("CGLState::AlphaFunc");

	_ASSERTE(n_op == GL_ALWAYS || n_op == GL_NEVER || n_op == GL_LESS || n_op == GL_LEQUAL ||
		n_op == GL_EQUAL || n_op == GL_NOTEQUAL || n_op == GL_GEQUAL || n_op == GL_GREATER);

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->n_depth_func != n_op ||
	   p_cur_state->f_alpha_tresh != f_tresh) {
		glAlphaFunc(p_cur_state->n_depth_func = n_op,
			p_cur_state->f_alpha_tresh = f_tresh);
	}
}

void CGLState::DisableAllTexture1D()
{
	__FuncGuard("CGLState::DisableAllTexture1D");

	TGLState *p_cur_state = m_p_cur_state;
	for(int i = 0; i < p_cur_state->n_max_texture_units; ++ i) {
#ifdef GL_STATE_MULTITEXTURE_ENABLED
		if(i || m_p_cur_state->n_active_tex_unit != 0)
			glActiveTexture(GL_TEXTURE0 + i);
#endif
		if(p_cur_state->p_texture1d_enabled[i]) {
			glDisable(GL_TEXTURE_1D);
			p_cur_state->p_texture1d_enabled[i] = false;
		}
	}
#ifdef GL_STATE_MULTITEXTURE_ENABLED
	if(p_cur_state->n_active_tex_unit != p_cur_state->n_max_texture_units - 1)
		glActiveTexture(GL_TEXTURE0 + p_cur_state->n_active_tex_unit);
#endif
}

void CGLState::DisableAllTextures()
{
	__FuncGuard("CGLState::DisableAllTextures");

	TGLState *p_cur_state = m_p_cur_state;
	for(int i = 0; i < p_cur_state->n_max_texture_units; ++ i) {
#ifdef GL_STATE_MULTITEXTURE_ENABLED
		if(i || m_p_cur_state->n_active_tex_unit != 0)
			glActiveTexture(GL_TEXTURE0 + i);
#endif
		if(p_cur_state->p_texture1d_enabled[i]) {
			glDisable(GL_TEXTURE_1D);
			p_cur_state->p_texture1d_enabled[i] = false;
		}
		if(p_cur_state->p_texture2d_enabled[i]) {
			glDisable(GL_TEXTURE_2D);
			p_cur_state->p_texture2d_enabled[i] = false;
		}
		if(p_cur_state->p_texture_rect_enabled[i]) {
			glDisable(GL_TEXTURE_RECTANGLE_ARB);
			p_cur_state->p_texture_rect_enabled[i] = false;
		}
		if(p_cur_state->p_texture3d_enabled[i]) {
			glDisable(GL_TEXTURE_3D);
			p_cur_state->p_texture3d_enabled[i] = false;
		}
		if(p_cur_state->p_texture_cubemap_enabled[i]) {
			glDisable(GL_TEXTURE_CUBE_MAP);
			p_cur_state->p_texture_cubemap_enabled[i] = false;
		}
	}
#ifdef GL_STATE_MULTITEXTURE_ENABLED
	if(p_cur_state->n_active_tex_unit != p_cur_state->n_max_texture_units - 1)
		glActiveTexture(GL_TEXTURE0 + p_cur_state->n_active_tex_unit);
#endif
}

void CGLState::DisableAllTexture2D()
{
	__FuncGuard("CGLState::DisableAllTexture2D");

	TGLState *p_cur_state = m_p_cur_state;
	for(int i = 0; i < p_cur_state->n_max_texture_units; ++ i) {
#ifdef GL_STATE_MULTITEXTURE_ENABLED
		if(i || m_p_cur_state->n_active_tex_unit != 0)
			glActiveTexture(GL_TEXTURE0 + i);
#endif
		if(p_cur_state->p_texture2d_enabled[i]) {
			glDisable(GL_TEXTURE_2D);
			p_cur_state->p_texture2d_enabled[i] = false;
		}
	}
#ifdef GL_STATE_MULTITEXTURE_ENABLED
	if(p_cur_state->n_active_tex_unit != p_cur_state->n_max_texture_units - 1)
		glActiveTexture(GL_TEXTURE0 + p_cur_state->n_active_tex_unit);
#endif
}

void CGLState::DisableAllTextureRect()
{
	__FuncGuard("CGLState::DisableAllTextureRect");

	TGLState *p_cur_state = m_p_cur_state;
	for(int i = 0; i < p_cur_state->n_max_texture_units; ++ i) {
#ifdef GL_STATE_MULTITEXTURE_ENABLED
		if(i || m_p_cur_state->n_active_tex_unit != 0)
			glActiveTexture(GL_TEXTURE0 + i);
#endif
		if(p_cur_state->p_texture_rect_enabled[i]) {
			glDisable(GL_TEXTURE_RECTANGLE_ARB);
			p_cur_state->p_texture_rect_enabled[i] = false;
		}
	}
#ifdef GL_STATE_MULTITEXTURE_ENABLED
	if(p_cur_state->n_active_tex_unit != p_cur_state->n_max_texture_units - 1)
		glActiveTexture(GL_TEXTURE0 + p_cur_state->n_active_tex_unit);
#endif
}

void CGLState::DisableAllTexture3D()
{
	__FuncGuard("CGLState::DisableAllTexture3D");

	TGLState *p_cur_state = m_p_cur_state;
	for(int i = 0; i < p_cur_state->n_max_texture_units; ++ i) {
#ifdef GL_STATE_MULTITEXTURE_ENABLED
		if(i || m_p_cur_state->n_active_tex_unit != 0)
			glActiveTexture(GL_TEXTURE0 + i);
#endif
		if(p_cur_state->p_texture3d_enabled[i]) {
			glDisable(GL_TEXTURE_3D);
			p_cur_state->p_texture3d_enabled[i] = false;
		}
	}
#ifdef GL_STATE_MULTITEXTURE_ENABLED
	if(p_cur_state->n_active_tex_unit != p_cur_state->n_max_texture_units - 1)
		glActiveTexture(GL_TEXTURE0 + p_cur_state->n_active_tex_unit);
#endif
}

void CGLState::DisableAllTextureCubeMap()
{
	__FuncGuard("CGLState::DisableAllTextureCubeMap");

	TGLState *p_cur_state = m_p_cur_state;
	for(int i = 0; i < p_cur_state->n_max_texture_units; ++ i) {
#ifdef GL_STATE_MULTITEXTURE_ENABLED
		if(i || m_p_cur_state->n_active_tex_unit != 0)
			glActiveTexture(GL_TEXTURE0 + i);
#endif
		if(p_cur_state->p_texture_cubemap_enabled[i]) {
			glDisable(GL_TEXTURE_CUBE_MAP);
			p_cur_state->p_texture_cubemap_enabled[i] = false;
		}
	}
#ifdef GL_STATE_MULTITEXTURE_ENABLED
	if(p_cur_state->n_active_tex_unit != p_cur_state->n_max_texture_units - 1)
		glActiveTexture(GL_TEXTURE0 + p_cur_state->n_active_tex_unit);
#endif
}

void CGLState::DisableAllTexture(GLenum n_type)
{
	__FuncGuard("CGLState::DisableAllTexture");

	switch(n_type) {
	case GL_TEXTURE_1D:
		DisableAllTexture1D();
		return;
	case GL_TEXTURE_2D:
		DisableAllTexture2D();
		return;
	case GL_TEXTURE_3D:
		DisableAllTexture3D();
		return;
	case GL_TEXTURE_CUBE_MAP:
		DisableAllTextureCubeMap();
		return;
	case GL_TEXTURE_RECTANGLE_ARB:
		DisableAllTextureRect();
		return;
	default:
		{
			TGLState *p_cur_state = m_p_cur_state;
			for(int i = 0; i < p_cur_state->n_max_texture_units; ++ i) {
#ifdef GL_STATE_MULTITEXTURE_ENABLED
				if(i || m_p_cur_state->n_active_tex_unit != 0)
					glActiveTexture(GL_TEXTURE0 + i);
#endif
				glDisable(n_type);
			}
#ifdef GL_STATE_MULTITEXTURE_ENABLED
			if(p_cur_state->n_active_tex_unit != p_cur_state->n_max_texture_units - 1)
				glActiveTexture(p_cur_state->n_active_tex_unit);
#endif
		}
	}
}

void CGLState::EnableTexture1D()
{
	__FuncGuard("CGLState::EnableTexture1D");

	TGLState *p_cur_state = m_p_cur_state;
	if(!p_cur_state->p_texture1d_enabled[p_cur_state->n_active_tex_unit]) {
		glEnable(GL_TEXTURE_1D);
		p_cur_state->p_texture1d_enabled[p_cur_state->n_active_tex_unit] = true;
	}
}

void CGLState::EnableTexture2D()
{
	__FuncGuard("CGLState::EnableTexture2D");

	TGLState *p_cur_state = m_p_cur_state;
	if(!p_cur_state->p_texture2d_enabled[p_cur_state->n_active_tex_unit]) {
		glEnable(GL_TEXTURE_2D);
		p_cur_state->p_texture2d_enabled[p_cur_state->n_active_tex_unit] = true;
	}
}

void CGLState::EnableTextureRect()
{
	__FuncGuard("CGLState::EnableTextureRect");

	TGLState *p_cur_state = m_p_cur_state;
	if(!p_cur_state->p_texture_rect_enabled[p_cur_state->n_active_tex_unit]) {
		glEnable(GL_TEXTURE_RECTANGLE_ARB);
		p_cur_state->p_texture_rect_enabled[p_cur_state->n_active_tex_unit] = true;
	}
}

void CGLState::EnableTexture3D()
{
	__FuncGuard("CGLState::EnableTexture3D");

	TGLState *p_cur_state = m_p_cur_state;
	if(!p_cur_state->p_texture3d_enabled[p_cur_state->n_active_tex_unit]) {
		glEnable(GL_TEXTURE_3D);
		p_cur_state->p_texture3d_enabled[p_cur_state->n_active_tex_unit] = true;
	}
}

void CGLState::EnableTextureCubeMap()
{
	__FuncGuard("CGLState::EnableTextureCubeMap");

	TGLState *p_cur_state = m_p_cur_state;
	if(!p_cur_state->p_texture_cubemap_enabled[p_cur_state->n_active_tex_unit]) {
		glEnable(GL_TEXTURE_CUBE_MAP);
		p_cur_state->p_texture_cubemap_enabled[p_cur_state->n_active_tex_unit] = true;
	}
}

void CGLState::EnableTexture(GLenum n_type)
{
	__FuncGuard("CGLState::EnableTexture");

	_ASSERTE(n_type != GL_TEXTURE_1D &&
			 n_type != GL_TEXTURE_2D &&
			 n_type != GL_TEXTURE_RECTANGLE_ARB &&
			 n_type != GL_TEXTURE_3D &&
			 n_type != GL_TEXTURE_CUBE_MAP);
	// not supposed to use this for known texture types

	glEnable(n_type);
}

void CGLState::DisableTexture1D()
{
	__FuncGuard("CGLState::DisableTexture1D");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_texture1d_enabled[p_cur_state->n_active_tex_unit]) {
		glDisable(GL_TEXTURE_1D);
		p_cur_state->p_texture1d_enabled[p_cur_state->n_active_tex_unit] = false;
	}
}

void CGLState::DisableTexture2D()
{
	__FuncGuard("CGLState::DisableTexture2D");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_texture2d_enabled[p_cur_state->n_active_tex_unit]) {
		glDisable(GL_TEXTURE_2D);
		p_cur_state->p_texture2d_enabled[p_cur_state->n_active_tex_unit] = false;
	}
}

void CGLState::DisableTextureRect()
{
	__FuncGuard("CGLState::DisableTextureRect");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_texture_rect_enabled[p_cur_state->n_active_tex_unit]) {
		glDisable(GL_TEXTURE_RECTANGLE_ARB);
		p_cur_state->p_texture_rect_enabled[p_cur_state->n_active_tex_unit] = false;
	}
}
void CGLState::DisableTexture3D()
{
	__FuncGuard("CGLState::DisableTexture3D");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_texture3d_enabled[p_cur_state->n_active_tex_unit]) {
		glDisable(GL_TEXTURE_3D);
		p_cur_state->p_texture3d_enabled[p_cur_state->n_active_tex_unit] = false;
	}
}

void CGLState::DisableTextureCubeMap()
{
	__FuncGuard("CGLState::DisableTextureCubeMap");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_texture_cubemap_enabled[p_cur_state->n_active_tex_unit]) {
		glDisable(GL_TEXTURE_CUBE_MAP);
		p_cur_state->p_texture_cubemap_enabled[p_cur_state->n_active_tex_unit] = false;
	}
}

void CGLState::DisableTexture(GLenum n_type)
{
	__FuncGuard("CGLState::DisableTexture");

	_ASSERTE(n_type != GL_TEXTURE_1D &&
			 n_type != GL_TEXTURE_2D &&
			 n_type != GL_TEXTURE_RECTANGLE_ARB &&
			 n_type != GL_TEXTURE_3D &&
			 n_type != GL_TEXTURE_CUBE_MAP);
	// not supposed to use this for known texture types

	glDisable(n_type);
}

void CGLState::ActiveTextureUnit(int n_unit)
{
	__FuncGuard("CGLState::ActiveTextureUnit");

	TGLState *p_cur_state = m_p_cur_state;
	_ASSERTE(n_unit >= 0 && n_unit < p_cur_state->n_max_texture_units);

#ifdef GL_STATE_MULTITEXTURE_ENABLED
	if(p_cur_state->n_active_tex_unit != n_unit)
		glActiveTexture(GL_TEXTURE0 + (p_cur_state->n_active_tex_unit = n_unit));
#endif
}

int CGLState::n_TexUnit_Num()
{
	__FuncGuard("CGLState::n_TexUnit_Num");

	return m_p_cur_state->n_max_texture_units;
}

void CGLState::BindTexture1D(GLuint n_texture)
{
	__FuncGuard("CGLState::BindTexture1D");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_texture1d[p_cur_state->n_active_tex_unit] != n_texture) {
		glBindTexture(GL_TEXTURE_1D,
			p_cur_state->p_texture1d[p_cur_state->n_active_tex_unit] = n_texture);
	}
}

void CGLState::BindTexture2D(GLuint n_texture)
{
	__FuncGuard("CGLState::BindTexture2D");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_texture2d[p_cur_state->n_active_tex_unit] != n_texture) {
		glBindTexture(GL_TEXTURE_2D,
			p_cur_state->p_texture2d[p_cur_state->n_active_tex_unit] = n_texture);
	}
}

void CGLState::BindTextureRect(GLuint n_texture)
{
	__FuncGuard("CGLState::BindTextureRect");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_texture_rect[p_cur_state->n_active_tex_unit] != n_texture) {
		glBindTexture(GL_TEXTURE_RECTANGLE_ARB,
			p_cur_state->p_texture_rect[p_cur_state->n_active_tex_unit] = n_texture);
	}
}

void CGLState::BindTexture3D(GLuint n_texture)
{
	__FuncGuard("CGLState::BindTexture3D");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_texture3d[p_cur_state->n_active_tex_unit] != n_texture) {
		glBindTexture(GL_TEXTURE_3D,
			p_cur_state->p_texture3d[p_cur_state->n_active_tex_unit] = n_texture);
	}
}

void CGLState::BindTextureCubeMap(GLuint n_texture)
{
	__FuncGuard("CGLState::BindTextureCubeMap");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_texture_cubemap[p_cur_state->n_active_tex_unit] != n_texture) {
		glBindTexture(GL_TEXTURE_CUBE_MAP,
			p_cur_state->p_texture_cubemap[p_cur_state->n_active_tex_unit] = n_texture);
	}
}

void CGLState::BindTexture(GLenum n_type, GLuint n_texture)
{
	__FuncGuard("CGLState::BindTexture");

	_ASSERTE(n_type != GL_TEXTURE_1D &&
			 n_type != GL_TEXTURE_2D &&
			 n_type != GL_TEXTURE_RECTANGLE_ARB &&
			 n_type != GL_TEXTURE_3D &&
			 n_type != GL_TEXTURE_CUBE_MAP);
	// not supposed to use this for known texture types

	glBindTexture(n_type, n_texture);
}

void CGLState::NotifyDeleteTexture(GLuint n_texture)
{
	__FuncGuard("CGLState::NotifyDeleteTexture");

#ifdef GL_STATE_SINGLE_CONTEXT_ONLY
	TGLState *p_cur_state = m_p_cur_state;
#else // GL_STATE_SINGLE_CONTEXT_ONLY
	std::vector<TGLState*>::iterator p_state;
	if((p_state = std::find_if(m_p_state->begin(),
	   m_p_state->end(), CFindState(wglGetCurrentContext()))) == m_p_state->end())
		return;
	TGLState *p_cur_state = *p_state;
#endif // GL_STATE_SINGLE_CONTEXT_ONLY
	// try to find state that was already set for this context

	if(!p_cur_state)
		return; // in case any OpenGL resources are dealocated after all GLStates are
	for(int i = 0; i < p_cur_state->n_max_texture_units; ++ i) {
		if(p_cur_state->p_texture1d[i] == n_texture)
			p_cur_state->p_texture1d[i] = 0;
		if(p_cur_state->p_texture2d[i] == n_texture)
			p_cur_state->p_texture2d[i] = 0;
		if(p_cur_state->p_texture_rect[i] == n_texture)
			p_cur_state->p_texture_rect[i] = 0;
		if(p_cur_state->p_texture3d[i] == n_texture)
			p_cur_state->p_texture3d[i] = 0;
		if(p_cur_state->p_texture_cubemap[i] == n_texture)
			p_cur_state->p_texture_cubemap[i] = 0;
	}
	// reset any references for this texture
}

void CGLState::Color3f(GLfloat r, GLfloat g, GLfloat b)
{
	__FuncGuard("CGLState::Color3f");

#ifdef GL_STATE_FORCE_COLOR_CACHING
	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_color[0] != r ||
	   p_cur_state->p_color[1] != g ||
	   p_cur_state->p_color[2] != b ||
	   p_cur_state->p_color[3] != 1.0f) {
		glColor3f(p_cur_state->p_color[0] = r,
			p_cur_state->p_color[1] = g,
			p_cur_state->p_color[2] = b);
		p_cur_state->p_color[3] = 1.0f;
	}
#else // GL_STATE_FORCE_COLOR_CACHING
	glColor3f(r, g, b);
#endif // GL_STATE_FORCE_COLOR_CACHING
}

void CGLState::Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
{
	__FuncGuard("CGLState::Color4f");

#ifdef GL_STATE_FORCE_COLOR_CACHING
	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_color[0] != r ||
	   p_cur_state->p_color[1] != g ||
	   p_cur_state->p_color[2] != b ||
	   p_cur_state->p_color[3] != a) {
		glColor4f(p_cur_state->p_color[0] = r,
			p_cur_state->p_color[1] = g,
			p_cur_state->p_color[2] = b,
			p_cur_state->p_color[3] = a);
	}
#else // GL_STATE_FORCE_COLOR_CACHING
	glColor4f(r, g, b, a);
#endif // GL_STATE_FORCE_COLOR_CACHING
}

void CGLState::BlendColor3f(GLfloat r, GLfloat g, GLfloat b)
{
	__FuncGuard("CGLState::BlendColor3f");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_blend_color[0] != r ||
	   p_cur_state->p_blend_color[1] != g ||
	   p_cur_state->p_blend_color[2] != b ||
	   p_cur_state->p_blend_color[3] != 1.0f) {
		glBlendColor(p_cur_state->p_blend_color[0] = r,
			p_cur_state->p_blend_color[1] = g,
			p_cur_state->p_blend_color[2] = b,
			p_cur_state->p_blend_color[3] = 1.0f);
	}
}

void CGLState::BlendColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
{
	__FuncGuard("CGLState::BlendColor4f");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_blend_color[0] != r ||
	   p_cur_state->p_blend_color[1] != g ||
	   p_cur_state->p_blend_color[2] != b ||
	   p_cur_state->p_blend_color[3] != a) {
		glBlendColor(p_cur_state->p_blend_color[0] = r,
			p_cur_state->p_blend_color[1] = g,
			p_cur_state->p_blend_color[2] = b,
			p_cur_state->p_blend_color[3] = a);
	}
}

void CGLState::ClearColor4f(GLclampf r, GLclampf g, GLclampf b, GLclampf a)
{
	__FuncGuard("CGLState::ClearColor4f");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_clr_color[0] != r ||
	   p_cur_state->p_clr_color[1] != g ||
	   p_cur_state->p_clr_color[2] != b ||
	   p_cur_state->p_clr_color[3] != a) {
		glClearColor(p_cur_state->p_clr_color[0] = r,
					 p_cur_state->p_clr_color[1] = g,
					 p_cur_state->p_clr_color[2] = b,
					 p_cur_state->p_clr_color[3] = a);
	}
}

void CGLState::ClearDepth(GLclampd d)
{
	__FuncGuard("CGLState::ClearDepth");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->f_clr_depth != d)
		glClearDepth(p_cur_state->f_clr_depth = d);
}

void CGLState::ClearStencil(GLint s)
{
	__FuncGuard("CGLState::ClearStencil");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->n_clr_stencil != s)
		glClearStencil(p_cur_state->n_clr_stencil = s);
}

void CGLState::EnableCullFace()
{
	__FuncGuard("CGLState::EnableCullFace");

	TGLState *p_cur_state = m_p_cur_state;
	if(!p_cur_state->b_cull_face) {
		glEnable(GL_CULL_FACE);
		p_cur_state->b_cull_face = true;
	}
}

void CGLState::DisableCullFace()
{
	__FuncGuard("CGLState::DisableCullFace");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_cull_face) {
		glDisable(GL_CULL_FACE);
		p_cur_state->b_cull_face = false;
	}
}

void CGLState::CullFace(GLenum n_mode)
{
	__FuncGuard("CGLState::CullFace");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->n_cull_face != n_mode)
		glCullFace(p_cur_state->n_cull_face = n_mode);
}

void CGLState::FrontFace(GLenum n_mode)
{
	__FuncGuard("CGLState::FrontFace");

	_ASSERTE(n_mode == GL_CW || n_mode == GL_CCW);

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->n_front_face != n_mode)
		glFrontFace(p_cur_state->n_front_face = n_mode);
}

void CGLState::Enable_STRQ_TexGen()
{
	__FuncGuard("CGLState::Enable_STRQ_TexGen");

	TGLState *p_cur_state = m_p_cur_state;
	if(!p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][0])
		glEnable(GL_TEXTURE_GEN_S);
	if(!p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][1])
		glEnable(GL_TEXTURE_GEN_T);
	if(!p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][2])
		glEnable(GL_TEXTURE_GEN_R);
	if(!p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][3])
		glEnable(GL_TEXTURE_GEN_Q);
	//
	p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][0] =
		p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][1] =
		p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][2] =
		p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][3] = true;
}

void CGLState::Disable_STRQ_Texgen()
{
	__FuncGuard("CGLState::Disable_STRQ_Texgen");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][0])
		glDisable(GL_TEXTURE_GEN_S);
	if(p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][1])
		glDisable(GL_TEXTURE_GEN_T);
	if(p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][2])
		glDisable(GL_TEXTURE_GEN_R);
	if(p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][3])
		glDisable(GL_TEXTURE_GEN_Q);
	//
	p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][0] =
		p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][1] =
		p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][2] =
		p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][3] = false;
}

void CGLState::Enable_S_TexGen()
{
	__FuncGuard("CGLState::Enable_S_TexGen");

	TGLState *p_cur_state = m_p_cur_state;
	if(!p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][0]) {
		glEnable(GL_TEXTURE_GEN_S);
		p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][0] = true;
	}
}

void CGLState::Enable_T_TexGen()
{
	__FuncGuard("CGLState::Enable_T_TexGen");

	TGLState *p_cur_state = m_p_cur_state;
	if(!p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][1]) {
		glEnable(GL_TEXTURE_GEN_T);
		p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][1] = true;
	}
}

void CGLState::Enable_R_TexGen()
{
	__FuncGuard("CGLState::Enable_R_TexGen");

	TGLState *p_cur_state = m_p_cur_state;
	if(!p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][2]) {
		glEnable(GL_TEXTURE_GEN_R);
		p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][2] = true;
	}
}

void CGLState::Enable_Q_TexGen()
{
	__FuncGuard("CGLState::Enable_Q_TexGen");

	TGLState *p_cur_state = m_p_cur_state;
	if(!p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][3]) {
		glEnable(GL_TEXTURE_GEN_Q);
		p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][3] = true;
	}
}

void CGLState::Disable_S_TexGen()
{
	__FuncGuard("CGLState::Disable_S_TexGen");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][0]) {
		glDisable(GL_TEXTURE_GEN_S);
		p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][0] = false;
	}
}

void CGLState::Disable_T_TexGen()
{
	__FuncGuard("CGLState::Disable_T_TexGen");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][1]) {
		glDisable(GL_TEXTURE_GEN_T);
		p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][1] = false;
	}
}

void CGLState::Disable_R_TexGen()
{
	__FuncGuard("CGLState::Disable_R_TexGen");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][2]) {
		glDisable(GL_TEXTURE_GEN_R);
		p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][2] = false;
	}
}

void CGLState::Disable_Q_TexGen()
{
	__FuncGuard("CGLState::Disable_Q_TexGen");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][3]) {
		glDisable(GL_TEXTURE_GEN_Q);
		p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][3] = false;
	}
}

void CGLState::Enable_ST_TexGen()
{
	__FuncGuard("CGLState::Enable_ST_TexGen");

	TGLState *p_cur_state = m_p_cur_state;
	if(!p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][0]) {
		glEnable(GL_TEXTURE_GEN_S);
		p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][0] = true;
	}
	if(!p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][1]) {
		glEnable(GL_TEXTURE_GEN_T);
		p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][1] = true;
	}
}

void CGLState::Enable_STR_TexGen()
{
	__FuncGuard("CGLState::Enable_STR_TexGen");

	TGLState *p_cur_state = m_p_cur_state;
	if(!p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][0]) {
		glEnable(GL_TEXTURE_GEN_S);
		p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][0] = true;
	}
	if(!p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][1]) {
		glEnable(GL_TEXTURE_GEN_T);
		p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][1] = true;
	}
	if(!p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][2]) {
		glEnable(GL_TEXTURE_GEN_R);
		p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][2] = true;
	}
}

void CGLState::EnableTexGen(int n_coord)
{
	__FuncGuard("CGLState::EnableTexGen");

	_ASSERTE(n_coord >= 0 && n_coord < 4);

	TGLState *p_cur_state = m_p_cur_state;
	if(!p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][n_coord]) {
		glEnable(n_coord + GL_TEXTURE_GEN_S);
		p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][n_coord] = true;
	}
}

void CGLState::Disable_ST_TexGen()
{
	__FuncGuard("CGLState::Disable_ST_TexGen");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][0]) {
		glDisable(GL_TEXTURE_GEN_S);
		p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][0] = false;
	}
	if(p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][1]) {
		glDisable(GL_TEXTURE_GEN_T);
		p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][1] = false;
	}
}

void CGLState::Disable_STR_TexGen()
{
	__FuncGuard("CGLState::Disable_STR_TexGen");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][0]) {
		glDisable(GL_TEXTURE_GEN_S);
		p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][0] = false;
	}
	if(p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][1]) {
		glDisable(GL_TEXTURE_GEN_T);
		p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][1] = false;
	}
	if(p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][2]) {
		glDisable(GL_TEXTURE_GEN_R);
		p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][2] = false;
	}
}

void CGLState::DisableTexGen(int n_coord)
{
	__FuncGuard("CGLState::DisableTexGen");

	_ASSERTE(n_coord >= 0 && n_coord < 4);

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][n_coord]) {
		glDisable(n_coord + GL_TEXTURE_GEN_S);
		p_cur_state->p_texgen_enabled[p_cur_state->n_active_tex_unit][n_coord] = false;
	}
}

void CGLState::TexGen_STRQ_fv(int n_name, GLfloat *p_param16)
{
	__FuncGuard("CGLState::TexGen_STRQ_fv");

	_ASSERTE(n_name == GL_OBJECT_PLANE || n_name == GL_EYE_PLANE);

	TGLState *p_cur_state = m_p_cur_state;
	if(n_name == GL_OBJECT_PLANE) {
		if(memcmp(p_cur_state->p_texgen_object_plane[p_cur_state->n_active_tex_unit][0], p_param16, 4 * sizeof(GLfloat))) {
			memcpy(p_cur_state->p_texgen_object_plane[p_cur_state->n_active_tex_unit][0], p_param16, 4 * sizeof(GLfloat));
			glTexGenfv(GL_S, GL_OBJECT_PLANE, p_param16);
		}
		p_param16 += 4;
		if(memcmp(p_cur_state->p_texgen_object_plane[p_cur_state->n_active_tex_unit][1], p_param16, 4 * sizeof(GLfloat))) {
			memcpy(p_cur_state->p_texgen_object_plane[p_cur_state->n_active_tex_unit][1], p_param16, 4 * sizeof(GLfloat));
			glTexGenfv(GL_T, GL_OBJECT_PLANE, p_param16);
		}
		p_param16 += 4;
		if(memcmp(p_cur_state->p_texgen_object_plane[p_cur_state->n_active_tex_unit][2], p_param16, 4 * sizeof(GLfloat))) {
			memcpy(p_cur_state->p_texgen_object_plane[p_cur_state->n_active_tex_unit][2], p_param16, 4 * sizeof(GLfloat));
			glTexGenfv(GL_R, GL_OBJECT_PLANE, p_param16);
		}
		p_param16 += 4;
		if(memcmp(p_cur_state->p_texgen_object_plane[p_cur_state->n_active_tex_unit][3], p_param16, 4 * sizeof(GLfloat))) {
			memcpy(p_cur_state->p_texgen_object_plane[p_cur_state->n_active_tex_unit][3], p_param16, 4 * sizeof(GLfloat));
			glTexGenfv(GL_Q, GL_OBJECT_PLANE, p_param16);
		}
	} else if(n_name == GL_EYE_PLANE) {
		/*if(memcmp(p_cur_state->p_texgen_eye_plane[p_cur_state->n_active_tex_unit][0], p_param16, 4 * sizeof(GLfloat))) {
			memcpy(p_cur_state->p_texgen_eye_plane[p_cur_state->n_active_tex_unit][0], p_param16, 4 * sizeof(GLfloat));
			glTexGenfv(GL_S, GL_EYE_PLANE, p_param16);
		}
		p_param16 += 4;
		if(memcmp(p_cur_state->p_texgen_eye_plane[p_cur_state->n_active_tex_unit][1], p_param16, 4 * sizeof(GLfloat))) {
			memcpy(p_cur_state->p_texgen_eye_plane[p_cur_state->n_active_tex_unit][1], p_param16, 4 * sizeof(GLfloat));
			glTexGenfv(GL_T, GL_EYE_PLANE, p_param16);
		}
		p_param16 += 4;
		if(memcmp(p_cur_state->p_texgen_eye_plane[p_cur_state->n_active_tex_unit][2], p_param16, 4 * sizeof(GLfloat))) {
			memcpy(p_cur_state->p_texgen_eye_plane[p_cur_state->n_active_tex_unit][2], p_param16, 4 * sizeof(GLfloat));
			glTexGenfv(GL_R, GL_EYE_PLANE, p_param16);
		}
		p_param16 += 4;
		if(memcmp(p_cur_state->p_texgen_eye_plane[p_cur_state->n_active_tex_unit][3], p_param16, 4 * sizeof(GLfloat))) {
			memcpy(p_cur_state->p_texgen_eye_plane[p_cur_state->n_active_tex_unit][3], p_param16, 4 * sizeof(GLfloat));
			glTexGenfv(GL_Q, GL_EYE_PLANE, p_param16);
		}*/
		// caching disabled, depends on current modelview

		glTexGenfv(GL_S, GL_EYE_PLANE, p_param16);
		glTexGenfv(GL_T, GL_EYE_PLANE, p_param16 + 4);
		glTexGenfv(GL_R, GL_EYE_PLANE, p_param16 + 8);
		glTexGenfv(GL_Q, GL_EYE_PLANE, p_param16 + 12);
	}
}

void CGLState::TexGen_ST_fv(int n_name, GLfloat *p_param8)
{
	__FuncGuard("CGLState::TexGen_ST_fv");

	_ASSERTE(n_name == GL_OBJECT_PLANE || n_name == GL_EYE_PLANE);

	TGLState *p_cur_state = m_p_cur_state;
	if(n_name == GL_OBJECT_PLANE) {
		if(memcmp(p_cur_state->p_texgen_object_plane[p_cur_state->n_active_tex_unit][0], p_param8, 4 * sizeof(GLfloat))) {
			memcpy(p_cur_state->p_texgen_object_plane[p_cur_state->n_active_tex_unit][0], p_param8, 4 * sizeof(GLfloat));
			glTexGenfv(GL_S, GL_OBJECT_PLANE, p_param8);
		}
		p_param8 += 4;
		if(memcmp(p_cur_state->p_texgen_object_plane[p_cur_state->n_active_tex_unit][1], p_param8, 4 * sizeof(GLfloat))) {
			memcpy(p_cur_state->p_texgen_object_plane[p_cur_state->n_active_tex_unit][1], p_param8, 4 * sizeof(GLfloat));
			glTexGenfv(GL_T, GL_OBJECT_PLANE, p_param8);
		}
	} else if(n_name == GL_EYE_PLANE) {
		/*if(memcmp(p_cur_state->p_texgen_eye_plane[p_cur_state->n_active_tex_unit][0], p_param8, 4 * sizeof(GLfloat))) {
			memcpy(p_cur_state->p_texgen_eye_plane[p_cur_state->n_active_tex_unit][0], p_param8, 4 * sizeof(GLfloat));
			glTexGenfv(GL_S, GL_EYE_PLANE, p_param8);
		}
		p_param8 += 4;
		if(memcmp(p_cur_state->p_texgen_eye_plane[p_cur_state->n_active_tex_unit][1], p_param8, 4 * sizeof(GLfloat))) {
			memcpy(p_cur_state->p_texgen_eye_plane[p_cur_state->n_active_tex_unit][1], p_param8, 4 * sizeof(GLfloat));
			glTexGenfv(GL_T, GL_EYE_PLANE, p_param8);
		}*/
		// caching disabled, depends on current modelview

		glTexGenfv(GL_S, GL_EYE_PLANE, p_param8);
		glTexGenfv(GL_T, GL_EYE_PLANE, p_param8 + 4);
	}
}

void CGLState::TexGen_STR_fv(int n_name, GLfloat *p_param12)
{
	__FuncGuard("CGLState::TexGen_STR_fv");

	_ASSERTE(n_name == GL_OBJECT_PLANE || n_name == GL_EYE_PLANE);

	TGLState *p_cur_state = m_p_cur_state;
	if(n_name == GL_OBJECT_PLANE) {
		if(memcmp(p_cur_state->p_texgen_object_plane[p_cur_state->n_active_tex_unit][0], p_param12, 4 * sizeof(GLfloat))) {
			memcpy(p_cur_state->p_texgen_object_plane[p_cur_state->n_active_tex_unit][0], p_param12, 4 * sizeof(GLfloat));
			glTexGenfv(GL_S, GL_OBJECT_PLANE, p_param12);
		}
		p_param12 += 4;
		if(memcmp(p_cur_state->p_texgen_object_plane[p_cur_state->n_active_tex_unit][1], p_param12, 4 * sizeof(GLfloat))) {
			memcpy(p_cur_state->p_texgen_object_plane[p_cur_state->n_active_tex_unit][1], p_param12, 4 * sizeof(GLfloat));
			glTexGenfv(GL_T, GL_OBJECT_PLANE, p_param12);
		}
		p_param12 += 4;
		if(memcmp(p_cur_state->p_texgen_object_plane[p_cur_state->n_active_tex_unit][2], p_param12, 4 * sizeof(GLfloat))) {
			memcpy(p_cur_state->p_texgen_object_plane[p_cur_state->n_active_tex_unit][2], p_param12, 4 * sizeof(GLfloat));
			glTexGenfv(GL_R, GL_OBJECT_PLANE, p_param12);
		}
	} else if(n_name == GL_EYE_PLANE) {
		/*if(memcmp(p_cur_state->p_texgen_eye_plane[p_cur_state->n_active_tex_unit][0], p_param12, 4 * sizeof(GLfloat))) {
			memcpy(p_cur_state->p_texgen_eye_plane[p_cur_state->n_active_tex_unit][0], p_param12, 4 * sizeof(GLfloat));
			glTexGenfv(GL_S, GL_EYE_PLANE, p_param12);
		}
		p_param12 += 4;
		if(memcmp(p_cur_state->p_texgen_eye_plane[p_cur_state->n_active_tex_unit][1], p_param12, 4 * sizeof(GLfloat))) {
			memcpy(p_cur_state->p_texgen_eye_plane[p_cur_state->n_active_tex_unit][1], p_param12, 4 * sizeof(GLfloat));
			glTexGenfv(GL_T, GL_EYE_PLANE, p_param12);
		}
		p_param12 += 4;
		if(memcmp(p_cur_state->p_texgen_eye_plane[p_cur_state->n_active_tex_unit][2], p_param12, 4 * sizeof(GLfloat))) {
			memcpy(p_cur_state->p_texgen_eye_plane[p_cur_state->n_active_tex_unit][2], p_param12, 4 * sizeof(GLfloat));
			glTexGenfv(GL_R, GL_EYE_PLANE, p_param12);
		}*/
		// caching disabled, depends on current modelview

		glTexGenfv(GL_S, GL_EYE_PLANE, p_param12);
		glTexGenfv(GL_T, GL_EYE_PLANE, p_param12 + 4);
		glTexGenfv(GL_R, GL_EYE_PLANE, p_param12 + 8);
	}
}

void CGLState::TexGenfv(int n_coord, int n_name, GLfloat *p_param4)
{
	__FuncGuard("CGLState::TexGenfv");

	_ASSERTE(n_coord >= 0 && n_coord < 4);
	_ASSERTE(n_name == GL_OBJECT_PLANE || n_name == GL_EYE_PLANE);

	TGLState *p_cur_state = m_p_cur_state;
	if(n_name == GL_OBJECT_PLANE) {
		if(memcmp(p_cur_state->p_texgen_object_plane[p_cur_state->n_active_tex_unit][n_coord], p_param4, 4 * sizeof(GLfloat))) {
			memcpy(p_cur_state->p_texgen_object_plane[p_cur_state->n_active_tex_unit][n_coord], p_param4, 4 * sizeof(GLfloat));
			glTexGenfv(GL_S + n_coord, GL_OBJECT_PLANE, p_param4);
		}
	} else if(n_name == GL_EYE_PLANE) {
		/*if(memcmp(p_cur_state->p_texgen_eye_plane[p_cur_state->n_active_tex_unit][n_coord], p_param4, 4 * sizeof(GLfloat))) {
			memcpy(p_cur_state->p_texgen_eye_plane[p_cur_state->n_active_tex_unit][n_coord], p_param4, 4 * sizeof(GLfloat));*/
			glTexGenfv(GL_S + n_coord, GL_EYE_PLANE, p_param4);
			// caching disabled, depends on current modelview
		//}
	}
}

void CGLState::TexGen_STRQ_Mode(GLenum n_param)
{
	__FuncGuard("CGLState::TexGen_STRQ_Mode");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][0] != n_param)
		glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][0] = n_param);
	if(p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][1] != n_param)
		glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][1] = n_param);
	if(p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][2] != n_param)
		glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][2] = n_param);
	if(p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][3] != n_param)
		glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][3] = n_param);
}

void CGLState::TexGen_STR_Mode(GLenum n_param)
{
	__FuncGuard("CGLState::TexGen_STR_Mode");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][0] != n_param)
		glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][0] = n_param);
	if(p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][1] != n_param)
		glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][1] = n_param);
	if(p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][2] != n_param)
		glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][2] = n_param);
}

void CGLState::TexGen_S_Mode(GLenum n_param)
{
	__FuncGuard("CGLState::TexGen_S_Mode");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][0] != n_param)
		glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][0] = n_param);
}

void CGLState::TexGen_T_Mode(GLenum n_param)
{
	__FuncGuard("CGLState::TexGen_T_Mode");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][1] != n_param)
		glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][1] = n_param);
}

void CGLState::TexGen_R_Mode(GLenum n_param)
{
	__FuncGuard("CGLState::TexGen_R_Mode");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][2] != n_param)
		glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][2] = n_param);
}

void CGLState::TexGen_Q_Mode(GLenum n_param)
{
	__FuncGuard("CGLState::TexGen_Q_Mode");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][3] != n_param)
		glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][3] = n_param);
}

void CGLState::TexGen_ST_Mode(GLenum n_param)
{
	__FuncGuard("CGLState::TexGen_ST_Mode");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][0] != n_param)
		glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][0] = n_param);
	if(p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][1] != n_param)
		glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][1] = n_param);
}

void CGLState::TexGenMode(int n_coord, GLenum n_param)
{
	__FuncGuard("CGLState::TexGenMode");

	_ASSERTE(n_coord >= 0 && n_coord < 4);

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][n_coord] != n_param) {
		glTexGeni(GL_S + n_coord, GL_TEXTURE_GEN_MODE,
			p_cur_state->p_texgen_mode[p_cur_state->n_active_tex_unit][n_coord] = n_param);
	}
}

void CGLState::TexGenEyePlane(int n_coord, const float *p_plane4)
{
	__FuncGuard("CGLState::TexGenEyePlane");

	_ASSERTE(n_coord >= 0 && n_coord < 4);

	//TGLState *p_cur_state = m_p_cur_state;
	/*if(memcmp(p_cur_state->p_texgen_eye_plane[p_cur_state->n_active_tex_unit][n_coord], p_plane4, 4 * sizeof(GLfloat))) {
		memcpy(p_cur_state->p_texgen_eye_plane[p_cur_state->n_active_tex_unit][n_coord], p_plane4, 4 * sizeof(GLfloat));*/
		glTexGenfv(GL_S + n_coord, GL_EYE_PLANE, p_plane4);
		// caching disabled, depends on current modelview
	//}
}

void CGLState::TexGenObjectPlane(int n_coord, const float *p_plane4)
{
	__FuncGuard("CGLState::TexGenObjectPlane");

	_ASSERTE(n_coord >= 0 && n_coord < 4);

	TGLState *p_cur_state = m_p_cur_state;
	if(memcmp(p_cur_state->p_texgen_object_plane[p_cur_state->n_active_tex_unit][n_coord], p_plane4, 4 * sizeof(GLfloat))) {
		memcpy(p_cur_state->p_texgen_object_plane[p_cur_state->n_active_tex_unit][n_coord], p_plane4, 4 * sizeof(GLfloat));
		glTexGenfv(GL_S + n_coord, GL_OBJECT_PLANE, p_plane4);
	}
}

void CGLState::ColorMask(bool b_r, bool b_g, bool b_b, bool b_a)
{
	__FuncGuard("CGLState::ColorMask");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_color_write[0] != b_r ||
	   p_cur_state->p_color_write[1] != b_g ||
	   p_cur_state->p_color_write[2] != b_b ||
	   p_cur_state->p_color_write[3] != b_a)
		glColorMask(p_cur_state->p_color_write[0] = b_r,
					p_cur_state->p_color_write[1] = b_g,
					p_cur_state->p_color_write[2] = b_b,
					p_cur_state->p_color_write[3] = b_a);
}

void CGLState::DepthMask(bool b_d)
{
	__FuncGuard("CGLState::DepthMask");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_depth_write != b_d)
		glDepthMask(p_cur_state->b_depth_write = b_d);
}

void CGLState::StencilMask(GLuint n_mask)
{
	__FuncGuard("CGLState::StencilMask");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_stencil_write[0] != n_mask ||
	   p_cur_state->p_stencil_write[1] != n_mask) {
		if(p_cur_state->b_separate_gl2_stencil) {
			glStencilMaskSeparate(GL_FRONT_AND_BACK, p_cur_state->p_stencil_write[0] =
				p_cur_state->p_stencil_write[1] = n_mask);
		} else
			glStencilMask(p_cur_state->p_stencil_write[1] = n_mask);
	}
}

void CGLState::StencilMask(bool b_front, GLuint n_mask)
{
	__FuncGuard("CGLState::StencilMask");

	_ASSERTE(b_front == !!b_front);
	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_stencil_write[b_front] != n_mask) {
		_ASSERTE(p_cur_state->b_separate_gl2_stencil);
		glStencilMaskSeparate((b_front)? GL_FRONT : GL_BACK,
			p_cur_state->p_stencil_write[b_front] = n_mask);
	}
}

void CGLState::Enable(GLenum n_value)
{
	__FuncGuard("CGLState::Enable");

#ifdef GL_STATE_CACHE_GENERIC_ENABLE_DISABLE
	switch(n_value) {
	case GL_ALPHA_TEST:
		EnableAlphaTest();
		return;
	case GL_STENCIL_TEST:
		EnableStencilTest();
		return;
	case GL_DEPTH_TEST:
		EnableDepthTest();
		return;
	case GL_CULL_FACE:
		EnableCullFace();
		return;
	case GL_TEXTURE_1D:
		EnableTexture1D();
		return;
	case GL_TEXTURE_2D:
		EnableTexture2D();
		return;
	case GL_TEXTURE_3D:
		EnableTexture3D();
		return;
	case GL_TEXTURE_CUBE_MAP:
		EnableTextureCubeMap();
		return;
	case GL_BLEND:
		EnableBlend();
		return;
	case GL_LIGHTING:
		EnableLighting();
		return;
	case GL_FOG:
		EnableFog();
		return;
	case GL_POLYGON_OFFSET_LINE:
		EnablePolygonOffset_Line();
		return;
	case GL_POLYGON_OFFSET_FILL:
		EnablePolygonOffset_Fill();
		return;
	case GL_POLYGON_OFFSET_POINT:
		EnablePolygonOffset_Point();
		return;
	case GL_VERTEX_PROGRAM_ARB:
		EnableVertexProgram();
		return;
	case GL_FRAGMENT_PROGRAM_ARB:
		EnableFragmentProgram();
		return;
	default:
		if(n_value >= GL_LIGHT0 && n_value < GL_LIGHT0 + 32)
			EnableLight(n_value - GL_LIGHT0);
		else if(n_value >= GL_CLIP_PLANE0 && n_value < GL_CLIP_PLANE0 + 32)
			EnableClipPlane(n_value - GL_CLIP_PLANE0);
		else if(n_value >= GL_TEXTURE_GEN_S && n_value <= GL_TEXTURE_GEN_Q)
			EnableTexGen(n_value - GL_TEXTURE_GEN_S);
		else
			glEnable(n_value);
	}
#else // GL_STATE_CACHE_GENERIC_ENABLE_DISABLE
	_ASSERTE(n_value != GL_ALPHA_TEST && n_value != GL_STENCIL_TEST &&
		n_value != GL_DEPTH_TEST && n_value != GL_CULL_FACE &&
		n_value != GL_TEXTURE_1D && n_value != GL_TEXTURE_2D &&
		n_value != GL_TEXTURE_3D && n_value != GL_TEXTURE_CUBE_MAP &&
		n_value != GL_BLEND && n_value != GL_LIGHTING &&
		n_value != GL_FOG && n_value != GL_POLYGON_OFFSET_LINE &&
		n_value != GL_POLYGON_OFFSET_FILL && n_value != GL_POLYGON_OFFSET_POINT &&
		n_value != GL_VERTEX_PROGRAM_ARB && n_value != GL_FRAGMENT_PROGRAM_ARB &&
		(n_value < GL_LIGHT0 || n_value >= GL_LIGHT0 + 32) &&
		(n_value < GL_CLIP_PLANE0 || n_value >= GL_CLIP_PLANE0 + 32) &&
		(n_value < GL_TEXTURE_GEN_S || n_value >= GL_TEXTURE_GEN_Q));
	// those states are cached and have their specialized enable function

	glEnable(n_value);
#endif // GL_STATE_CACHE_GENERIC_ENABLE_DISABLE
}

void CGLState::Disable(GLenum n_value)
{
	__FuncGuard("CGLState::Disable");

#ifdef GL_STATE_CACHE_GENERIC_ENABLE_DISABLE
	switch(n_value) {
	case GL_ALPHA_TEST:
		DisableAlphaTest();
		return;
	case GL_STENCIL_TEST:
		DisableStencilTest();
		return;
	case GL_DEPTH_TEST:
		DisableDepthTest();
		return;
	case GL_CULL_FACE:
		DisableCullFace();
		return;
	case GL_TEXTURE_1D:
		DisableTexture1D();
		return;
	case GL_TEXTURE_2D:
		DisableTexture2D();
		return;
	case GL_TEXTURE_3D:
		DisableTexture3D();
		return;
	case GL_TEXTURE_CUBE_MAP:
		DisableTextureCubeMap();
		return;
	case GL_BLEND:
		DisableBlend();
		return;
	case GL_LIGHTING:
		DisableLighting();
		return;
	case GL_FOG:
		DisableFog();
		return;
	case GL_POLYGON_OFFSET_LINE:
		DisablePolygonOffset_Line();
		return;
	case GL_POLYGON_OFFSET_FILL:
		DisablePolygonOffset_Fill();
		return;
	case GL_POLYGON_OFFSET_POINT:
		DisablePolygonOffset_Point();
		return;
	case GL_VERTEX_PROGRAM_ARB:
		DisableVertexProgram();
		return;
	case GL_FRAGMENT_PROGRAM_ARB:
		DisableFragmentProgram();
		return;
	default:
		if(n_value >= GL_LIGHT0 && n_value < GL_LIGHT0 + 32)
			DisableLight(n_value - GL_LIGHT0);
		else if(n_value >= GL_CLIP_PLANE0 && n_value < GL_CLIP_PLANE0 + 32)
			DisableClipPlane(n_value - GL_CLIP_PLANE0);
		else if(n_value >= GL_TEXTURE_GEN_S && n_value <= GL_TEXTURE_GEN_Q)
			DisableTexGen(n_value - GL_TEXTURE_GEN_S);
		else
			glDisable(n_value);
	}
#else // GL_STATE_CACHE_GENERIC_ENABLE_DISABLE
	_ASSERTE(n_value != GL_ALPHA_TEST && n_value != GL_STENCIL_TEST &&
		n_value != GL_DEPTH_TEST && n_value != GL_CULL_FACE &&
		n_value != GL_TEXTURE_1D && n_value != GL_TEXTURE_2D &&
		n_value != GL_TEXTURE_3D && n_value != GL_TEXTURE_CUBE_MAP &&
		n_value != GL_BLEND && n_value != GL_LIGHTING &&
		n_value != GL_FOG && n_value != GL_POLYGON_OFFSET_LINE &&
		n_value != GL_POLYGON_OFFSET_FILL && n_value != GL_POLYGON_OFFSET_POINT &&
		n_value != GL_VERTEX_PROGRAM_ARB && n_value != GL_FRAGMENT_PROGRAM_ARB &&
		(n_value < GL_LIGHT0 || n_value >= GL_LIGHT0 + 32) &&
		(n_value < GL_CLIP_PLANE0 || n_value >= GL_CLIP_PLANE0 + 32) &&
		(n_value < GL_TEXTURE_GEN_S || n_value >= GL_TEXTURE_GEN_Q));
	// those states are cached and have their specialized disable function

	glDisable(n_value);
#endif // GL_STATE_CACHE_GENERIC_ENABLE_DISABLE
}

void CGLState::EnablePolygonOffset(GLenum n_mode)
{
	__FuncGuard("CGLState::EnablePolygonOffset");

	_ASSERTE(n_mode == GL_POLYGON_OFFSET_FILL || n_mode == GL_POLYGON_OFFSET_LINE
		|| n_mode == GL_POLYGON_OFFSET_POINT);

	int n = 0;
	switch(n_mode) {
	case GL_POLYGON_OFFSET_FILL:
		n = 0;
		break;
	case GL_POLYGON_OFFSET_LINE:
		n = 1;
		break;
	case GL_POLYGON_OFFSET_POINT:
		n = 2;
		break;
	}

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_polygon_offset_support && !p_cur_state->p_polygon_offset_enabled[n]) {
		glEnable(n_mode);
		p_cur_state->p_polygon_offset_enabled[n] = true;
	}
}

void CGLState::DisablePolygonOffset(GLenum n_mode)
{
	__FuncGuard("CGLState::DisablePolygonOffset");

	_ASSERTE(n_mode == GL_POLYGON_OFFSET_FILL || n_mode == GL_POLYGON_OFFSET_LINE
		|| n_mode == GL_POLYGON_OFFSET_POINT);

	int n = 0;
	switch(n_mode) {
	case GL_POLYGON_OFFSET_FILL:
		n = 0;
		break;
	case GL_POLYGON_OFFSET_LINE:
		n = 1;
		break;
	case GL_POLYGON_OFFSET_POINT:
		n = 2;
		break;
	}

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_polygon_offset_support && p_cur_state->p_polygon_offset_enabled[n]) {
		glDisable(n_mode);
		p_cur_state->p_polygon_offset_enabled[n] = false;
	}
}

void CGLState::EnablePolygonOffset_Fill()
{
	__FuncGuard("CGLState::EnablePolygonOffset_Fill");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_polygon_offset_support && !p_cur_state->p_polygon_offset_enabled[0]) {
		glEnable(GL_POLYGON_OFFSET_FILL);
		p_cur_state->p_polygon_offset_enabled[0] = true;
	}
}

void CGLState::DisablePolygonOffset_Fill()
{
	__FuncGuard("CGLState::DisablePolygonOffset_Fill");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_polygon_offset_support && p_cur_state->p_polygon_offset_enabled[0]) {
		glDisable(GL_POLYGON_OFFSET_FILL);
		p_cur_state->p_polygon_offset_enabled[0] = false;
	}
}

void CGLState::EnablePolygonOffset_Line()
{
	__FuncGuard("CGLState::EnablePolygonOffset_Line");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_polygon_offset_support && !p_cur_state->p_polygon_offset_enabled[1]) {
		glEnable(GL_POLYGON_OFFSET_LINE);
		p_cur_state->p_polygon_offset_enabled[1] = true;
	}
}

void CGLState::DisablePolygonOffset_Line()
{
	__FuncGuard("CGLState::DisablePolygonOffset_Line");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_polygon_offset_support && p_cur_state->p_polygon_offset_enabled[1]) {
		glDisable(GL_POLYGON_OFFSET_LINE);
		p_cur_state->p_polygon_offset_enabled[1] = false;
	}
}

void CGLState::EnablePolygonOffset_Point()
{
	__FuncGuard("CGLState::EnablePolygonOffset_Point");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_polygon_offset_support && !p_cur_state->p_polygon_offset_enabled[2]) {
		glEnable(GL_POLYGON_OFFSET_POINT);
		p_cur_state->p_polygon_offset_enabled[2] = true;
	}
}

void CGLState::DisablePolygonOffset_Point()
{
	__FuncGuard("CGLState::DisablePolygonOffset_Point");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_polygon_offset_support && p_cur_state->p_polygon_offset_enabled[2]) {
		glDisable(GL_POLYGON_OFFSET_POINT);
		p_cur_state->p_polygon_offset_enabled[2] = false;
	}
}

void CGLState::PolygonOffset(GLfloat f_factor, GLfloat f_bias)
{
	__FuncGuard("CGLState::PolygonOffset");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_polygon_offset_support) {
		if(p_cur_state->f_polygon_offset_factor != f_factor ||
		   p_cur_state->f_polygon_offset_bias != f_bias) {
			glPolygonOffset(p_cur_state->f_polygon_offset_factor = f_factor,
							   p_cur_state->f_polygon_offset_bias = f_bias);
		}
	}
}

void CGLState::EnableVertexProgram()
{
	__FuncGuard("CGLState::EnableVertexProgram");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_vertex_program_support && !p_cur_state->b_vertex_program_enabled) {
		glEnable(GL_VERTEX_PROGRAM_ARB);
		p_cur_state->b_vertex_program_enabled = true;
	}
}

void CGLState::EnableFragmentProgram()
{
	__FuncGuard("CGLState::EnableFragmentProgram");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_fragment_program_support && !p_cur_state->b_fragment_program_enabled) {
		glEnable(GL_FRAGMENT_PROGRAM_ARB);
		p_cur_state->b_fragment_program_enabled = true;
	}
}

void CGLState::DisableVertexProgram()
{
	__FuncGuard("CGLState::DisableVertexProgram");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_vertex_program_support && p_cur_state->b_vertex_program_enabled) {
		glDisable(GL_VERTEX_PROGRAM_ARB);
		p_cur_state->b_vertex_program_enabled = false;
	}
}

void CGLState::DisableFragmentProgram()
{
	__FuncGuard("CGLState::DisableFragmentProgram");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_fragment_program_support && p_cur_state->b_fragment_program_enabled) {
		glDisable(GL_FRAGMENT_PROGRAM_ARB);
		p_cur_state->b_fragment_program_enabled = false;
	}
}

void CGLState::BindProgramObject(GLhandleARB h_shader)
{
	__FuncGuard("CGLState::BindProgramObject");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_shader_support && p_cur_state->n_program_object != h_shader)
		glUseProgramObjectARB(p_cur_state->n_program_object = h_shader);
}

void CGLState::BindProgramObject_GL2(GLuint n_shader)
{
	__FuncGuard("CGLState::BindProgramObject_GL2");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_shader_gl2_support && p_cur_state->n_program_object != n_shader)
		glUseProgram(p_cur_state->n_program_object = n_shader);
}

void CGLState::BindVertexProgram(GLuint n_program)
{
	__FuncGuard("CGLState::BindVertexProgram");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_vertex_program_support && p_cur_state->n_vertex_program != n_program)
		glBindProgramARB(GL_VERTEX_PROGRAM_ARB, p_cur_state->n_vertex_program = n_program);
}

void CGLState::BindFragmentProgram(GLuint n_program)
{
	__FuncGuard("CGLState::BindFragmentProgram");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_vertex_program_support && p_cur_state->n_fragment_program != n_program)
		glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, p_cur_state->n_fragment_program = n_program);
}

void CGLState::NotifyDeleteProgramObject(GLhandleARB h_shader)
{
	__FuncGuard("CGLState::NotifyDeleteProgramObject");

#ifdef GL_STATE_SINGLE_CONTEXT_ONLY
	TGLState *p_cur_state = m_p_cur_state;
#else // GL_STATE_SINGLE_CONTEXT_ONLY
	std::vector<TGLState*>::iterator p_state;
	if((p_state = std::find_if(m_p_state->begin(),
	   m_p_state->end(), CFindState(wglGetCurrentContext()))) == m_p_state->end())
		return;
	TGLState *p_cur_state = *p_state;
#endif // GL_STATE_SINGLE_CONTEXT_ONLY
	// try to find state that was already set for this context

	if(!p_cur_state)
		return; // in case any OpenGL resources are dealocated after all GLStates are
	if(p_cur_state->n_program_object == h_shader)
		p_cur_state->n_program_object = 0;
}

void CGLState::NotifyDeleteProgramObject_GL2(GLuint n_shader)
{
	__FuncGuard("CGLState::NotifyDeleteProgramObject_GL2");

#ifdef GL_STATE_SINGLE_CONTEXT_ONLY
	TGLState *p_cur_state = m_p_cur_state;
#else // GL_STATE_SINGLE_CONTEXT_ONLY
	std::vector<TGLState*>::iterator p_state;
	if((p_state = std::find_if(m_p_state->begin(),
	   m_p_state->end(), CFindState(wglGetCurrentContext()))) == m_p_state->end())
		return;
	TGLState *p_cur_state = *p_state;
#endif // GL_STATE_SINGLE_CONTEXT_ONLY
	// try to find state that was already set for this context

	if(!p_cur_state)
		return; // in case any OpenGL resources are dealocated after all GLStates are
	if(p_cur_state->n_program_object == n_shader)
		p_cur_state->n_program_object = 0;
}

void CGLState::NotifyDeleteVertexProgram(GLuint n_program)
{
	__FuncGuard("CGLState::NotifyDeleteVertexProgram");

#ifdef GL_STATE_SINGLE_CONTEXT_ONLY
	TGLState *p_cur_state = m_p_cur_state;
#else // GL_STATE_SINGLE_CONTEXT_ONLY
	std::vector<TGLState*>::iterator p_state;
	if((p_state = std::find_if(m_p_state->begin(),
	   m_p_state->end(), CFindState(wglGetCurrentContext()))) == m_p_state->end())
		return;
	TGLState *p_cur_state = *p_state;
#endif // GL_STATE_SINGLE_CONTEXT_ONLY
	// try to find state that was already set for this context

	if(!p_cur_state)
		return; // in case any OpenGL resources are dealocated after all GLStates are
	if(p_cur_state->n_vertex_program == n_program)
		p_cur_state->n_vertex_program = 0;
}

void CGLState::NotifyDeleteFragmentProgram(GLuint n_program)
{
	__FuncGuard("CGLState::NotifyDeleteFragmentProgram");

#ifdef GL_STATE_SINGLE_CONTEXT_ONLY
	TGLState *p_cur_state = m_p_cur_state;
#else // GL_STATE_SINGLE_CONTEXT_ONLY
	std::vector<TGLState*>::iterator p_state;
	if((p_state = std::find_if(m_p_state->begin(),
	   m_p_state->end(), CFindState(wglGetCurrentContext()))) == m_p_state->end())
		return;
	TGLState *p_cur_state = *p_state;
#endif // GL_STATE_SINGLE_CONTEXT_ONLY
	// try to find state that was already set for this context

	if(!p_cur_state)
		return; // in case any OpenGL resources are dealocated after all GLStates are
	if(p_cur_state->n_fragment_program == n_program)
		p_cur_state->n_fragment_program = 0;
}

void CGLState::LightModelAmbient(const GLfloat *p_ambient4)
{
	__FuncGuard("CGLState::LightModelAmbient");

	TGLState *p_cur_state = m_p_cur_state;
	if(memcmp(p_cur_state->p_model_ambient, p_ambient4, 4 * sizeof(GLfloat))) {
		memcpy(p_cur_state->p_model_ambient, p_ambient4, 4 * sizeof(GLfloat));
		glLightModelfv(GL_LIGHT_MODEL_AMBIENT, p_ambient4);
	}
}

void CGLState::LightModelViewer(bool b_local)
{
	__FuncGuard("CGLState::LightModelViewer");

	TGLState *p_cur_state = m_p_cur_state;
	if((p_cur_state->b_model_local_viewer != 0) != b_local)
		glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, p_cur_state->b_model_local_viewer = b_local);
}

void CGLState::LightModelTwoSide(bool b_two_side)
{
	__FuncGuard("CGLState::LightModelTwoSide");

	TGLState *p_cur_state = m_p_cur_state;
	if((p_cur_state->b_model_two_side != 0) != b_two_side)
		glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, p_cur_state->b_model_two_side = b_two_side);
}

void CGLState::LightModelColorControl(GLenum n_mode)
{
	__FuncGuard("CGLState::LightModelColorControl");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->n_model_color_control != n_mode) {
		glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,
			p_cur_state->n_model_color_control = n_mode);
	}
}

void CGLState::MaterialAmbient(const GLfloat *p_ambient4)
{
	__FuncGuard("CGLState::MaterialAmbient");

	TGLState *p_cur_state = m_p_cur_state;
	if(memcmp(p_cur_state->p_material_ambient[0], p_ambient4, 4 * sizeof(GLfloat)) ||
	   memcmp(p_cur_state->p_material_ambient[1], p_ambient4, 4 * sizeof(GLfloat))) {
		memcpy(p_cur_state->p_material_ambient[0], p_ambient4, 4 * sizeof(GLfloat));
		memcpy(p_cur_state->p_material_ambient[1], p_ambient4, 4 * sizeof(GLfloat));
		glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, p_ambient4);
	}
}

void CGLState::MaterialAmbient(bool b_front, const GLfloat *p_ambient4)
{
	__FuncGuard("CGLState::MaterialAmbient");

	_ASSERTE(b_front == !!b_front);
	TGLState *p_cur_state = m_p_cur_state;
	if(memcmp(p_cur_state->p_material_ambient[b_front], p_ambient4, 4 * sizeof(GLfloat))) {
		memcpy(p_cur_state->p_material_ambient[b_front], p_ambient4, 4 * sizeof(GLfloat));
		glMaterialfv((b_front)? GL_FRONT : GL_BACK, GL_AMBIENT, p_ambient4);
	}
}

void CGLState::MaterialDiffuse(const GLfloat *p_diffuse4)
{
	__FuncGuard("CGLState::MaterialDiffuse");

	TGLState *p_cur_state = m_p_cur_state;
	if(memcmp(p_cur_state->p_material_diffuse[0], p_diffuse4, 4 * sizeof(GLfloat)) ||
	   memcmp(p_cur_state->p_material_diffuse[1], p_diffuse4, 4 * sizeof(GLfloat))) {
		memcpy(p_cur_state->p_material_diffuse[0], p_diffuse4, 4 * sizeof(GLfloat));
		memcpy(p_cur_state->p_material_diffuse[1], p_diffuse4, 4 * sizeof(GLfloat));
		glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, p_diffuse4);
	}
}

void CGLState::MaterialDiffuse(bool b_front, const GLfloat *p_diffuse4)
{
	__FuncGuard("CGLState::MaterialDiffuse");

	_ASSERTE(b_front == !!b_front);
	TGLState *p_cur_state = m_p_cur_state;
	if(memcmp(p_cur_state->p_material_diffuse[b_front], p_diffuse4, 4 * sizeof(GLfloat))) {
		memcpy(p_cur_state->p_material_diffuse[b_front], p_diffuse4, 4 * sizeof(GLfloat));
		glMaterialfv((b_front)? GL_FRONT : GL_BACK, GL_DIFFUSE, p_diffuse4);
	}
}

void CGLState::MaterialSpecular(const GLfloat *p_specular4)
{
	__FuncGuard("CGLState::MaterialSpecular");

	TGLState *p_cur_state = m_p_cur_state;
	if(memcmp(p_cur_state->p_material_specular[0], p_specular4, 4 * sizeof(GLfloat)) ||
	   memcmp(p_cur_state->p_material_specular[1], p_specular4, 4 * sizeof(GLfloat))) {
		memcpy(p_cur_state->p_material_specular[0], p_specular4, 4 * sizeof(GLfloat));
		memcpy(p_cur_state->p_material_specular[1], p_specular4, 4 * sizeof(GLfloat));
		glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, p_specular4);
	}
}

void CGLState::MaterialSpecular(bool b_front, const GLfloat *p_specular4)
{
	__FuncGuard("CGLState::MaterialSpecular");

	_ASSERTE(b_front == !!b_front);
	TGLState *p_cur_state = m_p_cur_state;
	if(memcmp(p_cur_state->p_material_specular[b_front], p_specular4, 4 * sizeof(GLfloat))) {
		memcpy(p_cur_state->p_material_specular[b_front], p_specular4, 4 * sizeof(GLfloat));
		glMaterialfv((b_front)? GL_FRONT : GL_BACK, GL_SPECULAR, p_specular4);
	}
}

void CGLState::MaterialEmission(const GLfloat *p_emission4)
{
	__FuncGuard("CGLState::MaterialEmission");

	TGLState *p_cur_state = m_p_cur_state;
	if(memcmp(p_cur_state->p_material_emission[0], p_emission4, 4 * sizeof(GLfloat)) ||
	   memcmp(p_cur_state->p_material_emission[1], p_emission4, 4 * sizeof(GLfloat))) {
		memcpy(p_cur_state->p_material_emission[0], p_emission4, 4 * sizeof(GLfloat));
		memcpy(p_cur_state->p_material_emission[1], p_emission4, 4 * sizeof(GLfloat));
		glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, p_emission4);
	}
}

void CGLState::MaterialEmission(bool b_front, const GLfloat *p_emission4)
{
	__FuncGuard("CGLState::MaterialEmission");

	_ASSERTE(b_front == !!b_front);
	TGLState *p_cur_state = m_p_cur_state;
	if(memcmp(p_cur_state->p_material_emission[b_front], p_emission4, 4 * sizeof(GLfloat))) {
		memcpy(p_cur_state->p_material_emission[b_front], p_emission4, 4 * sizeof(GLfloat));
		glMaterialfv((b_front)? GL_FRONT : GL_BACK, GL_EMISSION, p_emission4);
	}
}

void CGLState::MaterialShininess(GLfloat f_shininess)
{
	__FuncGuard("CGLState::MaterialShininess");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_material_shininess[0] != f_shininess ||
	   p_cur_state->p_material_shininess[1] != f_shininess) {
		glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS,
			p_cur_state->p_material_shininess[0] =
			p_cur_state->p_material_shininess[1] = f_shininess);
	}
}

void CGLState::MaterialShininess(bool b_front, GLfloat f_shininess)
{
	__FuncGuard("CGLState::MaterialShininess");

	_ASSERTE(b_front == !!b_front);

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->p_material_shininess[b_front] != f_shininess) {
		glMaterialf((b_front)? GL_FRONT : GL_BACK, GL_SHININESS,
			p_cur_state->p_material_shininess[b_front] = f_shininess);
	}
}

void CGLState::EnableClipPlane(int n_plane)
{
	__FuncGuard("CGLState::EnableClipPlane");

	TGLState *p_cur_state = m_p_cur_state;
	_ASSERTE(n_plane >= 0 && n_plane < p_cur_state->n_max_clip_planes);

	if(!p_cur_state->p_clip_plane_enabled[n_plane]) {
		p_cur_state->p_clip_plane_enabled[n_plane] = true;
		glEnable(GL_CLIP_PLANE0 + n_plane);
	}
}

void CGLState::DisableClipPlane(int n_plane)
{
	__FuncGuard("CGLState::DisableClipPlane");

	TGLState *p_cur_state = m_p_cur_state;
	_ASSERTE(n_plane >= 0 && n_plane < p_cur_state->n_max_clip_planes);

	if(p_cur_state->p_clip_plane_enabled[n_plane]) {
		p_cur_state->p_clip_plane_enabled[n_plane] = false;
		glDisable(GL_CLIP_PLANE0 + n_plane);
	}
}

void CGLState::DisableAllClipPlanes()
{
	__FuncGuard("CGLState::DisableAllClipPlanes");

	TGLState *p_cur_state = m_p_cur_state;
	for(int i = 0; i < p_cur_state->n_max_clip_planes; ++ i) {
		if(p_cur_state->p_clip_plane_enabled[i]) {
			p_cur_state->p_clip_plane_enabled[i] = false;
			glDisable(GL_CLIP_PLANE0 + i);
		}
	}
}

void CGLState::ClipPlane(int n_plane,
	GLdouble f_eqn0, GLdouble f_eqn1, GLdouble f_eqn2, GLdouble f_eqn3)
{
	__FuncGuard("CGLState::ClipPlane");

	_ASSERTE(n_plane >= 0 && n_plane < m_p_cur_state->n_max_clip_planes);

	//TGLState *p_cur_state = m_p_cur_state;
	/*if(p_cur_state->p_clip_plane[n_plane][0] != f_eqn0 ||
	   p_cur_state->p_clip_plane[n_plane][1] != f_eqn1 ||
	   p_cur_state->p_clip_plane[n_plane][2] != f_eqn2 ||
	   p_cur_state->p_clip_plane[n_plane][3] != f_eqn3) {*/
		GLdouble p_clip_plane[4];
		p_clip_plane[0] = f_eqn0;
		p_clip_plane[1] = f_eqn1;
		p_clip_plane[2] = f_eqn2;
		p_clip_plane[3] = f_eqn3;
		glClipPlane(GL_CLIP_PLANE0 + n_plane, p_clip_plane);
		// caching disabled, depends on current modelview
	//}
}

void CGLState::BindVertexArrayBuffer(GLuint n_buffer)
{
	__FuncGuard("CGLState::BindVertexArrayBuffer");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_vertex_buffer_support && p_cur_state->n_vertex_array_buffer != n_buffer)
		glBindBufferARB(GL_ARRAY_BUFFER, p_cur_state->n_vertex_array_buffer = n_buffer);
}

void CGLState::BindVertexElementArrayBuffer(GLuint n_buffer)
{
	__FuncGuard("CGLState::BindVertexElementArrayBuffer");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_vertex_buffer_support &&
	   p_cur_state->n_vertex_element_array_buffer != n_buffer) {
		glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER,
			p_cur_state->n_vertex_element_array_buffer = n_buffer);
	}
}

void CGLState::BindPixelPackBuffer(GLuint n_buffer)
{
	__FuncGuard("CGLState::BindPixelPackBuffer");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_pixel_buffer_support && p_cur_state->n_pixel_pack_buffer != n_buffer)
		glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, p_cur_state->n_pixel_pack_buffer = n_buffer);
}

void CGLState::BindPixelUnPackBuffer(GLuint n_buffer)
{
	__FuncGuard("CGLState::BindPixelUnPackBuffer");

	TGLState *p_cur_state = m_p_cur_state;
	if(p_cur_state->b_pixel_buffer_support && p_cur_state->n_pixel_unpack_buffer != n_buffer)
		glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, p_cur_state->n_pixel_unpack_buffer = n_buffer);
}

void CGLState::BindBuffer(GLenum n_target, GLuint n_buffer)
{
	__FuncGuard("CGLState::BindBuffer");

	TGLState *p_cur_state = m_p_cur_state;
	switch(n_target) {
	case GL_ARRAY_BUFFER:
		if(p_cur_state->b_vertex_buffer_support &&
		   p_cur_state->n_vertex_array_buffer != n_buffer)
			glBindBufferARB(GL_ARRAY_BUFFER, p_cur_state->n_vertex_array_buffer = n_buffer);
		return;
	case GL_ELEMENT_ARRAY_BUFFER:
		if(p_cur_state->b_vertex_buffer_support &&
		   p_cur_state->n_vertex_element_array_buffer != n_buffer) {
			glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER,
				p_cur_state->n_vertex_element_array_buffer = n_buffer);
		}
		return;
	case GL_PIXEL_PACK_BUFFER_ARB:
		if(p_cur_state->b_pixel_buffer_support && p_cur_state->n_pixel_pack_buffer != n_buffer)
			glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, p_cur_state->n_pixel_pack_buffer = n_buffer);
		return;
	case GL_PIXEL_UNPACK_BUFFER_ARB:
		if(p_cur_state->b_pixel_buffer_support &&
		   p_cur_state->n_pixel_unpack_buffer != n_buffer) {
			glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB,
				p_cur_state->n_pixel_unpack_buffer = n_buffer);
		}
		return;
	default:
		if(p_cur_state->b_vertex_buffer_support)
			glBindBufferARB(n_target, n_buffer);
	}
}

void CGLState::NotifyDeleteBufferObject(GLuint n_buffer)
{
	__FuncGuard("CGLState::NotifyDeleteBufferObject");

#ifdef GL_STATE_SINGLE_CONTEXT_ONLY
	TGLState *p_cur_state = m_p_cur_state;
#else // GL_STATE_SINGLE_CONTEXT_ONLY
	std::vector<TGLState*>::iterator p_state;
	if((p_state = std::find_if(m_p_state->begin(),
	   m_p_state->end(), CFindState(wglGetCurrentContext()))) == m_p_state->end())
		return;
	TGLState *p_cur_state = *p_state;
#endif // GL_STATE_SINGLE_CONTEXT_ONLY
	// try to find state that was already set for this context

	if(!p_cur_state)
		return; // in case any OpenGL resources are dealocated after all GLStates are
	if(p_cur_state->n_vertex_array_buffer == n_buffer)
		p_cur_state->n_vertex_array_buffer = 0;
	if(p_cur_state->n_vertex_element_array_buffer == n_buffer)
		p_cur_state->n_vertex_element_array_buffer = 0;
	if(p_cur_state->n_pixel_pack_buffer == n_buffer)
		p_cur_state->n_pixel_pack_buffer = 0;
	if(p_cur_state->n_pixel_unpack_buffer == n_buffer)
		p_cur_state->n_pixel_unpack_buffer = 0;
}

/*
 *								=== ~CGLState ===
 */

/*
 *		-end-of-file-
 */
