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

#pragma once
#ifndef __SHADER_SYSTEM_INCLUDED
#define __SHADER_SYSTEM_INCLUDED

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

#include "../NewFix.h"

#include "Shader2.h"

/*
 *	- if defined, uniforms are separate uniforms are uploaded as array 
 *	  which should result in faster shader binds (this is experimental feature)
 */
//#define __ENABLE_MERGE_UNIFORM_UPLOADS

/*enum {
	shader_param_Uniform, // ARB_*_shader unifrom
	shader_param_Parameter_Env_VP, // ARB_*_program env param, set trough VP
	shader_param_Parameter_Env_FP, // ARB_*_program env param, set trough FP
	shader_param_Parameter_Local_VP, // ARB_vertex_program local param
	shader_param_Parameter_Local_FP // ARB_fragment_program local param
};*/ // Shader2.h

/*
 *	struct TShaderInfo
 *		- contains informations on shader, loaded from .xml or .s++ file
 */
struct TShaderInfo {
	/*
	 *	TShaderInfo::<unnamed_0>
	 *		- GPU processor names
	 */
	enum {
		proc_Vertex = 0, // matches with false
		proc_Fragment, // matches with true
		proc_Geometry
	};

	int n_processor; // one of proc_Vertex, proc_Geometry, proc_Fragment
	char *p_s_name;

	GLenum n_geometry_in_type;
	GLenum n_geometry_out_type;
	int n_max_vertex_num; // geometry shader configuration

	/*
	 *	struct TShaderInfo::TNamedResource
	 *		- resource with name; universal class for samplers, texture
	 *		  unit names and base for program parameters
	 */
	struct TNamedResource {
	protected:
		char *p_s_name;

	public:
		int n_resource_index;

		/*
		 *	inline TShaderInfo::TNamedResource::TNamedResource()
		 *		- default constructor; clears name
		 */
		inline TNamedResource()
			:p_s_name(0)
		{}

		/*
		 *	inline TShaderInfo::TNamedResource::~TNamedResource()
		 *		- destructor
		 */
		inline ~TNamedResource()
		{
			if(p_s_name)
				delete[] p_s_name;
		}

		/*
		 *	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 Fill(const char *_p_s_name, int n_name_length, int _n_resource_index);

		/*
		 *	void TShaderInfo::TNamedResource::Swap(TNamedResource &r_t_info)
		 *		- swaps contents of this and r_t_info
		 */
		void Swap(TNamedResource &r_t_info);

		inline const char *p_s_Name() const
		{
			return p_s_name;
		}
	};

	/*
	 *	struct TShaderInfo::TParamInfo
	 *		- program parameter info (name, register and environment / local flag)
	 */
	struct TParamInfo : public TNamedResource {
		bool b_environment;

		/*
		 *	inline TShaderInfo::TParamInfo::TParamInfo()
		 *		- default constructor; clears name
		 */
		TParamInfo()
			:TNamedResource()
		{
			b_environment = false;
		}

		/*
		 *	bool TShaderInfo::TParamInfo::Fill(const char *_p_s_name,
		 *		int n_name_length, int _n_resource_index, bool _b_environment)
		 *		- fills-in values; _p_s_name is resource name, n_name_length is name length,
		 *		  or -1 in case name is null-terminated, _n_resource_index is resource index
		 *		  and _b_environment is environment / local parameter flag
		 *		- returns true on success, false on failure
		 */
		inline bool Fill(const char *_p_s_name, int n_name_length,
			int _n_resource_index, bool _b_environment)
		{
			bool b_result = TNamedResource::Fill(_p_s_name, n_name_length, _n_resource_index);
			b_environment = _b_environment;
			return b_result;
		}

		/*
		 *	void TShaderInfo::TParamInfo::Swap(TNamedResource &r_t_info)
		 *		- swaps contents of this and r_t_info
		 */
		inline void Swap(TParamInfo &r_t_info)
		{
			TNamedResource::Swap(r_t_info);
			bool b_tmp_environment = b_environment;
			b_environment = r_t_info.b_environment;
			r_t_info.b_environment = b_tmp_environment;
		}
	};

	/*
	 *	struct TShaderInfo::TShader
	 *		- structure, holding informations about shader (source code, sampler assignment)
	 *		- note samplers here are used for explicit texture unit assignment only; texture
	 *		  samplers are located automatically by OpenGL for high-level shaders
	 */
	struct TShader {
	protected:
		TNamedResource *p_sampler;
		int n_sampler_num;

		char *p_s_source_code;
	public:
		/*
		 *	TShaderInfo::TShader::TShader()
		 *		- default constructor; clears dynamically allocated fields
		 */
		TShader();

		/*
		 *	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
		 */
		TShader(const char *p_s_source_code, const char *p_s_sampler_list = 0);

		/*
		 *	TShaderInfo::TShader::~TShader()
		 *		- destructor
		 */
		~TShader();

		/*
		 *	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 IncludeSource(const char *p_s_include, bool b_add_to_front = 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 b_FreeTexUnit(int n_index) const;

		/*
		 *	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 n_FreeTexUnit(int n_index = 0) const;

		/*
		 *	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 n_TexUnit(const char *p_s_sampler_name) const;

		/*
		 *	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 n_AssignTextureUnit(const char *p_s_name, int n_force_index = -1);

		/*
		 *	bool TShaderInfo::TShader::Copy(const TShader &r_shader)
		 *		- copies contents of r_shader to this
		 *		- returns true on success, false on failure
		 */
		bool Copy(const TShader &r_shader);

		/*
		 *	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
		 */
		static int n_ListSize(const char *p_s_list, char n_separator);

		inline const char *p_s_Source_Code() const
		{
			return p_s_source_code;
		}

		inline int n_Sampler_Num() const
		{
			return n_sampler_num;
		}

		inline const TNamedResource &t_Sampler(int n_index) const
		{
			return p_sampler[n_index];
		}
	} *p_high;

	/*
	 *	struct TShaderInfo::TProgram
	 *		- structure, holding informations about program (source code,
	 *		  parameters and texture unit names)
	 *		- note samplers here are used for naming texture units so similar functionality
	 *		  like with high-level program's samplers can be acheived (user can get texture
	 *		  unit index by name, but cannot change it though)
	 */
	struct TProgram : public TShader {
	protected:
		TParamInfo *p_parameter;
		int n_parameter_num;

	public:
		/*
		 *	TShaderInfo::TProgram::TProgram()
		 *		- default constructor; clears dynamically allocated fields
		 */
		TProgram();

		/*
		 *	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
		 */
		TProgram(const char *p_s_source_code, const char *p_s_param_list,
			const char *p_s_tex_unit_list);

		/*
		 *	TShaderInfo::TProgram::~TProgram()
		 *		- destructor
		 */
		~TProgram();

		/*
		 *	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 AddParameter(const char *p_s_name, bool b_environment, int n_register_index);

		/*
		 *	bool TShaderInfo::TProgram::Copy(const TProgram &r_program)
		 *		- copies contents of r_program to this
		 *		- returns true on success, false on failure
		 */
		bool Copy(const TProgram &r_program);

		inline int n_Parameter_Num() const
		{
			return n_parameter_num;
		}

		inline const TParamInfo &t_Parameter(int n_index) const
		{
			return p_parameter[n_index];
		}
	} *p_low;

	/*
	 *	TShaderInfo::TShaderInfo()
	 *		- default constructor
	 */
	TShaderInfo();

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

	/*
	 *	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(const char *_p_s_name, int _n_processor,
		const char *p_s_source_code, const char *p_s_sampler_list = 0);

	/*
	 *	TShaderInfo::TShaderInfo(const TShaderInfo &r_t_shader_info)
	 *		- copy-constructor
	 */
	TShaderInfo(const TShaderInfo &r_t_shader_info);

	/*
	 *	TShaderInfo::~TShaderInfo()
	 *		- default destructor
	 */
	~TShaderInfo();

	/*
	 *	inline TShaderInfo &TShaderInfo::operator =(const TShaderInfo &r_t_shader_info)
	 *		- copy-operator
	 */
	TShaderInfo &operator =(const TShaderInfo &r_t_shader_info);

	/*
	 *	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 Copy(const TShaderInfo &r_t_shader_info);
};

/*
 *	class CAllocator
 *		- simple allocator class
 */
class CAllocator {
protected:
	std::vector<int> m_used_list;

public:
	/*
	 *	bool CAllocator::b_IsFree(int n_index) const
	 *		- returns true if entity n_index is free, otherwise returns false
	 */
	bool b_IsFree(int n_index) const;

	/*
	 *	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 Take(int n_index);

	/*
	 *	int CAllocator::n_NextFree() const
	 *		- returns the next free entity (but does not take it)
	 */
	int n_NextFree() const;
};

/*
 *	class CParHandle_Base3
 *		- base class for parameter handle
 */
class CParHandle_Base3 {
protected:
	char *m_p_s_name;
	unsigned int m_n_offset;
	int m_n_target;
	int m_n_type;
	int m_n_register;
	int m_n_count;

public:
	/*
	 *	inline CParHandle_Base3::CParHandle_Base3(int n_target, char *p_s_name,
	 *		int n_type, int n_register, int n_size, unsigned int n_offset)
	 *		- default constructor for parameter handle
	 *		- n_target is parameter target (one of shader_param_Uniform,
	 *		  shader_param_Parameter_Env_VP, shader_param_Parameter_Env_FP,
	 *		  shader_param_Parameter_Local_VP or shader_param_Parameter_Local_FP)
	 *		- p_s_name is parameter name; the pointer is used directly and it will
	 *		  be deleted by CParHandle_Base3::~CParHandle_Base3() destructor
	 *		- n_type is parameter type (one of uniform_Float, uniform_Float2, ...)
	 *		- n_register is parameter address (zero-based index to GPU register bank)
	 *		- n_count is parameter array size (1 for scalars, >= 1 for arrays)
	 *		- n_offset is parameter buffer offset (that's where parameter data are
	 *		  actually stored; this pointer is managed by CGLShaderParams)
	 */
	inline CParHandle_Base3(int n_target, char *p_s_name, int n_type,
		int n_register, int n_count, unsigned int n_offset)
		:m_p_s_name(p_s_name), m_n_offset(n_offset), m_n_target(n_target),
		m_n_type(n_type), m_n_register(n_register), m_n_count(n_count)
	{}

	/*
	 *	inline CParHandle_Base3::CParHandle_Base3(const CParHandle_Base3 &r_param)
	 *		- copy-constructor
	 */
	inline CParHandle_Base3(const CParHandle_Base3 &r_param)
		:m_n_offset(r_param.m_n_offset), m_n_target(r_param.m_n_target), m_n_type(r_param.m_n_type),
		m_n_register(r_param.m_n_register), m_n_count(r_param.m_n_count)
	{
		if((m_p_s_name = new(std::nothrow) char[strlen(r_param.m_p_s_name) + 1])) {
#if defined(_MSC_VER) && !defined(__MWERKS__) && _MSC_VER >= 1400
			strcpy_s(m_p_s_name, (strlen(r_param.m_p_s_name) + 1) * sizeof(char), r_param.m_p_s_name);
#else // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
			strcpy(m_p_s_name, r_param.m_p_s_name);
#endif // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
		}
	}

	/*
	 *	inline CParHandle_Base3::~CParHandle_Base3()
	 *		- default destructor
	 */
	inline ~CParHandle_Base3()
	{
		if(m_p_s_name)
			delete[] m_p_s_name; 
	}

	/*
	 *	inline CParHandle_Base3 CParHandle_Base3::operator =(const CParHandle_Base3 &r_param)
	 *		- assignment operator
	 */
	inline CParHandle_Base3 operator =(const CParHandle_Base3 &r_param)
	{
		if(&r_param == this)
			return *this;
		// handle self-assignment

		m_n_target = r_param.m_n_target;
		m_n_register = r_param.m_n_register;
		m_n_type = r_param.m_n_type;
		m_n_count = r_param.m_n_count;
		m_n_offset = r_param.m_n_offset;
		if(m_p_s_name)
			delete[] m_p_s_name;
		if((m_p_s_name = new(std::nothrow) char[strlen(r_param.m_p_s_name) + 1])) {
#if defined(_MSC_VER) && !defined(__MWERKS__) && _MSC_VER >= 1400
			strcpy_s(m_p_s_name, (strlen(r_param.m_p_s_name) + 1) * sizeof(char), r_param.m_p_s_name);
#else // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
			strcpy(m_p_s_name, r_param.m_p_s_name);
#endif // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
		}

		return *this;
	}

	/*
	 *	inline bool CParHandle_Base3::operator ==(const char *p_s_name) const
	 *		- comparison operator for searching parameters by their names
	 *		- returns true in case name matches (case dependent), otherwise false
	 */
	inline bool operator ==(const char *p_s_name) const
	{
		return m_p_s_name && !strcmp(m_p_s_name, p_s_name);
	}

	/*
	 *	inline const char *CParHandle_Base3::p_s_Name() const
	 *		- returns parameter name
	 */
	inline const char *p_s_Name() const
	{
		return m_p_s_name;
	}

	/*
	 *	inline int CParHandle_Base3::n_Register() const
	 *		- returns parameter location
	 */
	inline int n_Register() const
	{
		return m_n_register;
	}

	/*
	 *	inline int CParHandle_Base3::n_Target() const
	 *		- returns parameter target (one of shader_param_Uniform,
	 *		  shader_param_Parameter_Env_VP, shader_param_Parameter_Env_FP,
	 *		  shader_param_Parameter_Local_VP or shader_param_Parameter_Local_FP)
	 */
	inline int n_Target() const
	{
		return m_n_target;
	}

	/*
	 *	inline int CParHandle_Base3::n_Type() const
	 *		- returns parameter data type (one of uniform_Float, uniform_Float2, ...)
	 */
	inline int n_Type() const
	{
		return m_n_type;
	}

	/*
	 *	inline int CParHandle_Base3::n_Count() const
	 *		- returns parameter size (1 for scalars, >= 1 for arrays)
	 */
	inline int n_Count() const
	{
		return m_n_count;
	}

	/*
	 *	inline unsigned int CParHandle_Base3::n_Offset() const
	 *		- returns offset to parameter data in parameter buffer
	 */
	inline unsigned int n_Offset() const
	{
		return m_n_offset;
	}

	/*
	 *	inline void SetOffset(unsigned int n_offset)
	 *		- sets offset to parameter data in parameter buffer to n_offset
	 */
	inline void SetOffset(unsigned int n_offset)
	{
		m_n_offset = n_offset;
	}

	/*
	 *	inline bool operator <(const CParHandle_Base3 &r_t_data) const
	 *		- compares parameter location in GPU register bank
	 */
	inline bool operator <(const CParHandle_Base3 &r_t_data) const
	{
		return m_n_register < r_t_data.m_n_register;
	}

	/*
	 *	inline bool b_IsSampler()
	 *		- returns true in case parameter is sampler
	 *		- not-const version because for mem_fun
	 */
	inline bool b_IsSampler()
	{
		return (m_n_type & uniform_ClassMask) == uniform_class_Sampler;
	}
};

class CGLShaderObject;

template <class TScalarType>
class CShaderParameterRef;
template <class TScalarType>
class CShaderVectorParameterRef;
class CShaderMatrixParameterRef;

class CGLShaderParams {
protected:
	const std::vector<CParHandle_Base3> &m_r_parameter_list;
	// parameter handles (name, type, size, register and target)

	std::vector<CShaderParameterRef<float>*> m_parameter_ref_list;
	std::vector<CShaderParameterRef<int>*> m_int_bool_parameter_ref_list;
	std::vector<CShaderParameterRef<unsigned int>*> m_uint_parameter_ref_list;
	// lists of parameter references

	CGLShaderObject *m_p_parent;
	// pointer to parent shader object

	unsigned char *m_p_params_buffer;
	int m_n_params_size;
	// buffer to hold parameters values

public:
	/*
	 *	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(const std::vector<CParHandle_Base3> &r_parameter_list,
		int n_params_size, CGLShaderObject *p_parent);

	/*
	 *	CGLShaderParams::CGLShaderParams(const CGLShaderParams &r_shader_params)
	 *		- copy-constructor
	 *		- copies data and initialization parameters 
	 */
	CGLShaderParams(const CGLShaderParams &r_shader_params);

	/*
	 *	inline CGLShaderParams::~CGLShaderParams()
	 *		- default destructor
	 *		- invalidates all parameter references
	 */
	inline ~CGLShaderParams()
	{
		Invalidate(); // deletes all data to be deleted
	}

	/*
	 *	inline bool CGLShaderParams::b_Valid() const
	 *		- returns true if shader parameters are valid, false if not
	 *		- note all functions will fail in case shader parameters are not valid
	 */
	inline bool b_Valid() const
	{
		return m_p_params_buffer != 0 && m_p_parent != 0;
	}

	/*
	 *	inline const unsigned char *CGLShaderParams::p_DataBuffer() const
	 *		- returns pointer to parameters data buffer
	 *		  or 0 in case shader parameters aren't valid
	 */
	inline const unsigned char *p_DataBuffer() const
	{
		return m_p_params_buffer;
	}

	/*
	 *	inline const CGLShaderObject *CGLShaderParams::p_Parent() const
	 *		- returns pointer to parent shader object these params belong to
	 */
	inline const CGLShaderObject *p_Parent() const
	{
		return m_p_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 CopyData(const CGLShaderParams &r_params);

	/*
	 *	bool CGLShaderParams::Invalidate()
	 *		- invalidate shader parameters (shader object was destroyed)
	 *		- this also invalidates all paraameter references
	 *		- always returns true (because of mem_fun)
	 */
	bool Invalidate();

	/*
	 *	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> t_Find_Parameter(const char *p_s_parameter_name);

	/*
	 *	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> t_Find_IntParameter(const char *p_s_parameter_name);

	/*
	 *	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> t_Find_UnsignedIntParameter(const char *p_s_par_name);

	/*
	 *	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> t_Find_BoolParameter(const char *p_s_parameter_name);

	/*
	 *	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 t_Find_MatrixParameter(const char *p_s_parameter_name);

	/*
	 *	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 t_Find_NonSquareMatrixParameter(const char *p_s_par_name);

	/*
	 *	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 n_SamplerType(const char *p_s_sampler_name) const;

	/*
	 *	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 n_TextureUnit(const char *p_s_sampler_name) const;

	/*
	 *	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 Set_TextureUnit(const char *p_s_sampler_name, int n_tex_unit);

	/*
	 *	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 Register_Parameter(CShaderParameterRef<float> *p_parameter);

	/*
	 *	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 Register_Parameter(CShaderParameterRef<int> *p_parameter);

	/*
	 *	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 Register_Parameter(CShaderParameterRef<unsigned int> *p_parameter);

	/*
	 *	void CGLShaderParams::Notify_ParamDestruct(CShaderParameterRef<float> *p_parameter)
	 *		- notification from parameter destructor
	 *		- removes parameter p_parameter from the list
	 */
	void Notify_ParamDestruct(CShaderParameterRef<float> *p_parameter);

	/*
	 *	void CGLShaderParams::Notify_ParamDestruct(CShaderParameterRef<int> *p_parameter)
	 *		- notification from parameter destructor
	 *		- removes parameter p_parameter from the list
	 */
	void Notify_ParamDestruct(CShaderParameterRef<int> *p_parameter);

	/*
	 *	void CGLShaderParams::Notify_ParamDestruct(CShaderParameterRef<unsigned int> *p_parameter)
	 *		- notification from parameter destructor
	 *		- removes parameter p_parameter from the list
	 */
	void Notify_ParamDestruct(CShaderParameterRef<unsigned int> *p_parameter);
};

/*
 *	template <class TScalarType>
 *	class CShaderParameterRef
 *		- "smart" reference class to shader parameter data
 *		- invalidates itself once shader has been recompiled or deleted (shader keeps
 *		  the list of all the existing instances)
 */
template <class TScalarType>
class CShaderParameterRef {
protected:
	TScalarType *m_p_value; // target value
	int m_n_size, m_n_count;
	CGLShaderParams *m_p_parent;

public:
	/*
	 *	CShaderParameterRef::CShaderParameterRef()
	 *		- default constructor; creates invalid parameter pointing to nothing
	 */
	CShaderParameterRef()
		:m_p_value(0), m_n_size(0), m_n_count(0), m_p_parent(0)
	{}

	/*
	 *	CShaderParameterRef::CShaderParameterRef(TScalarType *p_value,
	 *		int n_size, int n_length, CGLShaderObject *p_parent)
	 *		- constructor
	 *		- p_value is destination value
	 *		- n_size is object size (1 for scalars, 2 to 4 for vectors, 4 to 16 for matrices)
	 *		- n_count is array parameter length (1 for scalars, 1 or more for arrays)
	 */
	CShaderParameterRef(TScalarType *p_value, int n_size, int n_count, CGLShaderParams *p_parent)
		:m_p_value(p_value), m_n_size(n_size), m_n_count(n_count), m_p_parent(p_parent)
	{
		if(m_p_parent && !m_p_parent->Register_Parameter(this))
			Invalidate();
	}

	/*
	 *	CShaderParameterRef::CShaderParameterRef(const CShaderParameterRef &r_source)
	 *		- copy-constructor
	 *		- registers itself in r_source's parent so it's deleted automatically as well
	 *		- note in case registering fails, it declares itself invalid
	 */
	CShaderParameterRef(const CShaderParameterRef &r_source)
		:m_p_value(r_source.m_p_value), m_n_size(r_source.m_n_size),
		m_n_count(r_source.m_n_count), m_p_parent(r_source.m_p_parent)
	{
		if(m_p_parent && !m_p_parent->Register_Parameter(this))
			Invalidate();
	}

	/*
	 *	CShaderParameterRef &CShaderParameterRef::operator =(const CShaderParameterRef &r_source)
	 *		- copy operator
	 *		- registers itself in r_source's parent so it's deleted automatically as well
	 *		- note in case registering fails, it declares itself invalid
	 */
	CShaderParameterRef &operator =(const CShaderParameterRef &r_source)
	{
		if(m_p_parent != r_source.m_p_parent) {
			if(m_p_parent)
				m_p_parent->Notify_ParamDestruct(this);
			if(r_source.m_p_parent && !r_source.m_p_parent->Register_Parameter(this)) {
				Invalidate();
				return *this;
			}
		}
		// unregister at old parent and register at new parent if necessary

		m_p_value = r_source.m_p_value;
		m_n_size = r_source.m_n_size;
		m_n_count = r_source.m_n_count;
		m_p_parent = r_source.m_p_parent;
		// copy data

		return *this;
	}

	/*
	 *	CShaderParameterRef::~CShaderParameterRef()
	 *		- default destructor
	 *		- invalidates itself automatically
	 */
	~CShaderParameterRef()
	{
		if(m_p_parent)
			m_p_parent->Notify_ParamDestruct(this);
	}

	/*
	 *	inline bool CShaderParameterRef::b_Valid() const
	 *		- returns true in case parameter is valid (shader it points to is valid)
	 */
	inline bool b_Valid() const
	{
		return m_p_value != 0;
	}

	/*
	 *	inline int n_Size() const
	 *		- returns size of parameter (1 for scalars, 2 to 4 for vectors, 4 to 16 for matrices)
	 */
	inline int n_Size() const
	{
		return m_n_size;
	}

	/*
	 *	inline int n_Count() const
	 *		- returns length of array parameter (1 for scalars, 1 or more for arrays)
	 */
	inline int n_Count() const
	{
		return m_n_count;
	}

	/*
	 *	bool CShaderParameterRef::Invalidate(bool b_remove = true)
	 *		- invalidates this parameter (used by CGLShaderObject; it keeps track of
	 *		  all it's parameters and in case it's destroyed / recompiled, it invalidates
	 *		  all parameters)
	 *		- always returns true (needed for std::mem_fun)
	 */
	bool Invalidate()
	{
		if(m_p_value) {
			m_p_value = 0;
			m_p_parent = 0;
		}
		return true;
	}
};

template <class TScalarType>
class CShaderVectorParameterRef : public CShaderParameterRef<TScalarType> {
public:
	/*
	 *	inline CShaderVectorParameterRef::CShaderVectorParameterRef()
	 *		- default constructor; creates invalid parameter pointing to nothing
	 */
	inline CShaderVectorParameterRef()
		:CShaderParameterRef<TScalarType>()
	{}

	/*
	 *	inline CShaderVectorParameterRef::CShaderVectorParameterRef(TScalarType *p_value,
	 *		int n_size, CGLShaderParams *p_parent)
	 *		- constructor
	 *		- p_value is destination value
	 *		- n_size is array size (must be 1 to 4)
	 *		- n_count is array parameter length (1 for scalars, 1 or more for arrays)
	 */
	inline CShaderVectorParameterRef(TScalarType *p_value, int n_size,
		int n_count, CGLShaderParams *p_parent)
		:CShaderParameterRef<TScalarType>(p_value, n_size, n_count, p_parent)
	{}

	/*
	 *	CShaderParameterRef::CShaderParameterRef(const CShaderParameterRef &r_source)
	 *		- copy-constructor
	 *		- registers itself in r_source's parent so it's deleted automatically as well
	 *		- note in case registering fails, it declares itself invalid
	 */
	inline CShaderVectorParameterRef(const CShaderVectorParameterRef<TScalarType> &r_source)
		:CShaderParameterRef<TScalarType>(r_source)
	{}

	/*
	 *	CShaderParameterRef &CShaderParameterRef::operator =(const CShaderParameterRef &r_source)
	 *		- copy operator
	 *		- registers itself in r_source's parent so it's deleted automatically as well
	 *		- note in case registering fails, it declares itself invalid
	 */
	inline CShaderVectorParameterRef<TScalarType> &operator =(const
		CShaderVectorParameterRef<TScalarType> &r_source)
	{
		CShaderParameterRef<TScalarType>::operator =(r_source);
		return *this;
	}

	/*
	 *	inline bool CShaderVectorParameterRef::SetValue(const TScalarType *p_value,
	 *		int n_index = 0, int n_count = 1)
	 *		- set target parameter value
	 *		- p_value is source value, number of items read from it equals parameter size
	 *		- n_index and n_count are designated to fill array parameters
	 *		  (array bounds are not checked)
	 *		- returns false in shader parameter is invalid, otherwise true
	 */
	inline bool SetValue(const TScalarType *p_value, int n_index = 0, int n_count = 1)
	{
		TScalarType *_p_value = CShaderParameterRef<TScalarType>::m_p_value;
		// gcc constraint, antialiass

		if(!_p_value)
			return false;

		unsigned int _n_size = CShaderParameterRef<TScalarType>::m_n_size;
		for(TScalarType *p_dest = _p_value + _n_size * n_index,
		   *p_end = _p_value + _n_size * (n_index + n_count);
		   p_dest != p_end; p_dest += _n_size)
			memcpy(p_dest, p_value, _n_size * sizeof(TScalarType));
		// copy parameters

		return true;
	}

	/*
	 *	inline bool CShaderVectorParameterRef::SetValue(const TScalarType t_value)
	 *		- set target parameter value
	 *		- t_value is source value, parameter size must be at least 1 (should be always)
	 *		- returns false in shader parameter is invalid, otherwise true
	 */
	bool inline SetValue(const TScalarType t_value)
	{
		TScalarType *_p_value = CShaderParameterRef<TScalarType>::m_p_value;
		unsigned int _n_size = CShaderParameterRef<TScalarType>::m_n_size;
		// gcc constraint, antialiass

		if(!_p_value || !_n_size)
			return false;

		*_p_value = t_value;
		// copy parameters

		return true;
	}

	/*
	 *	inline bool CShaderVectorParameterRef::SetValue(const TScalarType t_value0,
	 *		const TScalarType t_value1)
	 *		- set target parameter value
	 *		- t_value0 and t_value1 are source values, parameter size must be at least 2
	 *		- returns false in shader parameter is invalid, otherwise true
	 */
	bool inline SetValue(const TScalarType t_value0, const TScalarType t_value1)
	{
		TScalarType *_p_value = CShaderParameterRef<TScalarType>::m_p_value;
		unsigned int _n_size = CShaderParameterRef<TScalarType>::m_n_size;
		// gcc constraint, antialiass

		if(!_p_value || _n_size < 2)
			return false;

		_p_value[0] = t_value0;
		_p_value[1] = t_value1;
		// copy parameters

		return true;
	}

	/*
	 *	inline bool CShaderVectorParameterRef::SetValue(const TScalarType t_value0,
	 *		const TScalarType t_value1, const TScalarType t_value2)
	 *		- set target parameter value
	 *		- t_value1 trough t_value2 are source value, parameter size must be at least 3
	 *		- returns false in shader parameter is invalid, otherwise true
	 */
	bool inline SetValue(const TScalarType t_value0, const TScalarType t_value1,
		const TScalarType t_value2)
	{
		TScalarType *_p_value = CShaderParameterRef<TScalarType>::m_p_value;
		unsigned int _n_size = CShaderParameterRef<TScalarType>::m_n_size;
		// gcc constraint, antialiass

		if(!_p_value || _n_size < 3)
			return false;

		_p_value[0] = t_value0;
		_p_value[1] = t_value1;
		_p_value[2] = t_value2;
		// copy parameters

		return true;
	}

	/*
	 *	inline bool CShaderVectorParameterRef::SetValue(const TScalarType t_value0,
	 *		const TScalarType t_value1, const TScalarType t_value2, const TScalarType t_value3)
	 *		- set target parameter value
	 *		- t_value0 trough t_value3 are source value, parameter size must be at least 4
	 *		- returns false in shader parameter is invalid, otherwise true
	 */
	bool inline SetValue(const TScalarType t_value0, const TScalarType t_value1,
		const TScalarType t_value2, const TScalarType t_value3)
	{
		TScalarType *_p_value = CShaderParameterRef<TScalarType>::m_p_value;
		unsigned int _n_size = CShaderParameterRef<TScalarType>::m_n_size;
		if(!_p_value || _n_size < 4)
			return false;

		_p_value[0] = t_value0;
		_p_value[1] = t_value1;
		_p_value[2] = t_value2;
		_p_value[3] = t_value3;
		// copy parameters

		return true;
	}
};

class CShaderMatrixParameterRef : public CShaderParameterRef<float> {
protected:
	int m_n_width, m_n_height;

public:
	/*
	 *	inline CShaderMatrixParameterRef::CShaderMatrixParameterRef()
	 *		- default constructor; creates invalid parameter pointing to nothing
	 */
	inline CShaderMatrixParameterRef()
		:CShaderParameterRef<float>()
	{}

	/*
	 *	inline CShaderMatrixParameterRef::CShaderMatrixParameterRef(
	 *		float *p_value, int n_size, CGLShaderParams *p_parent)
	 *		- default constructor
	 *		- p_value is destination value
	 *		- n_width and n_height are matrix dimensions (2x3, 2x4, 3x2, 3x4, 4x2 or 4x3)
	 *		- n_count is array parameter length (1 for scalars, 1 or more for arrays)
	 */
	inline CShaderMatrixParameterRef(float *p_value,
		int n_width, int n_height, int n_count, CGLShaderParams *p_parent)
		:CShaderParameterRef<float>(p_value, n_width * n_height, n_count, p_parent),
		m_n_width(n_width), m_n_height(n_height)
	{}

	/*
	 *	inline int CShaderMatrixParameterRef::n_Width() const
	 *		- returns non-square matrix width
	 */
	inline int n_Width() const
	{
		return m_n_width;
	}

	/*
	 *	inline int CShaderMatrixParameterRef::n_Height() const
	 *		- returns non-square matrix height
	 */
	inline int n_Height() const
	{
		return m_n_height;
	}

	/*
	 *	bool CShaderMatrixParameterRef::SetValue(const float *p_value,
	 *		bool b_transpose = false, int n_index = 0, int n_count = 1)
	 *		- set target parameter value
	 *		- p_value is source value
	 *		- n_index and n_count are designated to fill array parameters
	 *		  (array bounds are not checked)
	 *		- returns true on success, false in case shader parameter is no longer valid
	 */
	bool SetValue(const float *p_value,
		bool b_transpose = false, int n_index = 0, int n_count = 1)
	{
		if(!m_p_value)
			return false;

		const int n_size = m_n_size;
		for(float *p_dest = m_p_value + m_n_size * n_index, *p_end = m_p_value +
		   m_n_size * (n_index + n_count); p_dest != p_end; p_dest += n_size) {
			if(!b_transpose)
				memcpy(p_dest, p_value, n_size * sizeof(float));
			else {
				for(int j = 0, n = m_n_height; j < n; ++ j) {
					for(int i = 0, m = m_n_width; i < m; ++ i)
						p_dest[i + m * j] = p_value[j + n * i];
				}
			}
		}

		return true;
	}
};

class CGLShaderObject {
protected:
	const TShaderInfo *m_p_vertex_shader;
	const TShaderInfo *m_p_geometry_shader;
	const TShaderInfo *m_p_fragment_shader;
	bool m_b_use_shader_target;

	CGLProgram *m_p_shader;

	std::vector<CParHandle_Base3> m_parameter_list;
	// parameter handles (name, type, size, register and target)

	std::vector<CGLShaderParams*> m_parameter_ref_list;
	// shader parameters list

	CGLShaderParams *m_p_params;
	// shader parameters

	struct TSetParamCmd;

	TSetParamCmd *m_p_set_param_cmd;
	int m_n_set_param_cmd_num; // set parameters commands

	class CFindMergeableCmd;
	class CSumCounts;

public:
	/*
	 *	CGLShaderObject::CGLShaderObject(const TShaderInfo *p_vertex_shader,
	 *		const TShaderInfo *p_fragment_shader)
	 *		- default constructor
	 *		- p_vertex_shader and 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(const TShaderInfo *p_vertex_shader, const TShaderInfo *p_fragment_shader);

	/*
	 *	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(const TShaderInfo *p_vertex_shader, const TShaderInfo *p_geometry_shader,
		const TShaderInfo *p_fragment_shader);

	/*
	 *	CGLShaderObject::~CGLShaderObject()
	 *		- destructor
	 */
	~CGLShaderObject();

	/*
	 *	const char *CGLShaderObject::p_s_VertexShader_Name() const
	 *		- returns name of vertex shader if present or 0 if not present
	 */
	const char *p_s_VertexShader_Name() const;

	/*
	 *	const char *CGLShaderObject::p_s_GeometryShader_Name() const
	 *		- returns name of geometry shader if present or 0 if not present
	 */
	const char *p_s_GeometryShader_Name() const;

	/*
	 *	const char *CGLShaderObject::p_s_FragmentShader_Name() const
	 *		- returns name of fragment shader if present or 0 if not present
	 */
	const char *p_s_FragmentShader_Name() const;

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

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

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

	/*
	 *	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 b_ShaderSupport(bool b_shader_target) const;

	/*
	 *	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 b_ShaderAvailability(bool b_shader_target) const;

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

	/*
	 *	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 b_ShaderTarget() const;

	/*
	 *	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 Prefer_ShaderTarget(bool b_shader_target);

	/*
	 *	bool CGLShaderObject::Compile_Link(CGLState *p_state, char *&r_p_s_compile_log,
	 *		char *&r_p_s_link_log)
	 *		- compiles and links 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 Compile_Link(CGLState *p_state, char *&r_p_s_compile_log, char *&r_p_s_link_log);

	/*
	 *	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 *p_GetParameterBuffer() const;

	/*
	 *	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 GetParameterBuffer(CGLShaderParams &r_params) const;

	/*
	 *	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 SetParameterBuffer(const CGLShaderParams &r_params);

	/*
	 *	CShaderVectorParameterRef<float> CGLShaderObject::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> t_Find_Parameter(const char *p_s_parameter_name);

	/*
	 *	CShaderVectorParameterRef<int> CGLShaderObject::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> t_Find_IntParameter(const char *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> t_Find_UnsignedIntParameter(const char *p_s_par_name);

	/*
	 *	CShaderVectorParameterRef<int> CGLShaderObject::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> t_Find_BoolParameter(const char *p_s_parameter_name);

	/*
	 *	CShaderMatrixParameterRef CGLShaderObject::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 t_Find_MatrixParameter(const char *p_s_parameter_name);

	/*
	 *	CShaderMatrixParameterRef CGLShaderObject::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 t_Find_NonSquareMatrixParameter(const char *p_s_par_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 n_SamplerType(const char *p_s_sampler_name) const;

	/*
	 *	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 n_TextureUnit(const char *p_s_sampler_name) const;

	/*
	 *	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 Set_TextureUnit(const char *p_s_sampler_name, int n_tex_unit);

	/*
	 *	bool CGLShaderObject::Bind(CGLState *p_state) const
	 *		- binds shader, set parameters supplied earlier
	 *		- returns true on success, false on failure
	 */
	bool Bind(CGLState *p_state) const;

	/*
	 *	bool CGLShaderObject::Bind(CGLState *p_state, const CGLShaderParams *p_params) const
	 *		- bind shader, set supplied parameters
	 *		- note parameter valuess object inside this shader object are not changed
	 */
	bool Bind(CGLState *p_state, const CGLShaderParams *p_params) const;

	/*
	 *	void CGLShaderObject::Release(CGLState *p_state) const
	 *		- releases shader
	 */
	void Release(CGLState *p_state) const;

	/*
	 *	int CGLShaderObject::n_Api() const
	 *		- returns 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 n_Api() const;

	/*
	 *	void CGLShaderObject::Delete_Shaders()
	 *		- deletes opengl shader objects (in case they were created)
	 */
	void Delete_Shaders();

	/*
	 *	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 Register_Parameters(CGLShaderParams *p_params);

	/*
	 *	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 Notify_ParamsDestruct(CGLShaderParams *p_params);

protected:
	bool Resolve_Uniforms();
	bool Fill_Parameters();
	bool CreateSetParamsCommands(bool b_merge_commands);
};

#endif // !__SHADER_SYSTEM_INCLUDED
