/*
								+---------------------------------+
								|                                 |
								|    ***   Shader system   ***    |
								|                                 |
								|  Copyright  © -tHE SWINe- 2006  |
								|                                 |
								|          ShaderSys.cpp          |
								|                                 |
								+---------------------------------+
*/

/**
 *	@file gl2/ShaderSys.cpp
 *	@date 2006
 *	@author -tHE SWINe-
 *	@brief Shader system
 *
 *	@date 2007-02-05
 *
 *	passed code revision
 *
 *	fixed some signed / unsigned glitches
 *	removed const_iterator to iterator type cast hack in CGLShaderObject::n_TextureType()
 *	and in CGLShaderObject::n_TextureUnit()
 *
 *	@date 2007-03-29
 *
 *	changed shader parameter system a bit; added consistent copy constructors and copy operators
 *	to shader parameter classes, shader object now return parameter objects directly, not pointers
 *	to them.
 *	added simpler version of CShaderVectorParameterRef::SetValue() without swizzle,
 *	fixed CShaderMatrixParameterRef::SetValue() for matrix parameters (which didn't correctly
 *	copy transpose matrix parameters)
 *
 *	t_odo: prepare architecture for GL_EXT_gpu_program_parameters, use glUniform*iv for faster
 *	parameter transfers using single command. shader object architecture is ready for that.
 *
 *	@date 2007-05-09
 *
 *	added a few versions of CShaderVectorParameterRef::SetValue() to directly accept scalar params
 *
 *	@date 2007-08-10
 *
 *	fixed bug in CGLShaderObject::Fill_Parameters which always failed because it didn't reserve
 *	any space in parameter list and checked for it right after
 *
 *	renamed CGLShaderObject::n_TextureType to CGLShaderObject::n_SamplerType
 *
 *	CShaderParameterRef::n_Size() now returns number of elements of parameter; 1 is scalar,
 *	2 trough 4 is vector and 4 trough 16 is matrix (note the same value must be passed to
 *	CShaderParameterRef constructor parameter n_size)
 *
 *	removed CSwizzleGenerator as it was considered useless feature
 *
 *	added parameter buffers which are intended for quickly setting all shader parameters
 *	in scenarios where there are several constant sets of parameters that need to be used
 *	(such as materials sharing a single shader but having different parameters which do not
 *	change in time - or at least most of them does not)
 *
 *	added parameter upload grouping capability - in theory for vertex / fragment programs
 *	all parameters could be uploaded by single OpenGL call, it's similar with shaders but there
 *	needs to be call per uniform type (call for all samplers, vectors, ...)
 *	this is experimental and is not yet debugged
 *
 *	added GL_EXT_gpu_shader4 parameter types as well as non-square matrices but those aren't
 *	actualy getting uploaded as i lack hardware to debug it
 *
 *	added support for array parameters
 *
 *	added some TShaderInfo constructors for simple parsing of either programs or shaders
 *	from simple string format (in case both programs and shaders are required, two
 *	TShaderInfo instances must be created and either p_high or p_low pointers swapped)
 *
 *	@date 2007-11-10
 *
 *	improved linux compatibility
 *
 *	@date 2007-11-26
 *
 *	fixed bug with new NVidia drivers (163.71) where glGetProgramiv with GL_ACTIVE_UNIFORMS,
 *	as well as glGetActiveUniform returns reserved (builtin) OpenGL variables, among other
 *	shader parameres. it crashes because glGetUniformLocation returns -1 for them, of course ...
 *
 *	@date 2008-03-04
 *
 *	cleaned up uniform binder code, core shaders now support unsigned integer uniforms
 *	as well as non-square matrix uniforms
 *
 *	@date 2008-03-11
 *
 *	added still missing support for geometry shaders. note it's necessary to set geometry
 *	shader properties (input and output primitives type, max number of emitted vertices)
 *	in TShaderInfo. note the constructors of TShaderInfo slightly changed, but any software
 *	using earlier version of shader system should compile and work without any changes.
 *
 *	@date 2008-03-13
 *
 *	fixed some fatal mistakes in CGLShaderObject::b_ShaderSupport and
 *	CGLShaderObject::b_ShaderAvailability which made compiling low-level shaders impossible
 *
 *	@date 2008-04-29
 *
 *	exposed __ENABLE_MERGE_UNIFORM_UPLOADS which enables parameter upload grouping capability
 *	(see change from 2007-08-10)
 *
 *	@date 2008-05-19
 *
 *	fixed typos in the word 'environment'
 *
 *	@date 2008-08-08
 *
 *	added \#ifdef for windows 64
 *
 *	@date 2008-08-09
 *
 *	added default constructors to CShaderParameterRef, CShaderVectorParameterRef and
 *	CShaderMatrixParameterRef. those are handy when using parameters without parameter buffer.
 *
 *	@date 2008-08-19
 *
 *	removed unused b_shader_target field from TShaderInfo
 *
 *	redesigned inner classes of TShaderInfo, added functionality for conveniently adding
 *	code and samplers to existing shaders (useful for including library functions to shaders)
 *
 *	created better working texture unit allocator for CGLShaderObject (when compiling shaders
 *	with samplers in both vertex and fragment code, or when compiling shader with some of
 *	samplers allocated explicitly and some implicitly, the old allocator might create conflicts)
 *
 *	@date 2009-05-23
 *
 *	removed all instances of std::vector::reserve and replaced them by stl_ut::Reserve_*
 *
 *	@date 2009-10-20
 *
 *	fixed some warnings when compiling under VC 2005, implemented "Security
 *	Enhancements in the CRT" for VC 2008. compare against MyProjects_2009-10-19_
 *
 */

#include "../NewFix.h"

#include "../CallStack.h"
#include <vector>
#include <algorithm>
#include <functional>
#include "OpenGL20.h"
#include "OpenGLState.h"
#include "Texture.h"
#include "RenderBuffer2.h"
#include "Shader2.h"
#include "ShaderSys.h"
#include "../StlUtils.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

static char *cpp_strdup(const char *p_s_string)
{
	char *p_s_str = new(std::nothrow) char[strlen(p_s_string) + 1];
	if(!p_s_str)
		return 0;
#if defined(_MSC_VER) && !defined(__MWERKS__) && _MSC_VER >= 1400
	strcpy_s(p_s_str, (strlen(p_s_string) + 1) * sizeof(char), p_s_string);
#else // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
	strcpy(p_s_str, p_s_string);
#endif // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
	return p_s_str;
}

/*
 *								=== TShaderInfo ===
 */

/*
 *	TShaderInfo::TShaderInfo()
 *		- default constructor
 */
TShaderInfo::TShaderInfo()
	:n_processor(proc_Vertex), p_s_name(0), n_geometry_in_type(GL_TRIANGLES),
	n_geometry_out_type(GL_TRIANGLE_STRIP), n_max_vertex_num(0), p_high(0), p_low(0)
{}

/*
 *	TShaderInfo::TShaderInfo(const TShaderInfo &r_t_shader_info)
 *		- copy-constructor
 */
TShaderInfo::TShaderInfo(const TShaderInfo &r_t_shader_info)
	:n_processor(proc_Vertex), p_s_name(0), n_geometry_in_type(GL_TRIANGLES),
	n_geometry_out_type(GL_TRIANGLE_STRIP), n_max_vertex_num(0), p_high(0), p_low(0)
{
	Copy(r_t_shader_info);
}

/*
 *	TShaderInfo::TShaderInfo(const char *_p_s_name, int _n_processor,
 *		const char *p_s_source_code, const char *p_s_sampler_list = 0)
 *		- convenience constructor for creating simple GLSL shaders
 *		- _p_s_name is shader name
 *		- _n_processor is one of proc_Vertex, proc_Geometry, proc_Fragment
 *		- p_s_source_code is shader source code
 *		- p_s_sampler_list can optionaly contain list of samplers separated
 *		  by '|' characters to enforce texture unit association
 *		- in case constructor fails, p_high section is guaranteed to be 0
 */
TShaderInfo::TShaderInfo(const char *_p_s_name, int _n_processor,
	const char *p_s_source_code, const char *p_s_sampler_list)
	:n_processor(_n_processor), p_s_name(0), n_geometry_in_type(GL_TRIANGLES),
	n_geometry_out_type(GL_TRIANGLE_STRIP), n_max_vertex_num(0), p_high(0), p_low(0)
{
	if(!(p_high = new(std::nothrow) TShader(p_s_source_code, p_s_sampler_list)))
		return;
	if(!p_high->p_s_Source_Code() || !(p_s_name = cpp_strdup(_p_s_name))) {
		delete p_high;
		p_high = 0;
	}
}

/*
 *	TShaderInfo::TShaderInfo(const char *_p_s_name, int _n_processor,
 *		const char *p_s_source_code, const char *p_s_param_list,
 *		const char *p_s_tex_unit_name_list)
 *		- convenience constructor for creating simple ARB programs
 *		- _p_s_name is shader name
 *		- _n_processor is one of proc_Vertex, proc_Geometry, proc_Fragment
 *		- p_s_source_code is program source code
 *		- p_s_param_list is list of program parameters separated by '|' characters
 *		  where each program parameter is in format 'name:e:location' or 'name:l:location'
 *		  ('e' for environment parameters, 'l' for local parameters)
 *		- p_s_tex_unit_name_list is list of texture unit names separated by '|'
 *		  (it's purpose is to aid missing sampler names)
 *		- in case constructor fails, p_low section is guaranteed to be 0
 */
TShaderInfo::TShaderInfo(const char *_p_s_name, int _n_processor,
	const char *p_s_source_code, const char *p_s_param_list, const char *p_s_tex_unit_name_list)
	:n_processor(_n_processor),  p_s_name(0), n_geometry_in_type(GL_TRIANGLES),
	n_geometry_out_type(GL_TRIANGLE_STRIP), n_max_vertex_num(0), p_high(0), p_low(0)
{
	if(!(p_low = new(std::nothrow) TProgram(p_s_source_code, p_s_param_list, p_s_tex_unit_name_list)))
		return;
	if(!p_low->p_s_Source_Code() || !(p_s_name = cpp_strdup(_p_s_name))) {
		delete p_low;
		p_low = 0;
	}
}

/*
 *	TShaderInfo::~TShaderInfo()
 *		- default destructor
 */
TShaderInfo::~TShaderInfo()
{
	if(p_s_name)
		delete[] p_s_name;
	if(p_high)
		delete p_high;
	if(p_low)
		delete p_low;
}

/*
 *	inline TShaderInfo &TShaderInfo::operator =(const TShaderInfo &r_t_shader_info)
 *		- copy-operator
 */
TShaderInfo &TShaderInfo::operator =(const TShaderInfo &r_t_shader_info)
{
	Copy(r_t_shader_info);
	return *this;
}

/*
 *	bool TShaderInfo::Copy(const TShaderInfo &r_t_shader_info)
 *		- copies contents of r_t_shader_info to this
 *		- returns true on success, false on failure (not enough memory)
 */
bool TShaderInfo::Copy(const TShaderInfo &r_t_shader_info)
{
	if(&r_t_shader_info == this)
		return true;
	// handle self-assignment

	if(p_s_name)
		delete[] p_s_name;
	if(p_high) {
		delete[] p_high;
		p_high = 0;
	}
	if(p_low) {
		delete[] p_low;
		p_low = 0;
	}
	// delete data

	if(!(p_s_name = cpp_strdup(r_t_shader_info.p_s_name)))
		return false;
	// copy name

	n_geometry_in_type = r_t_shader_info.n_geometry_in_type;
	n_geometry_out_type = r_t_shader_info.n_geometry_out_type;
	n_max_vertex_num = r_t_shader_info.n_max_vertex_num;
	n_processor = r_t_shader_info.n_processor;
	// copy scalar properties

	if(r_t_shader_info.p_high) {
		if(!(p_high = new(std::nothrow) TShader))
			return false;
		if(!p_high->Copy(*r_t_shader_info.p_high))
			return false;
	}
	// copy "high" section

	if(r_t_shader_info.p_low) {
		if(!(p_low = new(std::nothrow) TProgram))
			return false;
		if(!p_low->Copy(*r_t_shader_info.p_low))
			return false;
	}
	// copy "low" section

	return true;
}

/*
 *								=== ~TShaderInfo ===
 */

/*
 *								=== TShaderInfo::TShader ===
 */

/*
 *	TShaderInfo::TShader::TShader()
 *		- default constructor; clears dynamically allocated fields
 */
TShaderInfo::TShader::TShader()
	:p_sampler(0), p_s_source_code(0)
{}

/*
 *	TShaderInfo::TShader::TShader(const char *p_s_source_code,
 *		const char *p_s_sampler_list = 0)
 *		- constructor
 *		- creates shader with source code p_s_source_code and assigns samplers
 *		  from p_s_sampler_list (sampler names separated by '|' characters)
 *		- note in case constructor fails, p_s_source_code is set to 0
 */
TShaderInfo::TShader::TShader(const char *_p_s_source_code, const char *p_s_sampler_list)
	:p_sampler(0), n_sampler_num(0)
{
	if(!(p_s_source_code = cpp_strdup(_p_s_source_code)))
		return;

	if(n_sampler_num = n_ListSize(p_s_sampler_list, '|')) {
		// count samplers

		if(!(p_sampler = new(std::nothrow) TNamedResource[n_sampler_num])) {
			delete[] p_s_source_code;
			p_s_source_code = 0; // delete source code to mark error
			return;
		}
		// alloc samplers

		for(int i = 0; i < n_sampler_num; ++ i) {
			const char *p_s_next_sampler = strchr(p_s_sampler_list, '|');
			int n_name_length = (p_s_next_sampler)? p_s_next_sampler - p_s_sampler_list : -1;

			if(!p_sampler[i].Fill(p_s_sampler_list, n_name_length, i)) {
				delete[] p_s_source_code;
				p_s_source_code = 0; // delete source code to mark error
				return;
			}

			p_s_sampler_list = p_s_next_sampler + 1;
		}
		// copy samplers
	}
}

/*
 *	TShaderInfo::TShader::~TShader()
 *		- destructor
 */
TShaderInfo::TShader::~TShader()
{
	if(p_s_source_code)
		delete[] p_s_source_code;
	if(p_sampler)
		delete[] p_sampler;
}

/*
 *	bool TShaderInfo::TShader::IncludeSource(const char *p_s_include, bool b_add_to_front = true)
 *		- adds p_s_include to source code, if b_add_to_front is true,
 *		  p_s_include is added to front of source code, otherwise
 *		  it is appended to back of source code
 *		- returns true on success, false on failure
 */
bool TShaderInfo::TShader::IncludeSource(const char *p_s_include, bool b_add_to_front)
{
	if(!p_s_source_code) {
		if(!(p_s_source_code = cpp_strdup(p_s_include)))
			return false;
		return true;
	}
	// create new shader from scratch

	char *p_s_new_source;
	if(!(p_s_new_source = new(std::nothrow) char[strlen(p_s_source_code) + strlen(p_s_include) + 2]))
		return false;
	// alloc new buffer for shader source

#if defined(_MSC_VER) && !defined(__MWERKS__) && _MSC_VER >= 1400
	size_t n_bufsize = (strlen(p_s_source_code) + strlen(p_s_include) + 2) * sizeof(char);
	if(b_add_to_front) {
		strcpy_s(p_s_new_source, n_bufsize, p_s_include);
		strcat_s(p_s_new_source, n_bufsize, "\n");
		strcat_s(p_s_new_source, n_bufsize, p_s_source_code);
	} else {
		strcpy_s(p_s_new_source, n_bufsize, p_s_source_code);
		strcat_s(p_s_new_source, n_bufsize, "\n");
		strcat_s(p_s_new_source, n_bufsize, p_s_include);
	}
#else // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
	if(b_add_to_front) {
		strcpy(p_s_new_source, p_s_include);
		strcat(p_s_new_source, "\n");
		strcat(p_s_new_source, p_s_source_code);
	} else {
		strcpy(p_s_new_source, p_s_source_code);
		strcat(p_s_new_source, "\n");
		strcat(p_s_new_source, p_s_include);
	}
#endif // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
	// concat source code and include

	delete[] p_s_source_code;
	p_s_source_code = p_s_new_source;
	// delete old source, swap pointers

	return true;
}

/*
 *	bool TShaderInfo::TShader::b_FreeTexUnit(int n_index) const
 *		- returns true if texturing unit with zero-based index n_index
 *		  does not have assigned sampler, otherwise returns false
 */
bool TShaderInfo::TShader::b_FreeTexUnit(int n_index) const
{
	for(int i = 0; i < n_sampler_num; ++ i) {
		if(p_sampler[i].n_resource_index == n_index)
			return false;
	}
	return true;
}

/*
 *	int TShaderInfo::TShader::n_FreeTexUnit(int n_index = 0) const
 *		- returns zero-based index of n_index-th texturing unit
 *		  which does not have assigned sampler
 */
int TShaderInfo::TShader::n_FreeTexUnit(int n_index) const
{
	for(int n_sampler = 0;; ++ n_sampler) {
		if(b_FreeTexUnit(n_sampler)) {
			if(!n_index)
				return n_sampler;
			-- n_index;
		}
	}
}

/*
 *	int TShaderInfo::TShader::n_TexUnit(const char *p_s_sampler_name) const
 *		- returns zero-based index of texturing unit with assigned
 *		  sampler p_s_sampler_name or -1 if there is no such sampler
 */
int TShaderInfo::TShader::n_TexUnit(const char *p_s_sampler_name) const
{
	for(int i = 0; i < n_sampler_num; ++ i) {
		if(!strcmp(p_sampler[i].p_s_Name(), p_s_sampler_name))
			return p_sampler[i].n_resource_index;
	}
	return -1;
}

/*
 *	int TShaderInfo::TShader::n_AssignTextureUnit(const char *p_s_name, int n_force_index = -1)
 *		- assigns sampler named p_s_name to texturing unit with
 *		  zero-based index n_force_index
 *		- if n_force_index is negative, first free index is used instead
 *		- if, on the other hand any other sampler is assigned to texture
 *		  unit with forced index, it is reassigned to next free texturing unit
 *		- returns zero-based index of texturing unit sampler was assigned to
 *		  or -1 on failure
 */
int TShaderInfo::TShader::n_AssignTextureUnit(const char *p_s_name, int n_force_index)
{
	if(n_force_index >= 0) {
		for(int i = 0; i < n_sampler_num; ++ i) {
			if(p_sampler[i].n_resource_index == n_force_index)
				p_sampler[i].n_resource_index = n_FreeTexUnit();
		}
	}
	// replace forced index by free index

	TNamedResource *p_new_sampler;
	if(!(p_new_sampler = new(std::nothrow) TNamedResource[n_sampler_num + 1]))
		return -1;
	// alloc new texture unit list

	int n_index = (n_force_index < 0)? n_FreeTexUnit() : n_force_index;
	if(!p_new_sampler[n_sampler_num].Fill(p_s_name, -1, n_index)) {
		delete[] p_new_sampler;
		return -1;
	}
	// create new texture unit

	for(int i = 0; i < n_sampler_num; ++ i)
		p_new_sampler[i].Swap(p_sampler[i]);
		//p_new_sampler[i].Fill(p_sampler[i].p_s_Name(), -1, p_sampler[i].n_resource_index);
	// swap old texture units

	if(p_sampler)
		delete[] p_sampler;
	p_sampler = p_new_sampler;
	++ n_sampler_num;
	// delete old array, swap pointers, increment counter

	return n_index;
}

/*
 *	bool TShaderInfo::TShader::Copy(const TShader &r_shader)
 *		- copies contents of r_shader to this
 *		- returns true on success, false on failure
 */
bool TShaderInfo::TShader::Copy(const TShader &r_shader)
{
	if(p_s_source_code)
		delete[] p_s_source_code;
	if(p_sampler) {
		delete[] p_sampler;
		p_sampler = 0;
	}
	// free everything

	if(!(p_s_source_code = cpp_strdup(r_shader.p_s_source_code)))
		return false;
	// copy source code

	if(n_sampler_num = r_shader.n_sampler_num) {
		if(!(p_sampler = new(std::nothrow) TNamedResource[n_sampler_num]))
			return false;
		for(int i = 0; i < n_sampler_num; ++ i) {
			if(!p_sampler[i].Fill(r_shader.p_sampler[i].p_s_Name(), -1,
			   r_shader.p_sampler[i].n_resource_index))
				return false;
		}
	}
	// copy samplers

	return true;
}

/*
 *	static int TShaderInfo::TShader::n_ListSize(const char *p_s_list, char n_separator)
 *		- utility function; calculates size of list p_s_list of
 *		  items separated by n_separator character
 *		- returns 0 if p_s_list is 0 or an empty string
 */
int TShaderInfo::TShader::n_ListSize(const char *p_s_list, char n_separator)
{
	if(!p_s_list || !*p_s_list)
		return 0;
	int n_result = 0;
	for(; p_s_list; p_s_list = (strchr(p_s_list, n_separator))?
	   strchr(p_s_list, n_separator) + 1 : 0)
		++ n_result;
	return n_result;
}

/*
 *								=== ~TShaderInfo::TShader ===
 */

/*
 *								=== TShaderInfo::TProgram ===
 */

/*
 *	TShaderInfo::TProgram::TProgram()
 *		- default constructor; clears dynamically allocated fields
 */
TShaderInfo::TProgram::TProgram()
	:TShader(), p_parameter(0)
{}

/*
 *	TShaderInfo::TProgram::TProgram(const char *p_s_source_code,
 *		const char *p_s_param_list, const char *p_s_tex_unit_list)
 *		- constructor
 *		- creates shader with source code p_s_source_code, parameters from
 *		  p_s_param_list (parameters in format 'name:[el]:register-index'
 *		  separated by '|') and texture unit names from p_s_tex_unit_list
 *		  (texture unit names separated by '|' characters)
 *		- note in case constructor fails, p_s_source_code is set to 0
 */
TShaderInfo::TProgram::TProgram(const char *_p_s_source_code,
	const char *p_s_param_list, const char *p_s_tex_unit_list)
	:TShader(_p_s_source_code, p_s_tex_unit_list), p_parameter(0), n_parameter_num(0)
{
	if(!p_s_source_code)
		return; // marks error in TShader::TShader()

	if(n_parameter_num = n_ListSize(p_s_param_list, '|')) {
		// count parameters

		if(!(p_parameter = new(std::nothrow) TParamInfo[n_parameter_num])) {
			delete[] p_s_source_code;
			p_s_source_code = 0; // delete source code to mark error
			return;
		}
		// alloc parameters

		for(int i = 0; i < n_parameter_num; ++ i) {
			const char *p_s_next_parameter = strchr(p_s_param_list, '|');
			const char *p_s_name_end = strchr(p_s_param_list, ':');
			if(!p_s_name_end || (p_s_next_parameter && p_s_name_end > p_s_next_parameter) ||
			   (tolower(p_s_name_end[1]) != 'e' && tolower(p_s_name_end[1]) != 'l') ||
			   p_s_name_end[2] != ':') {
				delete[] p_s_source_code;
				p_s_source_code = 0; // delete source code to mark error
				return;
			}
			// there must be ':[elEL]:[0-9]*[|\0]' following name

			const char *p_s_index = p_s_name_end + 3;
			for(const char *p_s_index_end = p_s_index;
			   *p_s_index_end && *p_s_index_end != '|'; ++ p_s_index_end) {
				if(!isdigit(*p_s_index_end)) {
					delete[] p_s_source_code;
					p_s_source_code = 0; // delete source code to mark error
					return;
				}
			}
			// check index (must be digits terminated by '|' or null character (end of string))

			if(!p_parameter[i].Fill(p_s_param_list, p_s_name_end - p_s_param_list,
			   atol(p_s_index), p_s_name_end[1] == 'e')) {
				delete[] p_s_source_code;
				p_s_source_code = 0; // delete source code to mark error
				return;
			}
			// fill parameter data

			p_s_param_list = p_s_next_parameter + 1;
		}
		// copy parameters
	}
}

/*
 *	TShaderInfo::TProgram::~TProgram()
 *		- destructor
 */
TShaderInfo::TProgram::~TProgram()
{
	if(p_parameter)
		delete[] p_parameter;
}

/*
 *	bool TShaderInfo::TProgram::AddParameter(const char *p_s_name,
 *		bool b_environment, int n_register_index)
 *		- adds new parameter with name p_s_name, locality b_environment, placed in
 *		  register with zero-based index n_register_index
 *		- returns true on success, false on failure
 */
bool TShaderInfo::TProgram::AddParameter(const char *p_s_name,
	bool b_environment, int n_register_index)
{
	TParamInfo *p_new_param;
	if(!(p_new_param = new(std::nothrow) TParamInfo[n_parameter_num + 1]))
		return false;
	// alloc new parameter list

	if(!p_new_param[n_parameter_num].Fill(p_s_name,
	   -1, n_register_index, b_environment)) {
		delete[] p_new_param;
		return false;
	}
	// create new parameter

	for(int i = 0; i < n_parameter_num; ++ i)
		p_new_param[i].Swap(p_parameter[i]);
	// swap old parameters

	if(p_parameter)
		delete[] p_parameter;
	p_parameter = p_new_param;
	++ n_parameter_num;
	// delete old array, swap pointers, increment counter

	return true;
}

/*
 *	bool TShaderInfo::TProgram::Copy(const TProgram &r_program)
 *		- copies contents of r_program to this
 *		- returns true on success, false on failure
 */
bool TShaderInfo::TProgram::Copy(const TProgram &r_program)
{
	if(p_parameter) {
		delete[] p_parameter;
		p_parameter = 0;
	}
	// free parameters

	if(!TShader::Copy(r_program))
		return false;
	// copy source code and samplers

	if(n_parameter_num = r_program.n_parameter_num) {
		if(!(p_parameter = new(std::nothrow) TParamInfo[n_parameter_num]))
			return false;
		for(int i = 0; i < n_parameter_num; ++ i) {
			if(!p_parameter[i].Fill(r_program.p_parameter[i].p_s_Name(), -1,
			   r_program.p_parameter[i].n_resource_index,
			   r_program.p_parameter[i].b_environment))
				return false;
		}
	}
	// copy parameters

	return true;
}

/*
 *								=== ~TShaderInfo::TProgram ===
 */

/*
 *								=== TShaderInfo::TNamedResource ===
 */

/*
 *	bool TShaderInfo::TNamedResource::Fill(const char *_p_s_name,
 *		int n_name_length, int _n_resource_index)
 *		- fills-in values; _p_s_name is resource name, n_name_length is name length,
 *		  or -1 in case name is null-terminated and _n_resource_index is resource index
 *		- returns true on success, false on failure
 */
bool TShaderInfo::TNamedResource::Fill(const char *_p_s_name,
	int n_name_length, int _n_resource_index)
{
	if(p_s_name)
		delete[] p_s_name;
	// delete old name

	if(n_name_length < 0)
		n_name_length = strlen(_p_s_name);
	if(!(p_s_name = new(std::nothrow) char[n_name_length + 1]))
		return false;
#if defined(_MSC_VER) && !defined(__MWERKS__) && _MSC_VER >= 1400
	strncpy_s(p_s_name, (n_name_length + 1) * sizeof(char), _p_s_name, n_name_length);
#else // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
	strncpy(p_s_name, _p_s_name, n_name_length);
#endif // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
	p_s_name[n_name_length] = 0;
	// alloc new name

	n_resource_index = _n_resource_index;
	return true;
}

/*
 *	void TShaderInfo::TNamedResource::Swap(TNamedResource &r_t_info)
 *		- swaps contents of this and r_t_info
 */
void TShaderInfo::TNamedResource::Swap(TNamedResource &r_t_info)
{
	char *p_s_tmp_name = p_s_name;
	p_s_name = r_t_info.p_s_name;
	r_t_info.p_s_name = p_s_tmp_name;
	int n_tmp_resource_index = n_resource_index;
	n_resource_index = r_t_info.n_resource_index;
	r_t_info.n_resource_index = n_tmp_resource_index;
}

/*
 *								=== ~TShaderInfo::TNamedResource ===
 */

/*
 *								=== CAllocator ===
 */

/*
 *	bool CAllocator::b_IsFree(int n_index) const
 *		- returns true if entity n_index is free, otherwise returns false
 */
bool CAllocator::b_IsFree(int n_index) const
{
	return std::find(m_used_list.begin(),
		m_used_list.end(), n_index) == m_used_list.end();
}

/*
 *	bool CAllocator::Take(int n_index)
 *		- takes entity n_index so it is no longer free
 *		- returns true on success, false on failure (not enough memory)
 */
bool CAllocator::Take(int n_index)
{
	_ASSERTE(b_IsFree(n_index));
	if(!stl_ut::Reserve_1More(m_used_list))
		return false;
	m_used_list.push_back(n_index);
	return true;
}

/*
 *	int CAllocator::n_NextFree() const
 *		- returns the next free entity (but does not take it)
 */
int CAllocator::n_NextFree() const
{
	for(int i = 0;; ++ i) {
		if(b_IsFree(i))
			return i;
	}
}

/*
 *								=== ~CAllocator ===
 */

typedef void (*BindFuncPtr)(CGLState*, const CGLProgram*, int, int, const void*);

/*
 *								=== TGLShaderBinder_Core ===
 */

struct TGLShaderBinder_Core {
	static void func_Uniform1fv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_Core_shader);
		((CGL_Core_shader*)p_shader)->_SetParam1fv(n_location, n_count, (const float*)p_value);
	}

	static void func_Uniform2fv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_Core_shader);
		((CGL_Core_shader*)p_shader)->_SetParam2fv(n_location, n_count, (const float*)p_value);
	}

	static void func_Uniform3fv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_Core_shader);
		((CGL_Core_shader*)p_shader)->_SetParam3fv(n_location, n_count, (const float*)p_value);
	}

	static void func_Uniform4fv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_Core_shader);
		((CGL_Core_shader*)p_shader)->_SetParam4fv(n_location, n_count, (const float*)p_value);
	}

	static void func_Uniform1iv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_Core_shader);
		((CGL_Core_shader*)p_shader)->_SetParam1iv(n_location, n_count, (const int*)p_value);
	}

	static void func_Uniform2iv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_Core_shader);
		((CGL_Core_shader*)p_shader)->_SetParam2iv(n_location, n_count, (const int*)p_value);
	}

	static void func_Uniform3iv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_Core_shader);
		((CGL_Core_shader*)p_shader)->_SetParam3iv(n_location, n_count, (const int*)p_value);
	}

	static void func_Uniform4iv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_Core_shader);
		((CGL_Core_shader*)p_shader)->_SetParam4iv(n_location, n_count, (const int*)p_value);
	}

	static void func_Uniform1uiv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_Core_shader);
		((CGL_Core_shader*)p_shader)->_SetParam1uiv(n_location, n_count, (const unsigned int*)p_value);
	}

	static void func_Uniform2uiv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_Core_shader);
		((CGL_Core_shader*)p_shader)->_SetParam2uiv(n_location, n_count, (const unsigned int*)p_value);
	}

	static void func_Uniform3uiv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_Core_shader);
		((CGL_Core_shader*)p_shader)->_SetParam3uiv(n_location, n_count, (const unsigned int*)p_value);
	}

	static void func_Uniform4uiv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_Core_shader);
		((CGL_Core_shader*)p_shader)->_SetParam4uiv(n_location, n_count, (const unsigned int*)p_value);
	}

	static void func_UniformMatrix2fv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_Core_shader);
		((CGL_Core_shader*)p_shader)->_SetParamMatrix2fv(
			n_location, n_count, false, (const float*)p_value);
	}

	static void func_UniformMatrix3fv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_Core_shader);
		((CGL_Core_shader*)p_shader)->_SetParamMatrix3fv(
			n_location, n_count, false, (const float*)p_value);
	}

	static void func_UniformMatrix4fv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_Core_shader);
		((CGL_Core_shader*)p_shader)->_SetParamMatrix4fv(
			n_location, n_count, false, (const float*)p_value);
	}

	static void func_UniformMatrix2x3fv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_Core_shader);
		((CGL_Core_shader*)p_shader)->_SetParamMatrix2x3fv(
			n_location, n_count, false, (const float*)p_value);
	}

	static void func_UniformMatrix2x4fv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_Core_shader);
		((CGL_Core_shader*)p_shader)->_SetParamMatrix2x4fv(
			n_location, n_count, false, (const float*)p_value);
	}

	static void func_UniformMatrix3x2fv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_Core_shader);
		((CGL_Core_shader*)p_shader)->_SetParamMatrix3x2fv(
			n_location, n_count, false, (const float*)p_value);
	}

	static void func_UniformMatrix3x4fv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_Core_shader);
		((CGL_Core_shader*)p_shader)->_SetParamMatrix3x4fv(
			n_location, n_count, false, (const float*)p_value);
	}

	static void func_UniformMatrix4x2fv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_Core_shader);
		((CGL_Core_shader*)p_shader)->_SetParamMatrix4x2fv(
			n_location, n_count, false, (const float*)p_value);
	}

	static void func_UniformMatrix4x3fv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_Core_shader);
		((CGL_Core_shader*)p_shader)->_SetParamMatrix4x3fv(
			n_location, n_count, false, (const float*)p_value);
	}

	static const BindFuncPtr func_ProgramEnvParameter4fvARB_vp;
	static const BindFuncPtr func_ProgramEnvParameter4fvARB_fp;
	static const BindFuncPtr func_ProgramLocalParameter4fvARB_vp;
	static const BindFuncPtr func_ProgramLocalParameter4fvARB_fp;
};

const BindFuncPtr TGLShaderBinder_Core::func_ProgramEnvParameter4fvARB_vp = 0;
const BindFuncPtr TGLShaderBinder_Core::func_ProgramEnvParameter4fvARB_fp = 0;
const BindFuncPtr TGLShaderBinder_Core::func_ProgramLocalParameter4fvARB_vp = 0;
const BindFuncPtr TGLShaderBinder_Core::func_ProgramLocalParameter4fvARB_fp = 0;

/*
 *								=== ~TGLShaderBinder_Core ===
 */

/*
 *								=== TGLShaderBinder_ARB ===
 */

struct TGLShaderBinder_ARB {
	static void func_Uniform1fv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_ARB_shader);
		((CGL_ARB_shader*)p_shader)->_SetParam1fv(n_location, n_count, (const float*)p_value);
	}

	static void func_Uniform2fv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_ARB_shader);
		((CGL_ARB_shader*)p_shader)->_SetParam2fv(n_location, n_count, (const float*)p_value);
	}

	static void func_Uniform3fv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_ARB_shader);
		((CGL_ARB_shader*)p_shader)->_SetParam3fv(n_location, n_count, (const float*)p_value);
	}

	static void func_Uniform4fv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_ARB_shader);
		((CGL_ARB_shader*)p_shader)->_SetParam4fv(n_location, n_count, (const float*)p_value);
	}

	static void func_Uniform1iv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_ARB_shader);
		((CGL_ARB_shader*)p_shader)->_SetParam1iv(n_location, n_count, (const int*)p_value);
	}

	static void func_Uniform2iv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_ARB_shader);
		((CGL_ARB_shader*)p_shader)->_SetParam2iv(n_location, n_count, (const int*)p_value);
	}

	static void func_Uniform3iv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_ARB_shader);
		((CGL_ARB_shader*)p_shader)->_SetParam3iv(n_location, n_count, (const int*)p_value);
	}

	static void func_Uniform4iv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_ARB_shader);
		((CGL_ARB_shader*)p_shader)->_SetParam4iv(n_location, n_count, (const int*)p_value);
	}

	static void func_UniformMatrix2fv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_ARB_shader);
		((CGL_ARB_shader*)p_shader)->_SetParamMatrix2fv(
			n_location, n_count, false, (const float*)p_value);
	}

	static void func_UniformMatrix3fv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_ARB_shader);
		((CGL_ARB_shader*)p_shader)->_SetParamMatrix3fv(
			n_location, n_count, false, (const float*)p_value);
	}

	static void func_UniformMatrix4fv(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_ARB_shader);
		((CGL_ARB_shader*)p_shader)->_SetParamMatrix4fv(
			n_location, n_count, false, (const float*)p_value);
	}

	static const BindFuncPtr func_ProgramEnvParameter4fvARB_vp;
	static const BindFuncPtr func_ProgramEnvParameter4fvARB_fp;
	static const BindFuncPtr func_ProgramLocalParameter4fvARB_vp;
	static const BindFuncPtr func_ProgramLocalParameter4fvARB_fp;
	static const BindFuncPtr func_Uniform1uiv;
	static const BindFuncPtr func_Uniform2uiv;
	static const BindFuncPtr func_Uniform3uiv;
	static const BindFuncPtr func_Uniform4uiv;
	static const BindFuncPtr func_UniformMatrix2x3fv;
	static const BindFuncPtr func_UniformMatrix2x4fv;
	static const BindFuncPtr func_UniformMatrix3x2fv;
	static const BindFuncPtr func_UniformMatrix3x4fv;
	static const BindFuncPtr func_UniformMatrix4x2fv;
	static const BindFuncPtr func_UniformMatrix4x3fv;
};

const BindFuncPtr TGLShaderBinder_ARB::func_ProgramEnvParameter4fvARB_vp = 0;
const BindFuncPtr TGLShaderBinder_ARB::func_ProgramEnvParameter4fvARB_fp = 0;
const BindFuncPtr TGLShaderBinder_ARB::func_ProgramLocalParameter4fvARB_vp = 0;
const BindFuncPtr TGLShaderBinder_ARB::func_ProgramLocalParameter4fvARB_fp = 0;
const BindFuncPtr TGLShaderBinder_ARB::func_Uniform1uiv = 0;
const BindFuncPtr TGLShaderBinder_ARB::func_Uniform2uiv = 0;
const BindFuncPtr TGLShaderBinder_ARB::func_Uniform3uiv = 0;
const BindFuncPtr TGLShaderBinder_ARB::func_Uniform4uiv = 0;
const BindFuncPtr TGLShaderBinder_ARB::func_UniformMatrix2x3fv = 0;
const BindFuncPtr TGLShaderBinder_ARB::func_UniformMatrix2x4fv = 0;
const BindFuncPtr TGLShaderBinder_ARB::func_UniformMatrix3x2fv = 0;
const BindFuncPtr TGLShaderBinder_ARB::func_UniformMatrix3x4fv = 0;
const BindFuncPtr TGLShaderBinder_ARB::func_UniformMatrix4x2fv = 0;
const BindFuncPtr TGLShaderBinder_ARB::func_UniformMatrix4x3fv = 0;

/*
 *								=== ~TGLShaderBinder_ARB ===
 */

/*
 *								=== TGLProgramBinder_ARB ===
 */

struct TGLProgramBinder_ARB {
	static void func_ProgramEnvParameter4fvARB_vp(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_ARB_program);
		_ASSERTE(n_count == 1);
		((CGL_ARB_program*)p_shader)->_SetEnvParam4fv_VP(n_location, (const float*)p_value);
	}

	static void func_ProgramEnvParameter4fvARB_fp(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_ARB_program);
		_ASSERTE(n_count == 1);
		((CGL_ARB_program*)p_shader)->_SetEnvParam4fv_FP(n_location, (const float*)p_value);
	}

	static void func_ProgramLocalParameter4fvARB_vp(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_ARB_program);
		_ASSERTE(n_count == 1);
		((CGL_ARB_program*)p_shader)->_SetLocalParam4fv_VP(n_location, (const float*)p_value);
	}

	static void func_ProgramLocalParameter4fvARB_fp(CGLState *p_state,
		const CGLProgram *p_shader, int n_location, int n_count, const void *p_value)
	{
		_ASSERTE(p_shader->n_Api() == shader_api_ARB_program);
		_ASSERTE(n_count == 1);
		((CGL_ARB_program*)p_shader)->_SetLocalParam4fv_FP(n_location, (const float*)p_value);
	}

	static const BindFuncPtr func_Uniform1fv;
	static const BindFuncPtr func_Uniform2fv;
	static const BindFuncPtr func_Uniform3fv;
	static const BindFuncPtr func_Uniform4fv;
	static const BindFuncPtr func_Uniform1iv;
	static const BindFuncPtr func_Uniform2iv;
	static const BindFuncPtr func_Uniform3iv;
	static const BindFuncPtr func_Uniform4iv;
	static const BindFuncPtr func_Uniform1uiv;
	static const BindFuncPtr func_Uniform2uiv;
	static const BindFuncPtr func_Uniform3uiv;
	static const BindFuncPtr func_Uniform4uiv;
	static const BindFuncPtr func_UniformMatrix2fv;
	static const BindFuncPtr func_UniformMatrix3fv;
	static const BindFuncPtr func_UniformMatrix4fv;
	static const BindFuncPtr func_UniformMatrix2x3fv;
	static const BindFuncPtr func_UniformMatrix2x4fv;
	static const BindFuncPtr func_UniformMatrix3x2fv;
	static const BindFuncPtr func_UniformMatrix3x4fv;
	static const BindFuncPtr func_UniformMatrix4x2fv;
	static const BindFuncPtr func_UniformMatrix4x3fv;
};

const BindFuncPtr TGLProgramBinder_ARB::func_Uniform1fv = 0;
const BindFuncPtr TGLProgramBinder_ARB::func_Uniform2fv = 0;
const BindFuncPtr TGLProgramBinder_ARB::func_Uniform3fv = 0;
const BindFuncPtr TGLProgramBinder_ARB::func_Uniform4fv = 0;
const BindFuncPtr TGLProgramBinder_ARB::func_Uniform1iv = 0;
const BindFuncPtr TGLProgramBinder_ARB::func_Uniform2iv = 0;
const BindFuncPtr TGLProgramBinder_ARB::func_Uniform3iv = 0;
const BindFuncPtr TGLProgramBinder_ARB::func_Uniform4iv = 0;
const BindFuncPtr TGLProgramBinder_ARB::func_Uniform1uiv = 0;
const BindFuncPtr TGLProgramBinder_ARB::func_Uniform2uiv = 0;
const BindFuncPtr TGLProgramBinder_ARB::func_Uniform3uiv = 0;
const BindFuncPtr TGLProgramBinder_ARB::func_Uniform4uiv = 0;
const BindFuncPtr TGLProgramBinder_ARB::func_UniformMatrix2fv = 0;
const BindFuncPtr TGLProgramBinder_ARB::func_UniformMatrix3fv = 0;
const BindFuncPtr TGLProgramBinder_ARB::func_UniformMatrix4fv = 0;
const BindFuncPtr TGLProgramBinder_ARB::func_UniformMatrix2x3fv = 0;
const BindFuncPtr TGLProgramBinder_ARB::func_UniformMatrix2x4fv = 0;
const BindFuncPtr TGLProgramBinder_ARB::func_UniformMatrix3x2fv = 0;
const BindFuncPtr TGLProgramBinder_ARB::func_UniformMatrix3x4fv = 0;
const BindFuncPtr TGLProgramBinder_ARB::func_UniformMatrix4x2fv = 0;
const BindFuncPtr TGLProgramBinder_ARB::func_UniformMatrix4x3fv = 0;

/*
 *								=== ~TGLProgramBinder_ARB ===
 */

/*
 *								=== CGetBindFunction ===
 */

template <class TParamBinder>
class CGetBindFunction {
public:
	static BindFuncPtr p_Function(int n_param_target, int n_param_type)
	{
		switch(n_param_target) {
		case shader_param_Uniform:
			switch(n_param_type) {
			case uniform_Float:
				return TParamBinder::func_Uniform1fv;
			case uniform_Float2:
				return TParamBinder::func_Uniform2fv;
			case uniform_Float3:
				return TParamBinder::func_Uniform3fv;
			case uniform_Float4:
				return TParamBinder::func_Uniform4fv;
			case uniform_Int:
			case uniform_Bool:
				return TParamBinder::func_Uniform1iv;
			case uniform_Int2:
			case uniform_Bool2:
				return TParamBinder::func_Uniform2iv;
			case uniform_Int3:
			case uniform_Bool3:
				return TParamBinder::func_Uniform3iv;
			case uniform_Int4:
			case uniform_Bool4:
				return TParamBinder::func_Uniform4iv;
			case uniform_Unsigned_Int:
				return TParamBinder::func_Uniform1uiv;
			case uniform_Unsigned_Int2:
				return TParamBinder::func_Uniform2uiv;
			case uniform_Unsigned_Int3:
				return TParamBinder::func_Uniform3uiv;
			case uniform_Unsigned_Int4:
				return TParamBinder::func_Uniform4uiv;
			case uniform_Matrix2:
				return TParamBinder::func_UniformMatrix2fv;
			case uniform_Matrix3:
				return TParamBinder::func_UniformMatrix3fv;
			case uniform_Matrix4:
				return TParamBinder::func_UniformMatrix4fv;
			case uniform_Matrix2x3:
				return TParamBinder::func_UniformMatrix2x3fv;
			case uniform_Matrix2x4:
				return TParamBinder::func_UniformMatrix2x4fv;
			case uniform_Matrix3x2:
				return TParamBinder::func_UniformMatrix3x2fv;
			case uniform_Matrix3x4:
				return TParamBinder::func_UniformMatrix3x4fv;
			case uniform_Matrix4x2:
				return TParamBinder::func_UniformMatrix4x2fv;
			case uniform_Matrix4x3:
				return TParamBinder::func_UniformMatrix4x3fv;
			default:
				if((n_param_type & uniform_ClassMask) == uniform_class_Sampler)
					return TParamBinder::func_Uniform1iv;
				return 0;
			}
			return 0;
		case shader_param_Parameter_Env_VP:
			return TParamBinder::func_ProgramEnvParameter4fvARB_vp;
		case shader_param_Parameter_Env_FP:
			return TParamBinder::func_ProgramEnvParameter4fvARB_fp;
		case shader_param_Parameter_Local_VP:
			return TParamBinder::func_ProgramLocalParameter4fvARB_vp;
		case shader_param_Parameter_Local_FP:
			return TParamBinder::func_ProgramLocalParameter4fvARB_fp;
		default:
			return 0;
		}
	}
};

/*
 *								=== ~CGetBindFunction ===
 */

/*
 *								=== CGLShaderObject::TSetParamCmd ===
 */

struct CGLShaderObject::TSetParamCmd {
	BindFuncPtr p_function; // function
	unsigned int n_offset; // offset to parameter value
	int n_location; // index to register bank
	int n_count; // parameter array size
	// working values

	int n_register_num; // number of registers, occupied by a single value
	int n_params_size; // size of parameter in memory
	// intermediate values

	class CFillParamCmds;

	inline TSetParamCmd()
	{}

	inline TSetParamCmd(CParHandle_Base3 &r_param, int n_api)
	{
		n_location = r_param.n_Register();
		n_count = r_param.n_Count();
		n_offset = r_param.n_Offset();

		switch(n_api) {
		case shader_api_ARB_program:
			p_function = CGetBindFunction<TGLProgramBinder_ARB>::p_Function(
				r_param.n_Target(), r_param.n_Type());
			break;
		case shader_api_ARB_shader:
			p_function = CGetBindFunction<TGLShaderBinder_ARB>::p_Function(
				r_param.n_Target(), r_param.n_Type());
			break;
		case shader_api_Core_shader:
			p_function = CGetBindFunction<TGLShaderBinder_Core>::p_Function(
				r_param.n_Target(), r_param.n_Type());
			break;
		default:
			p_function = 0;
			break;
		};

		switch(r_param.n_Target()) {
		case shader_param_Uniform:
			switch(r_param.n_Type() & uniform_ClassMask) {
			case uniform_class_FloatVec:
				n_params_size = n_count * sizeof(float) *
					(r_param.n_Type() >> uniform_SizeShift);
				n_register_num = 1;
				break;
			case uniform_class_IntVec:
			case uniform_class_BoolVec:
			case uniform_class_UnsignedIntVec:
			case uniform_class_Sampler: // as well
				n_params_size = n_count * sizeof(int) *
					(r_param.n_Type() >> uniform_SizeShift);
				n_register_num = 1;
				break;
			case uniform_class_Matrix:
				n_params_size = n_count * sizeof(float) *
					(r_param.n_Type() >> uniform_SizeShift);
				{
					int n_mat_size = r_param.n_Type() >> uniform_SizeShift; // 4, 9 or 16
					n_mat_size -= 4; // 0, 5 or 12
					n_mat_size /= 5; // 0, 1 or 2
					n_mat_size += 2; // 2, 3 or 4 ... which is register num
					_ASSERTE(n_mat_size * n_mat_size == (r_param.n_Type() >>
						uniform_SizeShift));
					n_register_num = n_mat_size;
				}
				break;
			case uniform_class_NonSquareMatrix:
				n_params_size = n_count * sizeof(float) *
					(r_param.n_Type() >> uniform_SizeShift);
				{
					int n_mat_type = r_param.n_Type() & uniform_TypeMask;
					_ASSERTE(n_mat_type >= 0 && n_mat_type < 6);
					const int p_register_num[] = {3, 4, 2, 4, 2, 3};
					n_register_num = p_register_num[n_mat_type];
				}
				break;
			default:
				p_function = 0; // set invalid value to mark error
				_ASSERTE(0); // shouldn't happen
				break;
			}
			break;
		case shader_param_Parameter_Env_VP:
		case shader_param_Parameter_Env_FP:
		case shader_param_Parameter_Local_VP:
		case shader_param_Parameter_Local_FP:
			_ASSERTE(r_param.n_Type() == parameter_Float4 && n_count == 1);
			n_params_size = n_count * 4 * sizeof(float);
			n_register_num = 1;
			break;
		default:
			p_function = 0; // set invalid value to mark error
			_ASSERTE(0); // shouldn't happen
			break;
		}
	}

	inline bool operator <(const TSetParamCmd &r_t_param_cmd) const
	{
		if(p_function < r_t_param_cmd.p_function)
			return true;
		else if(p_function > r_t_param_cmd.p_function)
			return false;
		return n_location < r_t_param_cmd.n_location;
	}
};

/*
 *								=== ~CGLShaderObject::TSetParamCmd ===
 */

/*
 *								=== CGLShaderObject::TSetParamCmd::CFillParamCmds ===
 */

class CGLShaderObject::TSetParamCmd::CFillParamCmds {
protected:
	std::vector<TSetParamCmd> &m_r_cmd_list;
	int m_n_shader_api;

public:
	inline CFillParamCmds(std::vector<TSetParamCmd> &r_cmd_list, int n_shader_api)
		:m_r_cmd_list(r_cmd_list), m_n_shader_api(n_shader_api)
	{}

	inline void operator ()(CParHandle_Base3 &r_param)
	{
		m_r_cmd_list.push_back(TSetParamCmd(r_param, m_n_shader_api));
	}
};

/*
 *								=== ~CGLShaderObject::TSetParamCmd::CFillParamCmds ===
 */

/*
 *								=== CGLShaderObject::CFindMergeableCmd ===
 */

class CGLShaderObject::CFindMergeableCmd {
protected:
	int m_n_location;
	BindFuncPtr m_p_function;
	unsigned int m_n_src_location;

public:
	inline CFindMergeableCmd(const TSetParamCmd &r_t_cmd)
		:m_n_location(r_t_cmd.n_location + r_t_cmd.n_count * r_t_cmd.n_register_num),
		m_p_function(r_t_cmd.p_function),
		m_n_src_location(r_t_cmd.n_offset + r_t_cmd.n_params_size)
	{}

	inline bool operator ()(const TSetParamCmd &r_t_cmd)
	{
		if(r_t_cmd.p_function != m_p_function ||
		   r_t_cmd.n_location != m_n_location ||
		   r_t_cmd.n_offset != m_n_src_location)
			return true;
		// different functions or locations

		/*if(m_p_function == TGLShaderBinder_Core::func_Uniform1iv ||
		   m_p_function == TGLShaderBinder_ARB::func_Uniform1iv)
			return true;*/
		// sometimes it doesn't like having texture sampler uniforms loaded in array

		m_n_location = r_t_cmd.n_location + r_t_cmd.n_count * r_t_cmd.n_register_num;
		m_n_src_location = r_t_cmd.n_offset + r_t_cmd.n_params_size;
		// location of next mergeable command

		return false;
	}
};

/*
 *								=== ~CGLShaderObject::CFindMergeableCmd ===
 */

/*
 *								=== CGLShaderObject::CSumCounts ===
 */

class CGLShaderObject::CSumCounts {
protected:
	unsigned int m_n_count;

public:
	inline CSumCounts()
		:m_n_count(0)
	{}

	inline void operator ()(const TSetParamCmd &r_t_cmd)
	{
		m_n_count += r_t_cmd.n_count;
	}

	inline operator int() const
	{
		return m_n_count;
	}
};

/*
 *								=== ~CGLShaderObject::CSumCounts ===
 */

/*
 *								=== CGLShaderObject ===
 */

/*
 *	CGLShaderObject::CGLShaderObject(const TShaderInfo *p_vertex_shader,
 *		const TShaderInfo *p_fragment_shader)
 *		- default constructor
 *		- m_p_vertex_shader and m_p_fragment_shader holds shader source code,
 *		  one of them can be 0
 *		- pointers are going to be referenced only, objects they point must remain
 *		  allocated till destruction of this object
 */
CGLShaderObject::CGLShaderObject(const TShaderInfo *p_vertex_shader,
	const TShaderInfo *p_fragment_shader)
	:m_p_vertex_shader(p_vertex_shader), m_p_geometry_shader(0),
	m_p_fragment_shader(p_fragment_shader), m_p_shader(0), m_p_params(0), m_p_set_param_cmd(0)
{
	m_b_use_shader_target = b_ShaderAvailability(true) && b_ShaderSupport(true);
	// see it's possible to use high-level shading language
	// (in case it isn't, it still doesn't mean it's possible to use low-level shading language)
}

/*
 *	CGLShaderObject::CGLShaderObject(const TShaderInfo *p_vertex_shader,
 *		const TShaderInfo *p_geometry_shader, const TShaderInfo *p_fragment_shader)
 *		- default constructor
 *		- p_vertex_shader, p_geometry_shader and p_fragment_shader holds shader source
 *		  code, at least one of them must not be 0
 *		- pointers are going to be referenced only, objects they point must remain
 *		  allocated till destruction of this object
 */
CGLShaderObject::CGLShaderObject(const TShaderInfo *p_vertex_shader, const TShaderInfo *p_geometry_shader,
	const TShaderInfo *p_fragment_shader)
	:m_p_vertex_shader(p_vertex_shader), m_p_geometry_shader(p_geometry_shader),
	m_p_fragment_shader(p_fragment_shader), m_p_shader(0), m_p_params(0), m_p_set_param_cmd(0)
{
	m_b_use_shader_target = b_ShaderAvailability(true) && b_ShaderSupport(true);
	// see it's possible to use high-level shading language
	// (in case it isn't, it still doesn't mean it's possible to use low-level shading language)
}

/*
 *	CGLShaderObject::~CGLShaderObject()
 *		- destructor
 */
CGLShaderObject::~CGLShaderObject()
{
	Delete_Shaders();
}

/*
 *	const char *CGLShaderObject::p_s_VertexShader_Name() const
 *		- returns name of vertex shader if present or 0 if not present
 */
const char *CGLShaderObject::p_s_VertexShader_Name() const
{
	return (m_p_vertex_shader)? m_p_vertex_shader->p_s_name : 0;
}

/*
 *	const char *CGLShaderObject::p_s_GeometryShader_Name() const
 *		- returns name of geometry shader if present or 0 if not present
 */
const char *CGLShaderObject::p_s_GeometryShader_Name() const
{
	return (m_p_geometry_shader)? m_p_geometry_shader->p_s_name : 0;
}

/*
 *	const char *CGLShaderObject::p_s_FragmentShader_Name() const
 *		- returns name of fragment shader if present or 0 if not present
 */
const char *CGLShaderObject::p_s_FragmentShader_Name() const
{
	return (m_p_fragment_shader)? m_p_fragment_shader->p_s_name : 0;
}

/*
 *	const TShaderInfo *CGLShaderObject::p_VertexShader_Info() const
 *		- returns pointer to vertex shader informations
 *		  or 0 in case there's no vertex shader
 */
const TShaderInfo *CGLShaderObject::p_VertexShader_Info() const
{
	return m_p_vertex_shader;
}

/*
 *	const TShaderInfo *CGLShaderObject::p_GeometryShader_Info() const
 *		- returns pointer to geometry shader informations
 *		  or 0 in case there's no geometry shader
 */
const TShaderInfo *CGLShaderObject::p_GeometryShader_Info() const
{
	return m_p_geometry_shader;
}

/*
 *	const TShaderInfo *CGLShaderObject::p_FragmentShader_Info() const
 *		- returns pointer to fragment shader informations
 *		  or 0 in case there's no fragment shader
 */
const TShaderInfo *CGLShaderObject::p_FragmentShader_Info() const
{
	return m_p_fragment_shader;
}

/*
 *	bool CGLShaderObject::b_ShaderSupport(bool b_shader_target) const
 *		- returns true in case extensions necessary to compile supplied
 *		  shaders is available (in case vertex shader only was supplied,
 *		  vertex shader support is sufficient, the same applies for fragment shader)
 *		- b_shader_target specifies shader language (low-level program;
 *		  b_shader_target = false or high-level shader; b_shader_target = true)
 *		  note this function doesn't check for source code availability in
 *		  supplied shaders (i.e. it's possible low-level shading language is supported
 *		  but supplied shaders are available in high-level shading language only)
 *		- returns false in case (all) required extensions aren't supported
 */
bool CGLShaderObject::b_ShaderSupport(bool b_shader_target) const
{
	bool b_arbprog_support = !m_p_geometry_shader &&
		CGL_ARB_program::b_Supported(m_p_vertex_shader != 0, m_p_fragment_shader != 0);
	bool b_arbshd_support = !m_p_geometry_shader &&
		CGL_ARB_shader::b_Supported(m_p_vertex_shader != 0, m_p_fragment_shader != 0);
	bool b_coreshd_support = CGL_Core_shader::b_Supported(m_p_vertex_shader != 0,
		m_p_geometry_shader != 0, m_p_fragment_shader != 0);
	// determine shader support

	return (b_shader_target && (b_arbshd_support || b_coreshd_support)) ||
		(!b_shader_target && b_arbprog_support);
	// find out wheter necessary extensions are supported

	/*return (b_shader_target && (!m_p_vertex_shader || m_p_vertex_shader->p_high) &&
		(!m_p_fragment_shader || m_p_fragment_shader->p_high) &&
		(CGL_ARB_shader::b_Supported(m_p_vertex_shader != 0, m_p_fragment_shader != 0) ||
		CGL_Core_shader::b_Supported(m_p_vertex_shader != 0, m_p_fragment_shader != 0))) ||
		(!b_shader_target && (!m_p_vertex_shader || m_p_vertex_shader->p_low) &&
		(!m_p_fragment_shader || m_p_fragment_shader->p_low) &&
		CGL_ARB_program::b_Supported(m_p_vertex_shader != 0, m_p_fragment_shader != 0));*/
	// optimized version; without geometry shaders
}

/*
 *	bool CGLShaderObject::b_ShaderAvailability(bool b_shader_target) const
 *		- returns true in case shaders in language, specified by b_shader_target are
 *		  available (returns false in case no shader was specified)
 *		- b_shader_target specifies shader language (low-level program;
 *		  b_shader_target = false or high-level shader; b_shader_target = true)
 *		  note this function doesn't check for OpenGL support
 *		- returns false in case (all specified) shaders are not available
 *		  in a given language
 */
bool CGLShaderObject::b_ShaderAvailability(bool b_shader_target) const
{
	if(!m_p_vertex_shader && !m_p_geometry_shader && !m_p_fragment_shader)
		return false;
	if(m_p_vertex_shader && ((b_shader_target && !m_p_vertex_shader->p_high) ||
	   (!b_shader_target && !m_p_vertex_shader->p_low)))
		return false;
	if(m_p_geometry_shader && ((b_shader_target && !m_p_geometry_shader->p_high) ||
	   (!b_shader_target && !m_p_geometry_shader->p_low)))
		return false;
	if(m_p_fragment_shader && ((b_shader_target && !m_p_fragment_shader->p_high) ||
	   (!b_shader_target && !m_p_fragment_shader->p_low)))
		return false;
	return true;
	// more readable version, with geometry shaders

	/*return (m_p_vertex_shader || m_p_fragment_shader || m_p_geometry_shader) &&
		((b_shader_target && (!m_p_vertex_shader || m_p_vertex_shader->p_high) &&
		(!m_p_fragment_shader || m_p_fragment_shader->p_high)) ||
		(!b_shader_target && (!m_p_vertex_shader || m_p_vertex_shader->p_low) &&
		(!m_p_fragment_shader || m_p_fragment_shader->p_low)));*/
	// optimized version; without geometry shaders
}

/*
 *	bool CGLShaderObject::b_Status() const
 *		- returns true in case vertex and pixel shaders are compatible
 *		  so it's possible to compile them; otherwise returns false
 */
bool CGLShaderObject::b_Status() const
{
	return (b_ShaderAvailability(true) && b_ShaderSupport(true)) ||
		(b_ShaderAvailability(false) && b_ShaderSupport(false));
}

/*
 *	bool CGLShaderObject::b_ShaderTarget() const
 *		- returns true in case high level shading language is going to be used
 *		- returns false in case low level shading language is going to be used
 */
bool CGLShaderObject::b_ShaderTarget() const
{
	return m_b_use_shader_target;
}

/*
 *	void CGLShaderObject::Prefer_ShaderTarget(bool b_shader_target)
 *		- hint to use low (b_shader_target = false) or high (b_shader_target = true)
 *		  level shading language
 *		- in case shaders are present in desired shading  language, it is going
 *		  to be used. otherwise available shading language is going to be used
 */
void CGLShaderObject::Prefer_ShaderTarget(bool b_shader_target)
{
	if(b_ShaderAvailability(b_shader_target) && b_ShaderSupport(b_shader_target))
		m_b_use_shader_target = b_shader_target;
}

/*
 *	bool CGLShaderObject::Compile_Link(CGLState *p_state, char *&r_p_s_compile_log,
 *		char *&r_p_s_link_log)
 *		- compile and link shaders
 *		- p_state is active opengl state guard
 *		- r_p_s_compile_log is compilation log, (compiller error / warnings output)
 *		  r_p_s_link_log is linkage log, (linker error / warnings output)
 *		  in case compiller / linker generated error / warning (text) output,
 *		  string is allocated and pointer is put here. (it has to be freed) otherwise
 *		  the pointer is set to 0
 *		- returns true in case shaders were successfuly compiled and linked
 *		  (note despite that warnings could have been generated, see log string pointers)
 */
bool CGLShaderObject::Compile_Link(CGLState *p_state, char *&r_p_s_compile_log,
	char *&r_p_s_link_log)
{
	r_p_s_compile_log = 0;
	r_p_s_link_log = 0;

	if(!b_ShaderAvailability(m_b_use_shader_target) || !b_ShaderSupport(m_b_use_shader_target)) {
		m_b_use_shader_target = !m_b_use_shader_target;
		if(!b_ShaderAvailability(m_b_use_shader_target) || !b_ShaderSupport(m_b_use_shader_target))
			return false;
	}
	// see if all necessary shaders and extensions are available

	_ASSERTE(p_state);
	Delete_Shaders();

	if(m_b_use_shader_target) {
		if(CGL_Core_shader::b_Supported(m_p_vertex_shader != 0,
		   m_p_geometry_shader != 0, m_p_fragment_shader != 0)) {
			if(!(m_p_shader = new(std::nothrow) CGL_Core_shader(
			   (m_p_vertex_shader)? m_p_vertex_shader->p_high->p_s_Source_Code() : 0,
			   (m_p_geometry_shader)? m_p_geometry_shader->p_high->p_s_Source_Code() : 0,
			   (m_p_fragment_shader)? m_p_fragment_shader->p_high->p_s_Source_Code() : 0)))
				return false;
		} else /*if(CGL_ARB_shader::b_Supported(m_p_vertex_shader != 0,
		   m_p_fragment_shader != 0))*/ {
			_ASSERTE(CGL_ARB_shader::b_Supported(m_p_vertex_shader != 0, m_p_fragment_shader != 0));
			_ASSERTE(!m_p_geometry_shader);
			if(!(m_p_shader = new(std::nothrow) CGL_ARB_shader(
			   (m_p_vertex_shader)? m_p_vertex_shader->p_high->p_s_Source_Code() : 0,
			   (m_p_fragment_shader)? m_p_fragment_shader->p_high->p_s_Source_Code() : 0)))
				return false;
		}
	} else {
		_ASSERTE(CGL_ARB_program::b_Supported(m_p_vertex_shader != 0, m_p_fragment_shader != 0));
		_ASSERTE(!m_p_geometry_shader);
		if(!(m_p_shader = new(std::nothrow) CGL_ARB_program(
		   (m_p_vertex_shader)? m_p_vertex_shader->p_low->p_s_Source_Code() : 0,
		   (m_p_fragment_shader)? m_p_fragment_shader->p_low->p_s_Source_Code() : 0)))
			return false;
	}
	// create a new shader object

	if(!m_p_shader->Compile(p_state, r_p_s_compile_log) ||
	   (m_b_use_shader_target && !((CGLShader*)m_p_shader)->Link(r_p_s_link_log))) {
		delete m_p_shader;
		m_p_shader = 0;
		return false;
	}
	// compile and link shader

	if((m_b_use_shader_target && !Resolve_Uniforms()) ||
	   (!m_b_use_shader_target && !Fill_Parameters()))
		return false;
	// fill lists with shader parameter handles

	if(m_p_geometry_shader) {
		_ASSERTE(m_p_shader->n_Api() == shader_api_Core_shader);
		CGL_Core_shader *p_shd = (CGL_Core_shader*)m_p_shader;
		if(!p_shd->SetGeometry_InputType(m_p_geometry_shader->n_geometry_in_type) ||
		   !p_shd->SetGeometry_OutputType(m_p_geometry_shader->n_geometry_out_type) ||
		   !p_shd->SetGeometry_VerticesOut(m_p_geometry_shader->n_max_vertex_num))
			return false;
	}
	// configure geometry shader

#ifdef __ENABLE_MERGE_UNIFORM_UPLOADS
	if(!CreateSetParamsCommands(true))
		return false;
#else // __ENABLE_MERGE_UNIFORM_UPLOADS
	if(!CreateSetParamsCommands(false))
		return false;
#endif // __ENABLE_MERGE_UNIFORM_UPLOADS
	// create commands necessary to set shader parameters

	return true;
}

/*
 *	bool CGLShaderObject::Resolve_Uniforms()
 *		- fill lists with shader uniform handles
 *		- returns true on success, false on failure
 *		- assumes parameter handle lists are empty
 */
bool CGLShaderObject::Resolve_Uniforms()
{
	if(!m_b_use_shader_target || !m_p_shader)
		return false;

	_ASSERTE(m_parameter_list.empty() && !m_p_params);
	// make sure parameter variables are deallocated

	_ASSERTE(m_p_shader->n_Api() == shader_api_ARB_shader ||
		m_p_shader->n_Api() == shader_api_Core_shader);
	CGLShader *p_shader = (CGLShader*)m_p_shader;
	// Resolve_Uniforms can be called for shader targets only (programs don't have uniforms)

	if(!stl_ut::Reserve_N(m_parameter_list, p_shader->n_Uniform_Num()))
		return false;
	// allocate enough space for parameter handles

	for(int i = 0, n = p_shader->n_Uniform_Num(); i < n; ++ i) {
		char *p_s_name;
		int n_register, n_type, n_count;
		if(!(p_s_name = p_shader->p_s_Uniform_Name(i, n_type, n_count)))
			return false;
		// get uniform name, size and type

		if(!strncmp(p_s_name, "gl_", 3)) {
			delete[] p_s_name;
			continue;
		}
		// my new drivers also returns names of OpenGL reserved objects,
		// such as gl_ModelViewProjectionMatrixTranspose

		if((n_register = p_shader->n_GetUniformLocation(p_s_name)) == -1)
			return false;
		// get uniform register address

		m_parameter_list.push_back(CParHandle_Base3(shader_param_Uniform,
			p_s_name, n_type, n_register, n_count, 0));
		// create a new parameter and put it to the list
	}
	// fill parameter handles list

	std::sort(m_parameter_list.begin(), m_parameter_list.end());
	// sort parameters by location

	unsigned int n_params_size = 0;
	// size of buffer for storing parameters

	for(int i = 0, n = m_parameter_list.size(); i < n; ++ i) {
		m_parameter_list[i].SetOffset(n_params_size);
		// set offset

		int n_content_class = m_parameter_list[i].n_Type() & uniform_ClassMask;
		int n_content_size = m_parameter_list[i].n_Type() >> uniform_SizeShift;
		if(n_content_class == uniform_class_FloatVec ||
		   n_content_class == uniform_class_Matrix ||
		   n_content_class == uniform_class_NonSquareMatrix)
			n_params_size += n_content_size * sizeof(int);
		else if(n_content_class == uniform_class_IntVec ||
		   n_content_class == uniform_class_UnsignedIntVec ||
		   n_content_class == uniform_class_BoolVec ||
		   n_content_class == uniform_class_Sampler)
			n_params_size += n_content_size * sizeof(int);
		else {
			_ASSERTE(0); // unknown parameter type; that is programming error in fact
			return false;
		}
	}
	// set offsets to parameters data buffer, determine parameters buffer size

	if(!(m_p_params = new(std::nothrow) CGLShaderParams(m_parameter_list, n_params_size, this)))
		return false;
	// create shader parameters

	CAllocator allocator;
	// texture unit allocator

	for(int n_pass = 0; n_pass < 2; ++ n_pass) {
		for(std::vector<CParHandle_Base3>::iterator p_sampler_iter = m_parameter_list.begin();
		   (p_sampler_iter = std::find_if(p_sampler_iter, m_parameter_list.end(),
		   std::mem_fun_ref(&CParHandle_Base3::b_IsSampler))) != m_parameter_list.end();
		   ++ p_sampler_iter) {
			const char *p_s_sam_name = (*p_sampler_iter).p_s_Name();
			// get sampler name

			int n_tex_unit = -1;
			for(int n_stage = 0; n_stage < 3; ++ n_stage) {
				const TShaderInfo *p_shader_info;
				if(n_stage == 0)
					p_shader_info = p_VertexShader_Info();
				else if(n_stage == 1)
					p_shader_info = p_GeometryShader_Info();
				else
					p_shader_info = p_FragmentShader_Info();
				if(!p_shader_info)
					continue;
				TShaderInfo::TShader *p_shader = p_shader_info->p_high;
				// do it for all vertex, geometry and fragment shaders

				if((n_tex_unit = p_shader->n_TexUnit(p_s_sam_name)) != -1)
					break;
			}
			// try to find texture unit assignment

			if(!n_pass && n_tex_unit == -1)
				continue;
			// in the first pass, we want to assign explicitly allocated texture units only

			if(n_pass && n_tex_unit != -1)
				continue;
			// in second pass, we want to assign the rest of unassigned texture units

			if(n_tex_unit == -1 || !allocator.b_IsFree(n_tex_unit))
				n_tex_unit = allocator.n_NextFree();
			if(!allocator.Take(n_tex_unit))
				return false;
			// handle texture unit allocation

			m_p_params->Set_TextureUnit(p_s_sam_name, n_tex_unit);
			// set texture unit index
		}
	}
	// assign texture units

	return true;
}

/*
 *	bool CGLShaderObject::Resolve_Uniforms()
 *		- fill lists with program parameter handles
 *		- returns true on success, false on failure
 *		- assumes parameter handle lists are empty
 */
bool CGLShaderObject::Fill_Parameters()
{
	if(m_b_use_shader_target || !m_p_shader)
		return false;

	_ASSERTE(m_parameter_list.empty() && !m_p_params);
	// make sure parameter variables are deallocated

	unsigned int n_parameter_num =
		((m_p_vertex_shader)? m_p_vertex_shader->p_low->n_Parameter_Num() : 0) +
		((m_p_fragment_shader)? m_p_fragment_shader->p_low->n_Parameter_Num() : 0);
	if(!stl_ut::Reserve_N(m_parameter_list, n_parameter_num))
		return false;
	// alloc space for all parameter handles

	unsigned int n_params_size = 0;
	// parameters buffer size

	for(int n_stage = 0; n_stage < 3; ++ n_stage) {
		const TShaderInfo *p_shader_info;
		if(n_stage == 0)
			p_shader_info = p_VertexShader_Info();
		else if(n_stage == 1)
			p_shader_info = p_GeometryShader_Info();
		else
			p_shader_info = p_FragmentShader_Info();
		if(!p_shader_info)
			continue;
		TShaderInfo::TProgram *p_program = p_shader_info->p_low;
		// do it for all vertex, geometry and fragment programs

		for(int i = 0, n = p_program->n_Parameter_Num(); i < n; ++ i) {
			const TShaderInfo::TParamInfo &t_parameter = p_program->t_Parameter(i);

			char *p_s_name;
			if(!(p_s_name = cpp_strdup(t_parameter.p_s_Name())))
				return false;
			// copy name
			
			int n_target = (t_parameter.b_environment)?
				((p_shader_info == m_p_vertex_shader)? shader_param_Parameter_Env_VP :
				shader_param_Parameter_Env_FP) : ((p_shader_info == m_p_vertex_shader)?
				shader_param_Parameter_Local_VP : shader_param_Parameter_Local_FP);
			// find out what seems to be parameter target

			m_parameter_list.push_back(CParHandle_Base3(n_target,
				p_s_name, parameter_Float4, t_parameter.n_resource_index, 1, n_params_size));
			// create a new parameter and put it to the list

			n_params_size += 4 * sizeof(float);
		}
	}
	// add all parameter handles

	if(!(m_p_params = new(std::nothrow) CGLShaderParams(m_parameter_list, n_params_size, this)))
		return false;
	// create shader parameters

	return true;
}

/*
 *	bool CGLShaderObject::CreateSetParamsCommands(bool b_merge_commands)
 *		- creates commands for setting shader parameters
 *		- in case b_merge_commands is true, merges commands loading the same
 *		  types of data to coinciding GPU registers (note this requires less
 *		  OpenGL calls but assumes some style of memory layout which might be
 *		  dependent on OpenGL implementation; experimental feature)
 *		- returns true on success, false on failure
 */
bool CGLShaderObject::CreateSetParamsCommands(bool b_merge_commands)
{
	_ASSERTE(!m_p_set_param_cmd);

	std::vector<TSetParamCmd> cmd_list;
	if(!stl_ut::Reserve_N(cmd_list, m_parameter_list.size()))
		return false;
	// alloc temp lists for commands (some of them will be merged later)

	std::for_each(m_parameter_list.begin(), m_parameter_list.end(),
		TSetParamCmd::CFillParamCmds(cmd_list, m_p_shader->n_Api()));
	// create commands

	std::stable_sort(cmd_list.begin(), cmd_list.end());
	// sort parameters by function, by register and
	// parameter buffer location

	if(b_merge_commands) {
		for(std::vector<TSetParamCmd>::iterator p_cur = cmd_list.begin();
		   p_cur != cmd_list.end();) {
			std::vector<TSetParamCmd>::iterator p_merge_end;
			p_merge_end = std::find_if(p_cur + 1, cmd_list.end(), CFindMergeableCmd(*p_cur));
			// find last command that can be merged with p_cur

			(*p_cur).n_count = std::for_each(p_cur, p_merge_end, CSumCounts());
			// sum count of array elements

			if(++ p_cur < p_merge_end)
				cmd_list.erase(p_cur, p_merge_end);
		}
	}
	// merge commands loading the same types of data to coinciding parts of memory
	// (note this requires less OpenGL calls but assumes some style of memory layout
	// which might be dependent on OpenGL implementation)

	if(!(m_p_set_param_cmd = new(std::nothrow) TSetParamCmd[cmd_list.size()]))
		return false;
	for(unsigned int i = 0; i < cmd_list.size(); ++ i) {
		if(!cmd_list[i].p_function)
			return false;
		m_p_set_param_cmd[i] = cmd_list[i];
	}
	m_n_set_param_cmd_num = cmd_list.size();
	// copy set commands

	return true;
}

/*
 *	CGLShaderParams *CGLShaderObject::p_GetParameterBuffer() const
 *		- returns a new shader parameters object, containing a new
 *		  instance of shader parameter values
 *		- returns 0 in case there was not enough memory or in case shader was not compiled
 */
CGLShaderParams *CGLShaderObject::p_GetParameterBuffer() const
{
	if(!m_p_params)
		return 0;
	CGLShaderParams *p_params;
	if(!(p_params = new(std::nothrow) CGLShaderParams(*m_p_params)))
		return 0;
	if(!p_params->b_Valid()) {
		delete p_params;
		return 0;
	}
	// create copy of shader params

	return p_params;
}

/*
 *	bool CGLShaderObject::GetParameterBuffer(TParamBuffer &r_params) const
 *		- copies current values of shader parameters (as set to CGLShaderObject,
 *		  doesn't query OpenGL) to an existing parameter buffer r_t_buffer
 *		  (obtained by calling p_GetParameterBuffer)
 *		- returns true on success, false on failure
 *		- note parameter buffer isn't connected to CGLShaderObject, changing
 *		  it's values will not affect shader parameter values (to do that, call
 *		  SetParameterBuffer)
 */
bool CGLShaderObject::GetParameterBuffer(CGLShaderParams &r_params) const
{
	if(!m_p_params)
		return false;
	return r_params.CopyData(*m_p_params);
}

/*
 *	bool CGLShaderObject::SetParameterBuffer(const CGLShaderParams &r_params)
 *		- sets shader parameter values from parameter buffer r_t_buffer
 *		  (obtained by calling p_GetParameterBuffer)
 *		- returns true on success, false on failure
 *		- note this must be called before Bind in order to take effect
 */
bool CGLShaderObject::SetParameterBuffer(const CGLShaderParams &r_params)
{
	if(!m_p_params)
		return false;
	return m_p_params->CopyData(r_params);
}

/*
 *	CShaderVectorParameterRef<float> CGLShaderObject::t_Find_Parameter(
 *		const char *p_s_parameter_name)
 *		- find float shader parameter by name p_s_parameter_name
 *		- returns shader parameter reference object, it's valid on success, invalid on failure
 *		  (in case shaders weren't compiled or parameter with p_s_parameter_name doesn't exist)
 */
CShaderVectorParameterRef<float> CGLShaderObject::t_Find_Parameter(const char *p_s_parameter_name)
{
	if(!m_p_params)
		return CShaderVectorParameterRef<float>(0, 0, 0, 0);
	return m_p_params->t_Find_Parameter(p_s_parameter_name);
}

/*
 *	CShaderVectorParameterRef<int> CGLShaderObject::t_Find_IntParameter(
 *		const char *p_s_parameter_name)
 *		- find integer shader parameter by name p_s_parameter_name
 *		- returns shader parameter reference object, it's valid on success, invalid on failure
 *		  (in case shaders weren't compiled or parameter with p_s_parameter_name doesn't exist)
 *		- note integer shader parameters are available in high-level shading language only
 */
CShaderVectorParameterRef<int> CGLShaderObject::t_Find_IntParameter(const char *p_s_parameter_name)
{
	if(!m_p_params)
		return CShaderVectorParameterRef<int>(0, 0, 0, 0);
	return m_p_params->t_Find_IntParameter(p_s_parameter_name);
}

/*
 *	CShaderVectorParameterRef<unsigned int> CGLShaderObject::t_Find_UnsignedIntParameter(
 *		const char *p_s_parameter_name)
 *		- find unsigned integer shader parameter by name p_s_parameter_name (EXT_gpu_shader4)
 *		- returns shader parameter reference object, it's valid on success, invalid on failure
 *		  (in case shaders weren't compiled or parameter with p_s_parameter_name doesn't exist)
 *		- note integer shader parameters are available in high-level shading language only
 */
CShaderVectorParameterRef<unsigned int> CGLShaderObject::t_Find_UnsignedIntParameter(
	const char *p_s_parameter_name)
{
	if(!m_p_params)
		return CShaderVectorParameterRef<unsigned int>(0, 0, 0, 0);
	return m_p_params->t_Find_UnsignedIntParameter(p_s_parameter_name);
}

/*
 *	CShaderVectorParameterRef<int> CGLShaderObject::t_Find_BoolParameter(
 *		const char *p_s_parameter_name)
 *		- find boolean shader parameter by name p_s_parameter_name
 *		- returns shader parameter reference object, it's valid on success, invalid on failure
 *		  (in case shaders weren't compiled or parameter with p_s_parameter_name doesn't exist)
 *		- note boolean shader parameters are available in high-level shading language only
 */
CShaderVectorParameterRef<int> CGLShaderObject::t_Find_BoolParameter(
	const char *p_s_parameter_name)
{
	if(!m_p_params)
		return CShaderVectorParameterRef<int>(0, 0, 0, 0);
	return m_p_params->t_Find_BoolParameter(p_s_parameter_name);
}

/*
 *	CShaderMatrixParameterRef CGLShaderObject::t_Find_MatrixParameter(
 *		const char *p_s_parameter_name)
 *		- find matrix shader parameter by name p_s_parameter_name
 *		- returns shader parameter reference object, it's valid on success, invalid on failure
 *		  (in case shaders weren't compiled or parameter with p_s_parameter_name doesn't exist)
 *		- note matrix shader parameters are available in high-level shading language only
 */
CShaderMatrixParameterRef CGLShaderObject::t_Find_MatrixParameter(const char *p_s_parameter_name)
{
	if(!m_p_params)
		return CShaderMatrixParameterRef(0, 0, 0, 0, 0);
	return m_p_params->t_Find_MatrixParameter(p_s_parameter_name);
}

/*
 *	CShaderMatrixParameterRef CGLShaderObject::t_Find_NonSquareMatrixParameter(
 *		const char *p_s_parameter_name)
 *		- finds matrix shader parameter by name p_s_parameter_name
 *		- returns shader parameter reference object, it's valid on success, invalid on failure
 *		  (in case shaders weren't compiled or parameter with p_s_parameter_name doesn't exist)
 *		- note matrix shader parameters are available in high-level shading language only
 *		- note non-square matrix shader parameters are available in OpenGL 2.1 and higher
 */
CShaderMatrixParameterRef CGLShaderObject::t_Find_NonSquareMatrixParameter(
	const char *p_s_parameter_name)
{
	if(!m_p_params)
		return CShaderMatrixParameterRef(0, 0, 0, 0, 0);
	return m_p_params->t_Find_NonSquareMatrixParameter(p_s_parameter_name);
}

/*
 *	int CGLShaderObject::n_SamplerType(const char *p_s_sampler_name) const
 *		- finds texture type by name p_s_sampler_name
 *		- returns sampler type (one of uniform_Sampler1D, uniform_Sampler2D, ...,
 *		  uniform_Sampler_Unsigned_Int_Buffer) or 0 on failure
 *		- note samplers are available in high-level shading language only
 */
int CGLShaderObject::n_SamplerType(const char *p_s_sampler_name) const
{
	if(!m_p_params)
		return 0;
	return m_p_params->n_SamplerType(p_s_sampler_name);
}

/*
 *	int CGLShaderObject::n_TextureUnit(const char *p_s_sampler_name) const
 *		- finds texture unit by name p_s_sampler_name (available for programs as well)
 *		- returns texture unit index (0 to GL_MAX_TEXTURE_UNITS - 1) or -1 on failure
 */
int CGLShaderObject::n_TextureUnit(const char *p_s_sampler_name) const
{
	if(!m_p_params)
		return -1;
	return m_p_params->n_TextureUnit(p_s_sampler_name);
}

/*
 *	bool CGLShaderObject::Set_TextureUnit(const char *p_s_sampler_name, int n_tex_unit)
 *		- finds sampler by name p_s_sampler_name and sets it's value to n_tex_unit
 *		- n_tex_unit is zero-based texture unit index (0 to GL_MAX_TEXTURE_UNITS - 1)
 *		- returns true on success, false on failure
 */
bool CGLShaderObject::Set_TextureUnit(const char *p_s_sampler_name, int n_tex_unit)
{
	if(!m_p_params)
		return false;
	return m_p_params->Set_TextureUnit(p_s_sampler_name, n_tex_unit);
}

/*
 *	bool CGLShaderObject::Bind(CGLState *p_state) const
 *		- bind shader, set parameters supplied earlier
 */
bool CGLShaderObject::Bind(CGLState *p_state) const
{
	if(!m_p_shader)
		return false;

	m_p_shader->Bind(p_state);
	// results in shorter assembly, m_p_shader->n_Api() is virtual itself

	/*if(m_p_shader->n_Api() == shader_api_Core_shader) {
		CGL_Core_shader *p_shader = (CGL_Core_shader*)m_p_shader;
		p_shader->_Bind(p_state);
		// bind shader
	} else if(m_p_shader->n_Api() == shader_api_ARB_shader) {
		CGL_ARB_shader *p_shader = (CGL_ARB_shader*)m_p_shader;
		p_shader->_Bind(p_state);
		// bind shader
	} else if(m_p_shader->n_Api() == shader_api_ARB_program) {
		CGL_ARB_program *p_program = (CGL_ARB_program*)m_p_shader;
		p_program->_Bind(p_state);
		// bind shader
	} else
		return false;*/

	const unsigned char *p_params_data = m_p_params->p_DataBuffer();
	for(const TSetParamCmd *p_cmd = m_p_set_param_cmd, *p_end = m_p_set_param_cmd +
	   m_n_set_param_cmd_num; p_cmd != p_end; ++ p_cmd) {
		p_cmd->p_function(p_state, m_p_shader, p_cmd->n_location,
		   p_cmd->n_count, p_params_data + p_cmd->n_offset);
	}
	// use earlier created (and optimised) commands to set shader parameters

	return true;
}

/*
 *	bool CGLShaderObject::Bind(CGLState *p_state, const CGLShaderParams *p_params) const
 *		- bind shader, set supplied parameters
 *		- note parameters object inside this shader object is not changed
 */
bool CGLShaderObject::Bind(CGLState *p_state, const CGLShaderParams *p_params) const
{
	if(!m_p_shader)
		return false;

	m_p_shader->Bind(p_state);
	// results in shorter assembly, m_p_shader->n_Api() is virtual itself

	/*if(m_p_shader->n_Api() == shader_api_Core_shader) {
		CGL_Core_shader *p_shader = (CGL_Core_shader*)m_p_shader;
		p_shader->_Bind(p_state);
		// bind shader
	} else if(m_p_shader->n_Api() == shader_api_ARB_shader) {
		CGL_ARB_shader *p_shader = (CGL_ARB_shader*)m_p_shader;
		p_shader->_Bind(p_state);
		// bind shader
	} else if(m_p_shader->n_Api() == shader_api_ARB_program) {
		CGL_ARB_program *p_program = (CGL_ARB_program*)m_p_shader;
		p_program->_Bind(p_state);
		// bind shader
	} else
		return false;*/

	if(p_params->p_Parent() != this)
		return false;
	// this doesn't belong here

	const unsigned char *p_params_data = p_params->p_DataBuffer();
	for(const TSetParamCmd *p_cmd = m_p_set_param_cmd, *p_end = m_p_set_param_cmd +
	   m_n_set_param_cmd_num; p_cmd != p_end; ++ p_cmd) {
		p_cmd->p_function(p_state, m_p_shader, p_cmd->n_location,
		   p_cmd->n_count, p_params_data + p_cmd->n_offset);
	}
	// use earlier created (and optimised) commands to set shader parameters

	return true;
}

/*
 *	void CGLShaderObject::Release(CGLState *p_state) const
 *		- release shader
 */
void CGLShaderObject::Release(CGLState *p_state) const
{
	if(m_p_shader)
		m_p_shader->Release(p_state);
}

/*
 *	int CGLShaderObject::n_Api() const
 *		- return id of api being used (shader_api_ARB_program,
 *		  shader_api_ARB_shader or shader_api_Core_shader) or
 *		  -1 in case no shader was compiled yet
 */
int CGLShaderObject::n_Api() const
{
	if(!m_p_shader)
		return -1;
	return m_p_shader->n_Api();
}

/*
 *	void CGLShaderObject::Delete_Shaders()
 *		- delete opengl shader objects (in case they were created)
 */
void CGLShaderObject::Delete_Shaders()
{
	if(m_p_shader) {
		delete m_p_shader;
		m_p_shader = 0;
	}
	// delete shader

	m_parameter_list.clear();
	// remove parameter handles

	if(m_p_params) {
		delete m_p_params;
		m_p_params = 0;
	}
	// delete parameters buffer

	if(m_p_set_param_cmd) {
		delete[] m_p_set_param_cmd;
		m_p_set_param_cmd = 0;
	}
	// delete set parameters commands

	std::for_each(m_parameter_ref_list.begin(), m_parameter_ref_list.end(),
		std::mem_fun(&CGLShaderParams::Invalidate));
	m_parameter_ref_list.clear();
	// remove and invalidate parameter references
}

/*
 *	bool CGLShaderObject::Register_Parameters(CGLShaderParams *p_params)
 *		- adds p_params to parameters list to get notification of shader's deletion
 *		- returns true on success, false on failure
 */
bool CGLShaderObject::Register_Parameters(CGLShaderParams *p_params)
{
	_ASSERTE(p_params->p_Parent() == this);
	if(!stl_ut::Reserve_1More(m_parameter_ref_list))
		return false;
	m_parameter_ref_list.push_back(p_params);
	return true;
}

/*
 *	void CGLShaderObject::Notify_ParamsDestruct(CGLShaderParams *p_params)
 *		- called by destructor of CGLShaderParams
 *		- removes p_params from parameters reference list so it doesn't
 *		  get notifications about parameters reset / etc
 */
void CGLShaderObject::Notify_ParamsDestruct(CGLShaderParams *p_params)
{
	_ASSERTE(p_params->p_Parent() == this);
	std::vector<CGLShaderParams*>::iterator p_params_iter =
		std::find(m_parameter_ref_list.begin(), m_parameter_ref_list.end(), p_params);
	if(p_params_iter != m_parameter_ref_list.end())
		m_parameter_ref_list.erase(p_params_iter);
}

/*
 *								=== ~CGLShaderObject ===
 */

/*
 *								=== CGLShaderParams ===
 */

/*
 *	CGLShaderParams::CGLShaderParams(const std::vector<CParHandle_Base3> &r_parameter_list,
 *		int n_params_size, CGLShaderObject *p_parent)
 *		- default constructor
 *		- r_parameter_list is list of parameter handles
 *		- n_params_size is size of parameter buffer in bytes
 *		- p_parent is pointer to parent shader object these params belong to
 */
CGLShaderParams::CGLShaderParams(const std::vector<CParHandle_Base3> &r_parameter_list,
	int n_params_size, CGLShaderObject *p_parent)
	:m_r_parameter_list(r_parameter_list), m_p_parent(p_parent), m_n_params_size(n_params_size)
{
	if((m_p_params_buffer = new(std::nothrow) unsigned char[n_params_size]))
		memset(m_p_params_buffer, 0, n_params_size * sizeof(unsigned char));
}

/*
 *	CGLShaderParams::CGLShaderParams(const CGLShaderParams &r_shader_params)
 *		- copy-constructor
 *		- copies data and initialization parameters 
 */
CGLShaderParams::CGLShaderParams(const CGLShaderParams &r_shader_params)
	:m_r_parameter_list(r_shader_params.m_r_parameter_list),
	m_p_parent(r_shader_params.m_p_parent), m_n_params_size(r_shader_params.m_n_params_size)
{
	if((m_p_params_buffer = new(std::nothrow) unsigned char[m_n_params_size])) {
		if(r_shader_params.m_p_params_buffer) {
			memcpy(m_p_params_buffer, r_shader_params.m_p_params_buffer,
				m_n_params_size * sizeof(unsigned char));
		} else
			memset(m_p_params_buffer, 0, m_n_params_size * sizeof(unsigned char));
		// alloc and copy buffer

		if(m_p_parent && !m_p_parent->Register_Parameters(this)) {
			m_p_parent = 0; // don't want to notify parent of invalidation since not registered
			Invalidate();
		}
		// register at parent
	}
}

/*
 *	bool CGLShaderParams::CopyData(const CGLShaderParams &r_params)
 *		- copies all shader parameters values from r_params to this
 *		- returns true on success, false in case attempt is made to copy data
 *		  between parameters that belong to different shaders or in case
 *		  either of parameters is invalid
 */
bool CGLShaderParams::CopyData(const CGLShaderParams &r_params)
{
	if(!b_Valid() || r_params.b_Valid() || m_p_parent != r_params.m_p_parent)
		return false;
	_ASSERTE(r_params.m_n_params_size == m_n_params_size);
	memcpy(m_p_params_buffer, r_params.m_p_params_buffer, m_n_params_size);
	return true;
}

/*
 *	bool CGLShaderParams::Invalidate()
 *		- invalidate shader parameters (shader object was destroyed)
 *		- this also invalidates all paraameter references
 *		- always returns true (because of mem_fun)
 */
bool CGLShaderParams::Invalidate()
{
	std::for_each(m_parameter_ref_list.begin(), m_parameter_ref_list.end(),
		std::mem_fun(&CShaderParameterRef<float>::Invalidate));
	std::for_each(m_int_bool_parameter_ref_list.begin(), m_int_bool_parameter_ref_list.end(),
		std::mem_fun(&CShaderParameterRef<int>::Invalidate));
	std::for_each(m_uint_parameter_ref_list.begin(), m_uint_parameter_ref_list.end(),
		std::mem_fun(&CShaderParameterRef<unsigned int>::Invalidate));
	// invalidate parameter references

	m_parameter_ref_list.clear();
	m_int_bool_parameter_ref_list.clear();
	m_uint_parameter_ref_list.clear();
	// clear lists of parameter references

	if(m_p_params_buffer) {
		delete[] m_p_params_buffer;
		m_p_params_buffer = 0;
	}
	// delete parameters buffer (which is validity flag!)

	if(m_p_parent) {
		m_p_parent->Notify_ParamsDestruct(this);
		m_p_parent = 0;
	}
	// delete from parent

	return true;
}

/*
 *	CShaderVectorParameterRef<float> CGLShaderParams::t_Find_Parameter(
 *		const char *p_s_parameter_name)
 *		- finds float shader parameter by name p_s_parameter_name
 *		- returns shader parameter reference object, it's valid on success, invalid on
 *		  failure (in case shaders weren't compiled or parameter with p_s_parameter_name
 *		  doesn't exist)
 */
CShaderVectorParameterRef<float> CGLShaderParams::t_Find_Parameter(const char *p_s_parameter_name)
{
	if(!b_Valid())
		return CShaderVectorParameterRef<float>(0, 0, 0, 0);

	std::vector<CParHandle_Base3>::const_iterator p_param_handle;
	if((p_param_handle = std::find(m_r_parameter_list.begin(),
	   m_r_parameter_list.end(), p_s_parameter_name)) == m_r_parameter_list.end() ||
	   ((*p_param_handle).n_Type() & uniform_ClassMask) != uniform_class_FloatVec)
		return CShaderVectorParameterRef<float>(0, 0, 0, 0);
	// find float - float4 uniform handle

	return CShaderVectorParameterRef<float>((float*)(m_p_params_buffer +
		(*p_param_handle).n_Offset()), ((*p_param_handle).n_Type() >> uniform_SizeShift),
		(*p_param_handle).n_Count(), this);
}

/*
 *	CShaderVectorParameterRef<int> CGLShaderParams::t_Find_IntParameter(
 *		const char *p_s_parameter_name)
 *		- finds integer shader parameter by name p_s_parameter_name
 *		- returns shader parameter reference object, it's valid on success, invalid on
 *		  failure (in case shaders weren't compiled or parameter with p_s_parameter_name
 *		  doesn't exist)
 *		- note integer shader parameters are available in high-level shading language only
 */
CShaderVectorParameterRef<int> CGLShaderParams::t_Find_IntParameter(const char *p_s_parameter_name)
{
	if(!b_Valid() || !m_p_parent->b_ShaderTarget())
		return CShaderVectorParameterRef<int>(0, 0, 0, 0);

	std::vector<CParHandle_Base3>::const_iterator p_param_handle;
	if((p_param_handle = std::find(m_r_parameter_list.begin(),
	   m_r_parameter_list.end(), p_s_parameter_name)) == m_r_parameter_list.end() ||
	   ((*p_param_handle).n_Type() & uniform_ClassMask) != uniform_class_IntVec)
		return CShaderVectorParameterRef<int>(0, 0, 0, 0);
	// find float - float4 uniform handle

	return CShaderVectorParameterRef<int>((int*)(m_p_params_buffer +
		(*p_param_handle).n_Offset()), ((*p_param_handle).n_Type() >> uniform_SizeShift),
		(*p_param_handle).n_Count(), this);
}

/*
 *	CShaderVectorParameterRef<unsigned int> CGLShaderParams::t_Find_UnsignedIntParameter(
 *		const char *p_s_parameter_name)
 *		- find unsigned integer shader parameter by name p_s_parameter_name (EXT_gpu_shader4)
 *		- returns shader parameter reference object, it's valid on success, invalid on
 *		  failure (in case shaders weren't compiled or parameter with p_s_parameter_name
 *		  doesn't exist)
 *		- note integer shader parameters are available in high-level shading language only
 */
CShaderVectorParameterRef<unsigned int> CGLShaderParams::t_Find_UnsignedIntParameter(const char *p_s_par_name)
{
	if(!b_Valid() || !m_p_parent->b_ShaderTarget())
		return CShaderVectorParameterRef<unsigned int>(0, 0, 0, 0);

	std::vector<CParHandle_Base3>::const_iterator p_param_handle;
	if((p_param_handle = std::find(m_r_parameter_list.begin(),
	   m_r_parameter_list.end(), p_s_par_name)) == m_r_parameter_list.end() ||
	   ((*p_param_handle).n_Type() & uniform_ClassMask) != uniform_class_UnsignedIntVec)
		return CShaderVectorParameterRef<unsigned int>(0, 0, 0, 0);
	// find float - float4 uniform handle

	return CShaderVectorParameterRef<unsigned int>((unsigned int*)(m_p_params_buffer +
		(*p_param_handle).n_Offset()), ((*p_param_handle).n_Type() >> uniform_SizeShift),
		(*p_param_handle).n_Count(), this);
}

/*
 *	CShaderVectorParameterRef<int> CGLShaderParams::t_Find_BoolParameter(
 *		const char *p_s_parameter_name)
 *		- finds boolean shader parameter by name p_s_parameter_name
 *		- returns shader parameter reference object, it's valid on success, invalid on
 *		  failure (in case shaders weren't compiled or parameter with p_s_parameter_name
 *		  doesn't exist)
 *		- note boolean shader parameters are available in high-level shading language only
 */
CShaderVectorParameterRef<int> CGLShaderParams::t_Find_BoolParameter(const char *p_s_parameter_name)
{
	if(!b_Valid() || !m_p_parent->b_ShaderTarget())
		return CShaderVectorParameterRef<int>(0, 0, 0, 0);

	std::vector<CParHandle_Base3>::const_iterator p_param_handle;
	if((p_param_handle = std::find(m_r_parameter_list.begin(),
	   m_r_parameter_list.end(), p_s_parameter_name)) == m_r_parameter_list.end() ||
	   ((*p_param_handle).n_Type() & uniform_ClassMask) != uniform_class_BoolVec)
		return CShaderVectorParameterRef<int>(0, 0, 0, 0);
	// find float - float4 uniform handle

	return CShaderVectorParameterRef<int>((int*)(m_p_params_buffer +
		(*p_param_handle).n_Offset()), ((*p_param_handle).n_Type() >> uniform_SizeShift),
		(*p_param_handle).n_Count(), this);
}

/*
 *	CShaderMatrixParameterRef CGLShaderParams::t_Find_MatrixParameter(
 *		const char *p_s_parameter_name)
 *		- finds matrix shader parameter by name p_s_parameter_name
 *		- returns shader parameter reference object, it's valid on success, invalid on
 *		  failure (in case shaders weren't compiled or parameter with p_s_parameter_name
 *		  doesn't exist)
 *		- note matrix shader parameters are available in high-level shading language only
 */
CShaderMatrixParameterRef CGLShaderParams::t_Find_MatrixParameter(const char *p_s_parameter_name)
{
	if(!b_Valid() || !m_p_parent->b_ShaderTarget())
		return CShaderMatrixParameterRef(0, 0, 0, 0, 0);

	std::vector<CParHandle_Base3>::const_iterator p_param_handle;
	if((p_param_handle = std::find(m_r_parameter_list.begin(),
	   m_r_parameter_list.end(), p_s_parameter_name)) == m_r_parameter_list.end() ||
	   ((*p_param_handle).n_Type() & uniform_ClassMask) != uniform_class_Matrix)
		return CShaderMatrixParameterRef(0, 0, 0, 0, 0);
	// find uniform handle

	int n_size2 = ((*p_param_handle).n_Type() >> uniform_SizeShift);
	int n_size = (n_size2 - 4) / 5 + 2; // 4, 9, 16 -> 0, 5, 12 -> 0, 1, 2 -> 2, 3, 4
	_ASSERTE(n_size2 == n_size * n_size);
	return CShaderMatrixParameterRef((float*)(m_p_params_buffer +
		(*p_param_handle).n_Offset()), n_size, n_size, (*p_param_handle).n_Count(), this);
}

/*
 *	CShaderMatrixParameterRef CGLShaderParams::t_Find_NonSquareMatrixParameter(
 *		const char *p_s_parameter_name)
 *		- finds non-square matrix shader parameter by name p_s_parameter_name
 *		- returns shader parameter reference object, it's valid on success, invalid on
 *		  failure (in case shaders weren't compiled or parameter with p_s_parameter_name
 *		  doesn't exist)
 *		- note matrix shader parameters are available in high-level shading language only
 *		- note non-square matrix shader parameters are available in OpenGL 2.1 and higher
 */
CShaderMatrixParameterRef CGLShaderParams::t_Find_NonSquareMatrixParameter(const char *p_s_par_name)
{
	if(!b_Valid() || !m_p_parent->b_ShaderTarget())
		return CShaderMatrixParameterRef(0, 0, 0, 0, 0);

	std::vector<CParHandle_Base3>::const_iterator p_param_handle;
	if((p_param_handle = std::find(m_r_parameter_list.begin(),
	   m_r_parameter_list.end(), p_s_par_name)) == m_r_parameter_list.end() ||
	   ((*p_param_handle).n_Type() & uniform_ClassMask) != uniform_class_NonSquareMatrix)
		return CShaderMatrixParameterRef(0, 0, 0, 0, 0);
	// find uniform handle

	int n_type = (*p_param_handle).n_Type() & uniform_TypeMask;
	const int p_height[] = {3, 4, 2, 4, 2, 3};
	int n_height = p_height[n_type];
	int n_width = ((*p_param_handle).n_Type() >> uniform_SizeShift) / n_height;
	return CShaderMatrixParameterRef((float*)(m_p_params_buffer +
		(*p_param_handle).n_Offset()), n_width, n_height, (*p_param_handle).n_Count(), this);
}

/*
 *	int CGLShaderParams::n_SamplerType(const char *p_s_sampler_name) const
 *		- finds texture type by name p_s_sampler_name
 *		- returns sampler type (one of uniform_Sampler1D, uniform_Sampler2D, ...,
 *		  uniform_Sampler_Unsigned_Int_Buffer) or 0 on failure
 *		- note samplers are available in high-level shading language only
 */
int CGLShaderParams::n_SamplerType(const char *p_s_sampler_name) const
{
	if(!b_Valid() || !m_p_parent->b_ShaderTarget())
		return 0;

	std::vector<CParHandle_Base3>::const_iterator p_sam;
	if((p_sam = std::find(m_r_parameter_list.begin(),
	   m_r_parameter_list.end(), p_s_sampler_name)) == m_r_parameter_list.end())
		return 0;
	return (*p_sam).n_Type();
}

/*
 *	int CGLShaderParams::n_TextureUnit(const char *p_s_sampler_name) const
 *		- finds texture unit by name p_s_sampler_name (available for programs as well)
 *		- returns texture unit index (0 to GL_MAX_TEXTURE_UNITS - 1) or -1 on failure
 */
int CGLShaderParams::n_TextureUnit(const char *p_s_sampler_name) const
{
	if(!b_Valid())
		return -1;

	if(m_p_parent->b_ShaderTarget()) {
		std::vector<CParHandle_Base3>::const_iterator p_sam;
		if((p_sam = std::find(m_r_parameter_list.begin(), m_r_parameter_list.end(),
		   p_s_sampler_name)) == m_r_parameter_list.end() ||
		   ((*p_sam).n_Type() & uniform_ClassMask) != uniform_class_Sampler)
			return -1;
		return *(int*)(m_p_params_buffer + (*p_sam).n_Offset());
	} else {
		for(int n_stage = 0; n_stage < 3; ++ n_stage) {
			const TShaderInfo *p_info;
			if(n_stage == 0)
				p_info = m_p_parent->p_VertexShader_Info();
			else if(n_stage == 1)
				p_info = m_p_parent->p_GeometryShader_Info();
			else
				p_info = m_p_parent->p_FragmentShader_Info();
			if(!p_info)
				continue;
			// do it for all vertex, geometry and fragment programs

			int n_tex_unit;
			if((n_tex_unit = p_info->p_low->n_TexUnit(p_s_sampler_name)) != -1)
				return n_tex_unit;
			// try to find texturing unit assignment
		}
		// find texture unit in shader source info
		return -1;
	}
}

/*
 *	bool CGLShaderParams::Set_TextureUnit(const char *p_s_sampler_name, int n_tex_unit)
 *		- finds sampler by name p_s_sampler_name and sets it's value to n_tex_unit
 *		- n_tex_unit is zero-based texture unit index (0 to GL_MAX_TEXTURE_UNITS - 1)
 *		- returns true on success, false on failure
 */
bool CGLShaderParams::Set_TextureUnit(const char *p_s_sampler_name, int n_tex_unit)
{
	if(!b_Valid() || !m_p_parent->b_ShaderTarget())
		return false;
	// must be valid and must be shader, not program

	std::vector<CParHandle_Base3>::const_iterator p_sam;
	if((p_sam = std::find(m_r_parameter_list.begin(), m_r_parameter_list.end(),
	   p_s_sampler_name)) == m_r_parameter_list.end() ||
	   ((*p_sam).n_Type() & uniform_ClassMask) != uniform_class_Sampler)
		return false;
	*(int*)(m_p_params_buffer + (*p_sam).n_Offset()) = n_tex_unit;
	return true;
}

/*
 *	bool CGLShaderParams::Register_Parameter(CShaderParameterRef<float> *p_parameter)
 *		- adds parameter p_parameter to the list
 *		- returns true on success, false in case there was not enough space in the list
 */
bool CGLShaderParams::Register_Parameter(CShaderParameterRef<float> *p_parameter)
{
	if(!stl_ut::Reserve_1More(m_parameter_ref_list))
		return false;
	m_parameter_ref_list.push_back(p_parameter);
	return true;
}

/*
 *	bool CGLShaderParams::Register_Parameter(CShaderParameterRef<int> *p_parameter)
 *		- adds parameter p_parameter to the list
 *		- returns true on success, false in case there was not enough space in the list
 */
bool CGLShaderParams::Register_Parameter(CShaderParameterRef<int> *p_parameter)
{
	if(!stl_ut::Reserve_1More(m_int_bool_parameter_ref_list))
		return false;
	m_int_bool_parameter_ref_list.push_back(p_parameter);
	return true;
}

/*
 *	bool CGLShaderParams::Register_Parameter(CShaderParameterRef<unsigned int> *p_parameter)
 *		- adds parameter p_parameter to the list
 *		- returns true on success, false in case there was not enough space in the list
 */
bool CGLShaderParams::Register_Parameter(CShaderParameterRef<unsigned int> *p_parameter)
{
	if(!stl_ut::Reserve_1More(m_uint_parameter_ref_list))
		return false;
	m_uint_parameter_ref_list.push_back(p_parameter);
	return true;
}

/*
 *	void CGLShaderParams::Notify_ParamDestruct(CShaderParameterRef<float> *p_parameter)
 *		- notification from parameter destructor
 *		- removes parameter p_parameter from the list
 */
void CGLShaderParams::Notify_ParamDestruct(CShaderParameterRef<float> *p_parameter)
{
	std::vector<CShaderParameterRef<float>*>::iterator p_param_iter =
		std::find(m_parameter_ref_list.begin(), m_parameter_ref_list.end(), p_parameter);
	if(p_param_iter != m_parameter_ref_list.end())
		m_parameter_ref_list.erase(p_param_iter);
}

/*
 *	void CGLShaderParams::Notify_ParamDestruct(CShaderParameterRef<int> *p_parameter)
 *		- notification from parameter destructor
 *		- removes parameter p_parameter from the list
 */
void CGLShaderParams::Notify_ParamDestruct(CShaderParameterRef<int> *p_parameter)
{
	std::vector<CShaderParameterRef<int>*>::iterator p_param_iter =
		std::find(m_int_bool_parameter_ref_list.begin(),
		m_int_bool_parameter_ref_list.end(), p_parameter);
	if(p_param_iter != m_int_bool_parameter_ref_list.end())
		m_int_bool_parameter_ref_list.erase(p_param_iter);
}

/*
 *	void CGLShaderParams::Notify_ParamDestruct(CShaderParameterRef<unsigned int> *p_parameter)
 *		- notification from parameter destructor
 *		- removes parameter p_parameter from the list
 */
void CGLShaderParams::Notify_ParamDestruct(CShaderParameterRef<unsigned int> *p_parameter)
{
	std::vector<CShaderParameterRef<unsigned int>*>::iterator p_param_iter =
		std::find(m_uint_parameter_ref_list.begin(),
		m_uint_parameter_ref_list.end(), p_parameter);
	if(p_param_iter != m_uint_parameter_ref_list.end())
		m_uint_parameter_ref_list.erase(p_param_iter);
}

/*
 *								=== ~CGLShaderParams ===
 */
