/*
								+--------------------------------+
								|                                |
								| ***   OpenGL 2.0 shaders   *** |
								|                                |
								|  Copyright © -tHE SWINe- 2006  |
								|                                |
								|          Shader2.cpp           |
								|                                |
								+--------------------------------+
*/

/**
 *	@file gl2/Shader2.cpp
 *	@date 2006
 *	@author -tHE SWINe-
 *	@brief OpenGL 2.0 shaders
 *
 *	@date 2006-10-09
 *
 *	passed code revision
 *
 *	removed most of ÜberLame stuff (todo - write new shader manager and generic
 *	encapsulation class)
 *	integers, containing just true or false were changed to bool
 *	fixed minor flaws in shader binding
 *	renamed to Shader2.cpp and Shader2.h respectively to avoid confusion with similar old source
 *
 *	@date 2006-11-10
 *
 *	passed code revision
 *
 *	created inline versions of Bind, Release and SetParam* functions so the encapsulation class,
 *	aware of shader api could use them (virtual functions themselves call them so there is no
 *	code written twice); note inlines are in Shader2.inl, there is too much of them to put them
 *	here
 *
 *	@date 2007-05-10
 *
 *	passed code revision
 *
 *	code to notify current GL state of shader deletion was added to GL_Free functions
 *	destructors don't invoke GL_Free in case shader isn't compiled
 *	void GL_Free(CGLState *p_state) was renamed to void Delete(void)
 *
 *	@date 2007-08-10
 *
 *	changed CGLShader::p_s_Uniform_Name(int n_index, int &r_n_content_type) const
 *	to CGLShader::p_s_Uniform_Name(int n_index, int &r_n_content_type, int &r_n_size) const
 *	so it's possible to determine size of array uniforms
 *
 *	replaced all __inline to inline for g++ compatibility
 *
 *	added CGL_ARB_program::_SetLocalParam4fv_VP(), CGL_ARB_program::_SetLocalParam4fv_FP(),
 *	CGL_ARB_program::_SetEnvParam4fv_VP() and CGL_ARB_program::_SetEnvParam4fv_FP() functions
 *	to overcome branching in CGL_ARB_program::_SetParam4fv()
 *
 *	added GL_EXT_gpu_shader4 uniform types and OpenGL 2.1 non-square matrix uniform types
 *
 *	renamed shader_param_* describing parameter data type to uniform_* as well as changed
 *	enum values so parameter type and size can be masked out of it
 *
 *	added count parameter to Uniform*v() so it's now possible to upload array uniforms
 *
 *	preparing for GL_EXT_geometry_shader
 *
 *	@date 2007-09-22
 *
 *	fixed minor bug which needlessly reallocated name string in CGL_Core_shader::p_s_Uniform_Name
 *	and CGL_ARB_shader::p_s_Uniform_Name
 *
 *	@date 2007-11-10
 *
 *	improved linux compatibility
 *
 *	rather crude change to all fast shader set parameter functions, state guard pointer
 *	was removed and parameters were rearranged so they come in the same order on stack
 *	like needed for gl functions
 *
 *	@date 2007-11-12
 *
 *	reformat (added line breaks where lines were longer than 100 characters)
 *
 *	@date 2007-11-26
 *
 *	added notice that the new NVidia drivers (163.71) slightly changed behavior of
 *	glGetProgramiv with GL_ACTIVE_UNIFORMS, as well as glGetActiveUniform so the reserved
 *	(builtin) OpenGL variables are returned as well, among other shader parameres.
 *
 *	@date 2008-03-04
 *
 *	added OpenGL 2.1 non-square matrix uniform functions and EXT_gpu_shader4 unsigned
 *	integer uniform functions
 *
 *	@date 2008-03-11
 *
 *	added geometry shaders to CGL_Core_shader, note it's not debugged functionality since
 *	i'm short on hardware to debug it on. new functions are CGL_Core_shader constructor
 *	taking three parameters (vertex, geometry and fragment shader source),
 *	CGL_Core_shader::SetGeometry_InputType, CGL_Core_shader::SetGeometry_OutputType,
 *	CGL_Core_shader::n_Geometry_MaxOutputVertices,
 *	CGL_Core_shader::n_Geometry_MaxOutputComponents, CGL_Core_shader::SetGeometry_VerticesOut
 *	and CGL_Core_shader::b_Supported with three parameters (vs, gs, fs)
 *
 *	@date 2008-03-13
 *
 *	fixed faulty assertion in Shader.cpp on line 1275 (1271 before adding this line)
 *
 *	@date 2008-08-08
 *
 *	added \#ifdef for windows 64
 *
 *	@date 2008-08-19
 *
 *	added \#include for OpenGL20.h and OpenGLState.h
 *
 *	@date 2009-05-04
 *
 *	fixed mixed windows / linux line endings
 *
 *	@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 "OpenGL20.h"
#include "OpenGLState.h"
#include "Texture.h"
#include "RenderBuffer2.h"
#include "Shader2.h"

/*
 *								=== CShaderStringTable ===
 */

class CShaderStringTable {
public:
	static const char *p_s_ARB_Program_String() { return "=== program (ARB) ===\n"; }
	static const char *p_s_ARB_VertexProgram_String() { return "=== vertex program (ARB) ===\n"; }
	static const char *p_s_ARB_FragmentProgram_String() { return "=== fragment program (ARB) ===\n"; }
	static const char *p_s_ARB_Shader_String() { return "=== shader (ARB) ===\n"; }
	static const char *p_s_ARB_VertexShader_String() { return "=== vertex shader (ARB) ===\n"; }
	static const char *p_s_ARB_FragmentShader_String() { return "=== fragment shader (ARB) ===\n"; }
	static const char *p_s_Core_Shader_String() { return "=== shader (OpenGL 2.0 core) ===\n"; }
	static const char *p_s_Core_VertexShader_String() { return "=== vertex shader (OpenGL 2.0 core) ===\n"; }
	static const char *p_s_Core_GeometryShader_String() { return "=== geometry shader (EXT) ===\n"; }
	static const char *p_s_Core_FragmentShader_String() { return "=== fragment shader (OpenGL 2.0 core) ===\n"; }
};

/*
 *								=== ~CShaderStringTable ===
 */

/*
 *								=== CShaderParamTypeConverter ===
 */

const CShaderParamTypeConverter::TTableElem CShaderParamTypeConverter::m_p_type_table[] = {
	{uniform_Float, GL_FLOAT},
	{uniform_Float2, GL_FLOAT_VEC2_ARB},
	{uniform_Float3, GL_FLOAT_VEC3_ARB},
	{uniform_Float4, GL_FLOAT_VEC4_ARB},
	{uniform_Int, GL_INT},
	{uniform_Int2, GL_INT_VEC2_ARB},
	{uniform_Int3, GL_INT_VEC3_ARB},
	{uniform_Int4, GL_INT_VEC4_ARB},
	{uniform_Bool, GL_BOOL_ARB},
	{uniform_Bool2, GL_BOOL_VEC2_ARB},
	{uniform_Bool3, GL_BOOL_VEC3_ARB},
	{uniform_Bool4, GL_BOOL_VEC4_ARB},
	{uniform_Matrix2, GL_FLOAT_MAT2_ARB},
	{uniform_Matrix3, GL_FLOAT_MAT3_ARB},
	{uniform_Matrix4, GL_FLOAT_MAT4_ARB},
	{uniform_Sampler1D, GL_SAMPLER_1D_ARB},
	{uniform_Sampler2D, GL_SAMPLER_2D_ARB},
	{uniform_Sampler3D, GL_SAMPLER_3D_ARB},
	{uniform_SamplerCube, GL_SAMPLER_CUBE_ARB},
	{uniform_Sampler1D_Shadow, GL_SAMPLER_1D_SHADOW_ARB},
	{uniform_Sampler2D_Shadow, GL_SAMPLER_2D_SHADOW_ARB},
	{uniform_Sampler2D_Rect, GL_SAMPLER_2D_RECT_ARB},
	{uniform_Sampler2D_Rect_Shadow, GL_SAMPLER_2D_RECT_SHADOW_ARB}, // "regular"

	{uniform_Matrix2x3, GL_FLOAT_MAT2x3},
	{uniform_Matrix2x4, GL_FLOAT_MAT2x4},
	{uniform_Matrix3x2, GL_FLOAT_MAT3x2},
	{uniform_Matrix3x4, GL_FLOAT_MAT3x4},
	{uniform_Matrix4x2, GL_FLOAT_MAT4x2},
	{uniform_Matrix4x3, GL_FLOAT_MAT4x3}, // OpenGL 2.1

	{uniform_Unsigned_Int, GL_UNSIGNED_INT},
	{uniform_Unsigned_Int2, GL_UNSIGNED_INT_VEC2_EXT},
	{uniform_Unsigned_Int3, GL_UNSIGNED_INT_VEC3_EXT},
	{uniform_Unsigned_Int4, GL_UNSIGNED_INT_VEC4_EXT},
	{uniform_Sampler1D_Array, GL_SAMPLER_1D_ARRAY_EXT},
	{uniform_Sampler2D_Array, GL_SAMPLER_2D_ARRAY_EXT},
	{uniform_SamplerBuffer, GL_SAMPLER_BUFFER_EXT},
	{uniform_Sampler1D_Array_Shadow, GL_SAMPLER_1D_ARRAY_SHADOW_EXT},
	{uniform_Sampler2D_Array_Shadow, GL_SAMPLER_2D_ARRAY_SHADOW_EXT},
	{uniform_SamplerCube_Shadow, GL_SAMPLER_CUBE_SHADOW_EXT},
	{uniform_Sampler_Int_1D, GL_INT_SAMPLER_1D_EXT},
	{uniform_Sampler_Int_2D, GL_INT_SAMPLER_2D_EXT},
	{uniform_Sampler_Int_3D, GL_INT_SAMPLER_3D_EXT},
	{uniform_Sampler_Int_Cube, GL_INT_SAMPLER_CUBE_EXT},
	{uniform_Sampler_Int_2D_Rect, GL_INT_SAMPLER_2D_RECT_EXT},
	{uniform_Sampler_Int_1D_Array, GL_INT_SAMPLER_1D_ARRAY_EXT},
	{uniform_Sampler_Int_2D_Array, GL_INT_SAMPLER_2D_ARRAY_EXT},
	{uniform_Sampler_Int_Buffer, GL_INT_SAMPLER_BUFFER_EXT},
	{uniform_Sampler_Unsigned_Int_1D, GL_UNSIGNED_INT_SAMPLER_1D_EXT},
	{uniform_Sampler_Unsigned_Int_2D, GL_UNSIGNED_INT_SAMPLER_2D_EXT},
	{uniform_Sampler_Unsigned_Int_3D, GL_UNSIGNED_INT_SAMPLER_3D_EXT},
	{uniform_Sampler_Unsigned_Int_Cube, GL_UNSIGNED_INT_SAMPLER_CUBE_EXT},
	{uniform_Sampler_Unsigned_Int_2D_Rect, GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT},
	{uniform_Sampler_Unsigned_Int_1D_Array, GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT},
	{uniform_Sampler_Unsigned_Int_2D_Array, GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT},
	{uniform_Sampler_Unsigned_Int_Buffer, GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT} // EXT_gpu_shader4
};

/*
 *	static int CShaderParamTypeConverter::n_EnumValue(GLenum n_gl_value)
 *		- translate OpenGL parameter type value to enum value
 *		  (reason to do that is faster parameter type tests as enum values
 *		  are successive integers)
 *		- in case unknown parameter type is passed, returns uniform_Unknown
 */
int CShaderParamTypeConverter::n_EnumValue(GLenum n_gl_value)
{
	for(const TTableElem *p_cur_elem = m_p_type_table,
	   *p_end = m_p_type_table + (sizeof(m_p_type_table) / sizeof(m_p_type_table[0]));
	   p_cur_elem < p_end; ++ p_cur_elem) {
		if(p_cur_elem->n_gl_value == n_gl_value)
			return p_cur_elem->n_enum_value;
	}
	return uniform_Unknown;
}

/*
 *	static GLenum CShaderParamTypeConverter::n_OpenGLValue(int n_enum_value)
 *		- translate enum value n_enum_value to OpenGL parameter
 *		- returns 0 (equal to GL_NONE) on uniform_Unknown / bad enum value
 */
GLenum CShaderParamTypeConverter::n_OpenGLValue(int n_enum_value)
{
	for(const TTableElem *p_cur_elem = m_p_type_table,
	   *p_end = m_p_type_table + (sizeof(m_p_type_table) / sizeof(m_p_type_table[0]));
	   p_cur_elem < p_end; ++ p_cur_elem) {
		if(p_cur_elem->n_enum_value == n_enum_value)
			return p_cur_elem->n_gl_value;
	}
	return 0;
}

/*
 *								=== ~CShaderParamTypeConverter ===
 */

/*
 *								=== CGL_ARB_program ===
 */

/*
 *	CGL_ARB_program::CGL_ARB_program(const char *p_s_vertex_shader, const char *p_s_fragment_shader)
 *		- default constructor
 *		- p_s_vertex_shader and p_s_fragment_shader are strings, containing shader source
 *		  codes, one of them can be 0
 *		- note pointers are copied only, they must not be freed until this object is deleted
 */
CGL_ARB_program::CGL_ARB_program(const char *p_s_vertex_shader, const char *p_s_fragment_shader)
	:CGLProgram(p_s_vertex_shader, p_s_fragment_shader),
	m_b_compiled(false),
	m_b_linked(false),
	m_n_vs_object(0),
	m_n_fs_object(0)
{
	__FuncGuard("CGL_ARB_program::CGL_ARB_program");
}

/*
 *	CGL_ARB_program::~CGL_ARB_program()
 *		- default destructor
 */
CGL_ARB_program::~CGL_ARB_program()
{
	__FuncGuard("CGL_ARB_program::~CGL_ARB_program");

	Delete();
}

/*
 *	static bool CGL_ARB_program::b_Supported(bool b_vertex_pipeline = true,
 *		bool b_fragment_pipeline = true)
 *		- b_vertex_pipeline and b_fragment_pipeline selects required functionality
 *		- returns true in case all necessary OpenGL extensions are supported,
 *		  otherwise returns false
 */
bool CGL_ARB_program::b_Supported(bool b_vertex_pipeline, bool b_fragment_pipeline)
{
	__FuncGuard("CGL_ARB_program::b_Supported");

	return (!b_vertex_pipeline ||
		(CGLExtensionHandler::b_SupportedExtension("GL_ARB_vertex_program") &&
		!CGLExtensionHandler::n_GetVertexProgramARBFuncPointers())) &&
		(!b_fragment_pipeline ||
		(CGLExtensionHandler::b_SupportedExtension("GL_ARB_fragment_program") &&
		!CGLExtensionHandler::n_GetFragmentProgramARBFuncPointers()));
}

/*
 *	bool CGL_ARB_program::Compile(CGLState *p_state, char *&r_p_s_info_log)
 *		- compile program and return info-log, which has to be freed
 *		- if you re-compile program, it call Delete() first
 *		- returns true on success, (still can return log with warnings) false on failure
 */
bool CGL_ARB_program::Compile(CGLState *p_state, char *&r_p_s_info_log)
{
	__FuncGuard("CGL_ARB_program::Compile");

	Delete();
	r_p_s_info_log = 0;

	GLsizei n_length;

	if(m_p_s_vertex_shader) {
		glGenProgramsARB(1, &m_n_vs_object);
		glBindProgramARB(GL_VERTEX_PROGRAM_ARB, m_n_vs_object);
		// create shader

		n_length = GLsizei(strlen(m_p_s_vertex_shader));
		glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
			n_length, m_p_s_vertex_shader);
		// compile vs ...

		int n_error;
		glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &n_error);
		bool b_compiled = n_error == -1;

		const char *p_s_error = (char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB);
		// query status ...
		if(p_s_error && (n_length = GLsizei(strlen(p_s_error)) + 1) > 1) {
			if(!(r_p_s_info_log = new(std::nothrow) char[n_length +
			   strlen(CShaderStringTable::p_s_ARB_VertexProgram_String())]))
				return false;
#if defined(_MSC_VER) && !defined(__MWERKS__) && _MSC_VER >= 1400
			size_t n_bufsize = (n_length +
				strlen(CShaderStringTable::p_s_ARB_VertexProgram_String())) * sizeof(char);
			strcpy_s(r_p_s_info_log, n_bufsize, CShaderStringTable::p_s_ARB_VertexProgram_String());
			strcat_s(r_p_s_info_log, n_bufsize, p_s_error);
#else // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
			strcpy(r_p_s_info_log, CShaderStringTable::p_s_ARB_VertexProgram_String());
			strcat(r_p_s_info_log, p_s_error);
#endif // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
		}
		// get info-log

		if(!b_compiled)
			return false;
	}
	// compile vertex shader

	if(m_p_s_fragment_shader) {
		glGenProgramsARB(1, &m_n_fs_object);
		glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_n_fs_object);
		// create shader

		n_length = GLsizei(strlen(m_p_s_fragment_shader));
		glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
			n_length, m_p_s_fragment_shader);
		// compile fs ...

		int n_error;
		glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &n_error);
		bool b_compiled = n_error == -1;

		const char *p_s_error = (char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB);
		// query status ...
		if(p_s_error && (n_length = GLsizei(strlen(p_s_error)) + 1) > 1) {
			if(m_n_vs_object && r_p_s_info_log) {
				char *p_s_temp_info_log;
				if(!(p_s_temp_info_log = new(std::nothrow) char[n_length + strlen(r_p_s_info_log) +
				   2 + strlen(CShaderStringTable::p_s_ARB_FragmentProgram_String())]))
					return false;
#if defined(_MSC_VER) && !defined(__MWERKS__) && _MSC_VER >= 1400
				size_t n_bufsize = (n_length + strlen(r_p_s_info_log) +
				   2 + strlen(CShaderStringTable::p_s_ARB_FragmentProgram_String())) * sizeof(char);
				strcpy_s(p_s_temp_info_log, n_bufsize, r_p_s_info_log);
				strcat_s(p_s_temp_info_log, n_bufsize, "\n\n");
				strcat_s(p_s_temp_info_log, n_bufsize, CShaderStringTable::p_s_ARB_FragmentProgram_String());
				strcat_s(p_s_temp_info_log, n_bufsize, p_s_error);
#else // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
				strcpy(p_s_temp_info_log, r_p_s_info_log);
				strcat(p_s_temp_info_log, "\n\n");
				strcat(p_s_temp_info_log, CShaderStringTable::p_s_ARB_FragmentProgram_String());
				strcat(p_s_temp_info_log, p_s_error);
#endif // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
				delete[] r_p_s_info_log;
				r_p_s_info_log = p_s_temp_info_log;
			} else {
				if(!(r_p_s_info_log = new(std::nothrow) char[n_length +
				   strlen(CShaderStringTable::p_s_ARB_FragmentProgram_String())]))
					return false;
#if defined(_MSC_VER) && !defined(__MWERKS__) && _MSC_VER >= 1400
				size_t n_bufsize = (n_length +
				   strlen(CShaderStringTable::p_s_ARB_FragmentProgram_String())) * sizeof(char);
				strcpy_s(r_p_s_info_log, n_bufsize, CShaderStringTable::p_s_ARB_FragmentProgram_String());
				strcat_s(r_p_s_info_log, n_bufsize, p_s_error);
#else // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
				strcpy(r_p_s_info_log, CShaderStringTable::p_s_ARB_FragmentProgram_String());
				strcat(r_p_s_info_log, p_s_error);
#endif // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
			}
		}
		// get info-log

		if(!b_compiled)
			return false;
	}
	// compile fragment shader

	if(glGetError() == GL_NO_ERROR)
		m_b_compiled = true;

	return m_b_compiled;
}

/*
 *	bool CGL_ARB_program::SetParam4fv(CGLState *p_state, int n_param_type,
 *		int n_location, const float *p_value, int n_count = 1) const
 *		- set float vec4 shader parameter
 *		- p_value is pointer to 4 floats, data will be read from
 *		- n_location is index of destination register
 *		- n_count is number of parameters to set
 *		- n_param_type must be one of shader_param_Parameter_Env_VP,
 *		  shader_param_Parameter_Env_FP, shader_param_Parameter_Local_VP
 *		  or shader_param_Parameter_Local_FP
 */
bool CGL_ARB_program::SetParam4fv(CGLState *p_state, int n_param_type,
	int n_location, const float *p_value, int n_count) const
{
	__FuncGuard("CGL_ARB_program::SetParam4fv");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	for(int i = 0, n = n_count; i < n; ++ i, ++ n_location, p_value += 4) {
		if(!_SetParam4fv(n_param_type, n_location, p_value))
			return false;
	}
	return true;
}

/*
 *	void CGL_ARB_program::Bind(CGLState *p_state) const
 *		- binds shader
 */
void CGL_ARB_program::Bind(CGLState *p_state) const
{
	__FuncGuard("CGL_ARB_program::Bind");

	_Bind(p_state);
}

/*
 *	void CGL_ARB_program::Release(CGLState *p_state) const
 *		- un-binds shader
 *		- used for safe switching between shaders with different api-s
 */
void CGL_ARB_program::Release(CGLState *p_state) const
{
	__FuncGuard("CGL_ARB_program::Release");

	_Release(p_state);
}

/*
 *	void CGL_ARB_program::Delete()
 *		- free open-gl resources
 *		- if program is about to be used again, it must be re-compiled,
 *		  re-bound vertex attribs, re-linked and re-queried for unifroms
 */
void CGL_ARB_program::Delete()
{
	__FuncGuard("CGL_ARB_program::Delete");

	//CGLProgram::Release(p_state);

	m_b_compiled = false;
	m_b_linked = false;

	if(m_n_vs_object) {
		glDeleteProgramsARB(1, &m_n_vs_object);
		CGLState::NotifyDeleteVertexProgram(m_n_vs_object);
		m_n_vs_object = 0;
	}
	if(m_n_fs_object) {
		glDeleteProgramsARB(1, &m_n_fs_object);
		CGLState::NotifyDeleteFragmentProgram(m_n_fs_object);
		m_n_fs_object = 0;
	}
}

/*
 *	int CGL_ARB_program::n_Api() const
 *		- return which api is used
 */
int CGL_ARB_program::n_Api() const
{
	__FuncGuard("CGL_ARB_program::n_Api");

	return shader_api_ARB_program;
}

/*
 *								=== ~CGL_ARB_program ===
 */

/*
 *								=== CGL_ARB_shader ===
 */

/*
 *	CGL_ARB_shader::CGL_ARB_shader(const char *p_s_vertex_shader, const char *p_s_fragment_shader)
 *		- default constructor
 *		- p_s_vertex_shader and p_s_fragment_shader are strings, containing shader source
 *		  codes, one of them can be 0
 *		- note pointers are copied only, they must not be freed until this object is deleted
 */
CGL_ARB_shader::CGL_ARB_shader(const char *p_s_vertex_shader, const char *p_s_fragment_shader)
	:CGLShader(p_s_vertex_shader, p_s_fragment_shader),
	m_b_compiled(false),
	m_n_program_object(0),
	m_n_vs_object(0),
	m_n_fs_object(0)
{
	__FuncGuard("CGL_ARB_shader::CGL_ARB_shader");
}

/*
 *	CGL_ARB_shader::~CGL_ARB_shader()
 *		- default destructor
 */
CGL_ARB_shader::~CGL_ARB_shader()
{
	__FuncGuard("CGL_ARB_shader::~CGL_ARB_shader");

	Delete();
}

/*
 *	static bool CGL_ARB_shader::b_Supported(bool b_vertex_pipeline = true,
 *		bool b_fragment_pipeline = true)
 *		- b_vertex_pipeline and b_fragment_pipeline selects required functionality
 *		- returns true in case all necessary OpenGL extensions are supported,
 *		  otherwise returns false
 */
bool CGL_ARB_shader::b_Supported(bool b_vertex_pipeline, bool b_fragment_pipeline)
{
	return CGLExtensionHandler::b_SupportedExtension("GL_ARB_shading_language_100") &&
		(!b_vertex_pipeline ||
		(CGLExtensionHandler::b_SupportedExtension("GL_ARB_vertex_shader") &&
		!CGLExtensionHandler::n_GetVertexShaderARBFuncPointers())) &&
		(!b_fragment_pipeline ||
		(CGLExtensionHandler::b_SupportedExtension("GL_ARB_fragment_shader") &&
		!CGLExtensionHandler::n_GetFragmentShaderARBFuncPointers())) &&
		CGLExtensionHandler::b_SupportedExtension("GL_ARB_shader_objects") &&
		!CGLExtensionHandler::n_GetShaderObjectsARBFuncPointers();
}

/*
 *	virutal bool CGL_ARB_shader::Compile(CGLState *p_state, char *&r_p_s_info_log)
 *		- compile program and return info-log, which has to be freed
 *		- if you re-compile program, it call Delete() first
 *		- returns true on success (can still return warnings), false on failure
 */
bool CGL_ARB_shader::Compile(CGLState *p_state, char *&r_p_s_info_log)
{
	__FuncGuard("CGL_ARB_shader::Compile");

	Delete();
	r_p_s_info_log = 0;

	m_n_program_object = glCreateProgramObjectARB();

	GLsizei n_length;

	m_n_vs_object = (m_p_s_vertex_shader)? glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB) : 0;
	if(m_n_vs_object) {
		n_length = GLsizei(strlen(m_p_s_vertex_shader));
		glShaderSourceARB(m_n_vs_object, 1, &m_p_s_vertex_shader, &n_length);
		glCompileShaderARB(m_n_vs_object);
		// compile vs ...

		int n_tmp;
		glGetObjectParameterivARB(m_n_vs_object, GL_OBJECT_COMPILE_STATUS_ARB, &n_tmp);
		bool b_compiled = n_tmp == GL_TRUE;
		glGetObjectParameterivARB(m_n_vs_object, GL_OBJECT_INFO_LOG_LENGTH_ARB, &n_length);
		// query status ...

		if(n_length > 1) {
			if(!(r_p_s_info_log = new(std::nothrow) char[n_length +
			   strlen(CShaderStringTable::p_s_ARB_VertexShader_String())]))
				return false;
			glGetInfoLogARB(m_n_vs_object, n_length, &n_length, r_p_s_info_log +
				strlen(CShaderStringTable::p_s_ARB_VertexShader_String()));
#if defined(_MSC_VER) && !defined(__MWERKS__) && _MSC_VER >= 1400
			strncpy_s(r_p_s_info_log, (n_length +
				strlen(CShaderStringTable::p_s_ARB_VertexShader_String())) * sizeof(char),
				CShaderStringTable::p_s_ARB_VertexShader_String(),
				strlen(CShaderStringTable::p_s_ARB_VertexShader_String()));
#else // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
			strncpy(r_p_s_info_log, CShaderStringTable::p_s_ARB_VertexShader_String(),
				strlen(CShaderStringTable::p_s_ARB_VertexShader_String()));
#endif // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
		}
		// get info-log

		if(!b_compiled)
			return false;
	}
	// compile vertex shader

	m_n_fs_object = (m_p_s_fragment_shader)? glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB) : 0;
	if(m_n_fs_object) {
		n_length = GLsizei(strlen(m_p_s_fragment_shader));
		glShaderSourceARB(m_n_fs_object, 1, &m_p_s_fragment_shader, &n_length);
		glCompileShaderARB(m_n_fs_object);
		// compile vs ...

		int n_tmp;
		glGetObjectParameterivARB(m_n_fs_object, GL_OBJECT_COMPILE_STATUS_ARB, &n_tmp);
		bool b_compiled = n_tmp == GL_TRUE;
		glGetObjectParameterivARB(m_n_fs_object, GL_OBJECT_INFO_LOG_LENGTH_ARB, &n_length);
		// query status ...

		if(n_length > 1) {
			if(m_n_vs_object && r_p_s_info_log) {
				char *p_s_temp_info_log;
				if(!(p_s_temp_info_log = new(std::nothrow) char[n_length + strlen(r_p_s_info_log) + 2 +
				   strlen(CShaderStringTable::p_s_ARB_FragmentShader_String())]))
					return false;
#if defined(_MSC_VER) && !defined(__MWERKS__) && _MSC_VER >= 1400
				size_t n_bufsize = (n_length + strlen(r_p_s_info_log) + 2 +
				   strlen(CShaderStringTable::p_s_ARB_FragmentShader_String())) * sizeof(char);
				strcpy_s(p_s_temp_info_log, n_bufsize, r_p_s_info_log);
				strcat_s(p_s_temp_info_log, n_bufsize, "\n\n");
				strcat_s(p_s_temp_info_log, n_bufsize, CShaderStringTable::p_s_ARB_FragmentShader_String());
#else // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
				strcpy(p_s_temp_info_log, r_p_s_info_log);
				strcat(p_s_temp_info_log, "\n\n");
				strcat(p_s_temp_info_log, CShaderStringTable::p_s_ARB_FragmentShader_String());
#endif // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
				glGetInfoLogARB(m_n_fs_object, n_length, &n_length,
					p_s_temp_info_log + strlen(r_p_s_info_log) + 2 +
					strlen(CShaderStringTable::p_s_ARB_FragmentShader_String()));
				delete[] r_p_s_info_log;
				r_p_s_info_log = p_s_temp_info_log;
			} else {
				if(!(r_p_s_info_log = new(std::nothrow) char[n_length +
				   strlen(CShaderStringTable::p_s_ARB_FragmentShader_String())]))
					return false;
				glGetInfoLogARB(m_n_fs_object, n_length, &n_length, r_p_s_info_log +
					strlen(CShaderStringTable::p_s_ARB_FragmentShader_String()));
#if defined(_MSC_VER) && !defined(__MWERKS__) && _MSC_VER >= 1400
				strncpy_s(r_p_s_info_log, (n_length +
					strlen(CShaderStringTable::p_s_ARB_FragmentShader_String())) * sizeof(char),
					CShaderStringTable::p_s_ARB_FragmentShader_String(),
					strlen(CShaderStringTable::p_s_ARB_FragmentShader_String()));
#else // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
				strncpy(r_p_s_info_log, CShaderStringTable::p_s_ARB_FragmentShader_String(),
					strlen(CShaderStringTable::p_s_ARB_FragmentShader_String()));
#endif // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
			}
		}
		// get info-log

		if(!b_compiled)
			return false;
	}
	// compile fragment shader

	if(m_n_vs_object)
		glAttachObjectARB(m_n_program_object, m_n_vs_object);
	if(m_n_fs_object)
		glAttachObjectARB(m_n_program_object, m_n_fs_object);
	// attach shaders to a program

	if(glGetError() == GL_NO_ERROR)
		m_b_compiled = true;

	//m_p_bound_program = this; // f_ixme - program isn't bound

	return m_b_compiled;
}

/*
 *	virutal bool CGL_ARB_shader::BindAttribLocation(int n_location, const char *p_s_attrib_name)
 *		- bind vertex attrib location
 *		- can be called only if program was successfully compiled and not linked
 *		- returns true on success, false on failure
 */
bool CGL_ARB_shader::BindAttribLocation(int n_location, const char *p_s_attrib_name)
{
	__FuncGuard("CGL_ARB_shader::BindAttribLocation");

	if(!m_b_compiled || m_b_linked)
		return false;
	// must be compiled, but not linked!

	glBindAttribLocationARB(m_n_program_object, n_location, p_s_attrib_name);

	return glGetError() == GL_NO_ERROR;
}

/*
 *	virutal bool CGL_ARB_shader::Link(char *&r_p_s_info_log)
 *		- link program, return info-log which has to be freed
 *		- can be called only if program was successfully compiled and not linked
 *		- returns true on success (can still return warnings), false on failure
 */
bool CGL_ARB_shader::Link(char *&r_p_s_info_log)
{
	__FuncGuard("CGL_ARB_shader::Link");

	r_p_s_info_log = 0;
	if(!m_b_compiled || m_b_linked)
		return false;

	glLinkProgramARB(m_n_program_object);
	int n_tmp;
	glGetObjectParameterivARB(m_n_program_object, GL_OBJECT_LINK_STATUS_ARB, &n_tmp);
	m_b_linked = n_tmp == GL_TRUE;
	// link

	int n_length;
	glGetObjectParameterivARB(m_n_program_object, GL_OBJECT_INFO_LOG_LENGTH_ARB, &n_length);
	if(n_length > 1) {
		const char *p_s_header = CShaderStringTable::p_s_ARB_Shader_String();
		size_t n_header_length = strlen(p_s_header);
		if(!(r_p_s_info_log = new(std::nothrow) char[n_length + n_header_length]))
			return false;
#if defined(_MSC_VER) && !defined(__MWERKS__) && _MSC_VER >= 1400
		strcpy_s(r_p_s_info_log, (n_length + n_header_length) * sizeof(char), p_s_header);
#else // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
		strcpy(r_p_s_info_log, p_s_header);
#endif // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
		glGetInfoLogARB(m_n_program_object, n_length, &n_length, r_p_s_info_log + n_header_length);
	}
	// get info-log

	return m_b_linked && glGetError() == GL_NO_ERROR;
	// f_ixme - does it ever return true if only one shader is presented ?? does.
}

/*
 *	virtual int CGL_ARB_shader::n_Uniform_Num() const
 *		- return number of uniform variables or -1 on failure
 *		- note this may also include OpenGL builtin uniforms such as
 *		  gl_ModelViewProjectionMatrixTranspose
 */
int CGL_ARB_shader::n_Uniform_Num() const
{
	if(!m_b_compiled || !m_b_linked)
		return -1;

	int n_uniform_num;
	glGetObjectParameterivARB(m_n_program_object, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &n_uniform_num);

	return (glGetError() == GL_NO_ERROR)? n_uniform_num : -1;
}

/*
 *	virtual char *CGL_ARB_shader::p_s_Uniform_Name(int n_index,
 *		int &r_n_content_type, int &r_n_size) const
 *		- return name of uniform variable with index n_index or 0 on failure
 *		- r_n_content_type is set to variable content type (one of uniform_Float,
 *		  uniform_Float2, ...)
 *		- r_n_size is set to size of the uniform variable (1 for scalars, 1 or more
 *		  than 1 for arrays)
 */
char *CGL_ARB_shader::p_s_Uniform_Name(int n_index, int &r_n_content_type, int &r_n_size) const
{
	if(!m_b_compiled || !m_b_linked)
		return 0;

	int n_max_name_length;
	glGetObjectParameterivARB(m_n_program_object,
		GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB, &n_max_name_length);

	char *p_s_temp_name;
	if(!(p_s_temp_name = new(std::nothrow) char[n_max_name_length + 1]))
		return 0;

	int n_length;
	int n_size;
	GLenum n_type;
	glGetActiveUniformARB(m_n_program_object, n_index, n_max_name_length, &n_length,
		&n_size, &n_type, p_s_temp_name);

	r_n_size = n_size;

	r_n_content_type = CShaderParamTypeConverter::n_EnumValue(n_type);
	// translate the value

	if(glGetError() != GL_NO_ERROR) {
		delete[] p_s_temp_name;
		return 0;
	}

	if(strlen(p_s_temp_name) + 1 == n_max_name_length)
		return p_s_temp_name;
	else {
		char *p_s_name;
		if(!(p_s_name = new(std::nothrow) char[strlen(p_s_temp_name) + 1]))
			return p_s_temp_name;
#if defined(_MSC_VER) && !defined(__MWERKS__) && _MSC_VER >= 1400
		strcpy_s(p_s_name, (strlen(p_s_temp_name) + 1) * sizeof(char), p_s_temp_name);
#else // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
		strcpy(p_s_name, p_s_temp_name);
#endif // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
		delete[] p_s_temp_name;
		return p_s_name;
	}
}

/*
 *	virutal int CGL_ARB_shader::n_GetUniformLocation(const char *p_s_uniform_name) const
 *		- returns uniform location by uniform name
 *		- note this fails on OpenGL builtin uniforms such as
 *		  gl_ModelViewProjectionMatrixTranspose
 *		- returns -1 on failure
 */
int CGL_ARB_shader::n_GetUniformLocation(const char *p_s_uniform_name) const
{
	__FuncGuard("CGL_ARB_shader::n_GetUniformLocation");

	if(!m_b_compiled || !m_b_linked)
		return -1; // f_ixme - 0 or -1 - answer is -1

	return glGetUniformLocationARB(m_n_program_object, p_s_uniform_name);
}

/*
 *	bool CGL_ARB_shader::SetParam1fv(CGLState *p_state, int n_param_type,
 *		int n_location, const float *p_value, int n_count = 1)
 *		- set float uniform to value of first element in p_value array
 *		- n_param_type is safe-check only, it should be shader_param_Uniform
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_ARB_shader::SetParam1fv(CGLState *p_state, int n_param_type,
	int n_location, const float *p_value, int n_count)
{
	__FuncGuard("CGL_ARB_shader::SetParam1fv");

	if(!m_b_compiled || !m_b_linked || n_param_type != shader_param_Uniform)
		return false;
	//_ASSERTE(n_param_type == shader_param_Uniform);
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParam1fv(n_location, n_count, p_value);
	return true;
}

/*
 *	bool CGL_ARB_shader::SetParam2fv(CGLState *p_state, int n_param_type,
 *		int n_location, const float *p_value, int n_count = 1)
 *		- set float vec2 uniform to value of first two elements in p_value array
 *		- n_param_type is safe-check only, it should be shader_param_Uniform
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_ARB_shader::SetParam2fv(CGLState *p_state, int n_param_type,
	int n_location, const float *p_value, int n_count)
{
	__FuncGuard("CGL_ARB_shader::SetParam2fv");

	if(!m_b_compiled || !m_b_linked || n_param_type != shader_param_Uniform)
		return false;
	//_ASSERTE(n_param_type == shader_param_Uniform);
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParam2fv(n_location, n_count, p_value);
	return true;
}

/*
 *	bool CGL_ARB_shader::SetParam3fv(CGLState *p_state, int n_param_type,
 *		int n_location, const float *p_value, int n_count = 1)
 *		- set float vec3 uniform to value of first three elements in p_value array
 *		- n_param_type is safe-check only, it should be shader_param_Uniform
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_ARB_shader::SetParam3fv(CGLState *p_state, int n_param_type,
	int n_location, const float *p_value, int n_count)
{
	__FuncGuard("CGL_ARB_shader::SetParam3fv");

	if(!m_b_compiled || !m_b_linked || n_param_type != shader_param_Uniform)
		return false;
	//_ASSERTE(n_param_type == shader_param_Uniform);
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParam3fv(n_location, n_count, p_value);
	return true;
}

/*
 *	bool CGL_ARB_shader::SetParam4fv(CGLState *p_state, int n_param_type,
 *		int n_location, const float *p_value, int n_count = 1) const
 *		- set float vec4 uniform to value of first four elements in p_value array
 *		- n_param_type is safe-check only, it should be shader_param_Uniform
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_ARB_shader::SetParam4fv(CGLState *p_state, int n_param_type,
	int n_location, const float *p_value, int n_count) const
{
	__FuncGuard("CGL_ARB_shader::SetParam4fv");

	if(!m_b_compiled || !m_b_linked || n_param_type != shader_param_Uniform)
		return false;
	//_ASSERTE(n_param_type == shader_param_Uniform);
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParam4fv(n_location, n_count, p_value);
	return true;
}

/*
 *	bool CGL_ARB_shader::SetParam1i(CGLState *p_state, int n_location, int n_value)
 *		- set integer uniform (sampler) to n_value
 *		- n_location is destination register index
 *		- returns true on success, false on failure
 */
bool CGL_ARB_shader::SetParam1i(CGLState *p_state, int n_location, int n_value)
{
	__FuncGuard("CGL_ARB_shader::SetParam1i");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);

	_SetParam1i(n_location, n_value);
	return true;
}

/*
 *	virtual bool CGL_ARB_shader::SetParam1iv(CGLState *p_state,
 *		int n_location, const int *p_value, int n_count = 1)
 *		- set integer vec2 uniform to n_value of first two elements in p_value
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_ARB_shader::SetParam1iv(CGLState *p_state,
	int n_location, const int *p_value, int n_count)
{
	__FuncGuard("CGL_ARB_shader::SetParam1iv");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParam1iv(n_location, n_count, p_value);
	return true;
}

/*
 *	virtual bool CGL_ARB_shader::SetParam2iv(CGLState *p_state,
 *		int n_location, const int *p_value, int n_count = 1)
 *		- set integer vec2 uniform to n_value of first two elements in p_value
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_ARB_shader::SetParam2iv(CGLState *p_state,
	int n_location, const int *p_value, int n_count)
{
	__FuncGuard("CGL_ARB_shader::SetParam2iv");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParam2iv(n_location, n_count, p_value);
	return true;
}

/*
 *	virtual bool CGL_ARB_shader::SetParam3iv(CGLState *p_state,
 *		int n_location, const int *p_value, int n_count = 1)
 *		- set integer vec3 uniform to n_value of first three elements in p_value
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_ARB_shader::SetParam3iv(CGLState *p_state,
	int n_location, const int *p_value, int n_count)
{
	__FuncGuard("CGL_ARB_shader::SetParam3iv");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParam3iv(n_location, n_count, p_value);
	return true;
}

/*
 *	virtual bool CGL_ARB_shader::SetParam4iv(CGLState *p_state,
 *		int n_location, const int *p_value, int n_count = 1)
 *		- set integer vec4 uniform to n_value of first four elements in p_value
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_ARB_shader::SetParam4iv(CGLState *p_state,
	int n_location, const int *p_value, int n_count)
{
	__FuncGuard("CGL_ARB_shader::SetParam4iv");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParam4iv(n_location, n_count, p_value);
	return true;
}

/*
 *	virtual bool CGL_ARB_shader::SetParamMatrix2fv(CGLState *p_state, int n_location,
 *		bool b_transpose, const float *p_value, int n_count = 1)
 *		- set 2x2 float matrix uniform to 2x2 matrix form p_value
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_ARB_shader::SetParamMatrix2fv(CGLState *p_state, int n_location,
	bool b_transpose, const float *p_value, int n_count)
{
	__FuncGuard("CGL_ARB_shader::SetParamMatrix2fv");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParamMatrix2fv(n_location, n_count, b_transpose, p_value);
	return true;
}

/*
 *	virtual bool CGL_ARB_shader::SetParamMatrix3fv(CGLState *p_state, int n_location,
 *		bool b_transpose, const float *p_value, int n_count = 1)
 *		- set 3x3 float matrix uniform to 3x3 matrix form p_value
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_ARB_shader::SetParamMatrix3fv(CGLState *p_state, int n_location,
	bool b_transpose, const float *p_value, int n_count)
{
	__FuncGuard("CGL_ARB_shader::SetParamMatrix3fv");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParamMatrix3fv(n_location, n_count, b_transpose, p_value);
	return true;
}

/*
 *	virtual bool CGL_ARB_shader::SetParamMatrix4fv(CGLState *p_state, int n_location,
 *		bool b_transpose, const float *p_value, int n_count = 1)
 *		- set 4x4 float matrix uniform to 4x4 matrix form p_value
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_ARB_shader::SetParamMatrix4fv(CGLState *p_state, int n_location,
	bool b_transpose, const float *p_value, int n_count)
{
	__FuncGuard("CGL_ARB_shader::SetParamMatrix4fv");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParamMatrix4fv(n_location, n_count, b_transpose, p_value);
	return true;
}

/*
 *	virutal void CGL_ARB_shader::Bind(CGLState *p_state) const
 *		- binds shader
 */
void CGL_ARB_shader::Bind(CGLState *p_state) const
{
	__FuncGuard("CGL_ARB_shader::Bind");

	_Bind(p_state);
}

/*
 *	virutal void CGL_ARB_shader::Release(CGLState *p_state) const
 *		- un-binds shader
 *		- used for safe switching between shaders with different api-s
 */
void CGL_ARB_shader::Release(CGLState *p_state) const
{
	__FuncGuard("CGL_ARB_shader::Release");

	_Release(p_state);
}

/*
 *	virutal void CGL_ARB_shader::Delete()
 *		- free open-gl resources
 *		- if program is about to be used again, it must be re-compiled,
 *		  re-bound vertex attribs, re-linked and re-queried for unifroms
 */
void CGL_ARB_shader::Delete()
{
	__FuncGuard("CGL_ARB_shader::Delete");

	//CGLProgram::Release(p_state);

	m_b_compiled = false;
	m_b_linked = false;

	if(m_n_program_object) {
		glDeleteObjectARB(m_n_program_object);
		CGLState::NotifyDeleteProgramObject(m_n_program_object);
		m_n_program_object = 0;
	}
	if(m_n_vs_object) {
		glDeleteObjectARB(m_n_vs_object);
		m_n_vs_object = 0;
	}
	if(m_n_fs_object) {
		glDeleteObjectARB(m_n_fs_object);
		m_n_fs_object = 0;
	}
}

/*
 *	virutal int CGL_ARB_shader::n_Api() const
 *		- return which api is used
 */
int CGL_ARB_shader::n_Api() const
{
	__FuncGuard("CGL_ARB_shader::n_Api");

	return shader_api_ARB_shader;
}

/*
 *								 === ~CGL_ARB_shader ===
 */

/*
 *								 === CGL_Core_shader ===
 */

/*
 *	CGL_Core_shader::CGL_Core_shader(const char *p_s_vertex_shader, const char *p_s_fragment_shader)
 *		- default constructor
 *		- p_s_vertex_shader and p_s_fragment_shader are strings, containing shader source
 *		  codes, one of them can be 0
 *		- note pointers are copied only, they must not be freed until this object is deleted
 */
CGL_Core_shader::CGL_Core_shader(const char *p_s_vertex_shader, const char *p_s_fragment_shader)
	:CGLShader(p_s_vertex_shader, p_s_fragment_shader), m_p_s_geometry_shader(0),
	m_b_compiled(false),
	m_b_linked(false),
	m_n_program_object(0),
	m_n_vs_object(0),
	m_n_gs_object(0),
	m_n_fs_object(0)
{
	__FuncGuard("CGL_Core_shader::CGL_Core_shader");
}

/*
 *	CGL_Core_shader::CGL_Core_shader(const char *p_s_vertex_shader,
 *		const char *p_s_geometry_shader, const char *p_s_fragment_shader)
 *		- default constructor
 *		- p_s_vertex_shader, p_s_geometry_shader and p_s_fragment_shader are strings,
 *		  containing shader source codes, at least one of them must not be 0
 *		- note pointers are copied only, they must not be freed until this object is deleted
 */
CGL_Core_shader::CGL_Core_shader(const char *p_s_vertex_shader,
	const char *p_s_geometry_shader, const char *p_s_fragment_shader)
	:CGLShader(p_s_vertex_shader, p_s_fragment_shader), m_p_s_geometry_shader(p_s_geometry_shader),
	m_b_compiled(false),
	m_b_linked(false),
	m_n_program_object(0),
	m_n_vs_object(0),
	m_n_gs_object(0),
	m_n_fs_object(0)
{
	__FuncGuard("CGL_Core_shader::CGL_Core_shader");
}

/*
 *	CGL_Core_shader::~CGL_Core_shader()
 *		- default destructor
 */
CGL_Core_shader::~CGL_Core_shader()
{
	__FuncGuard("CGL_Core_shader::~CGL_Core_shader");

	Delete();
}

/*
 *	static bool CGL_Core_shader::b_Supported(bool b_vertex_pipeline = true,
 *		bool b_fragment_pipeline = true)
 *		- b_vertex_pipeline and b_fragment_pipeline selects required functionality
 *		- returns true in case all necessary OpenGL extensions are supported,
 *		  otherwise returns false
 */
bool CGL_Core_shader::b_Supported(bool b_vertex_pipeline, bool b_fragment_pipeline)
{
	return CGLExtensionHandler::b_Support_OpenGL(2, 0) &&
		!CGLExtensionHandler::n_GetGL20FuncPointers();
	// doesn't separate vertex / fragment shader support; fallback to GL_ARB_*_shader
	// is always possible anyway
}

/*
 *	static bool CGL_Core_shader::b_Supported(bool b_vertex_pipeline,
 *		bool b_geometry_pipeline, bool b_fragment_pipeline)
 *		- b_vertex_pipeline, b_geometry_pipeline and b_fragment_pipeline selects
 *		  required functionality
 *		- returns true in case all necessary OpenGL extensions are supported,
 *		  otherwise returns false
 */
bool CGL_Core_shader::b_Supported(bool b_vertex_pipeline,
	bool b_geometry_pipeline, bool b_fragment_pipeline)
{
	return CGLExtensionHandler::b_Support_OpenGL(2, 0) &&
		!CGLExtensionHandler::n_GetGL20FuncPointers() &&
		(!b_geometry_pipeline ||
		(CGLExtensionHandler::b_SupportedExtension("GL_EXT_geometry_shader4") &&
		!CGLExtensionHandler::n_GetGeometryShader4EXTFuncPointers()));
	// doesn't separate vertex / fragment shader support; fallback to GL_ARB_*_shader
	// is always possible anyway
}

/*
 *	virutal bool CGL_Core_shader::Compile(CGLState *p_state, char *&r_p_s_info_log)
 *		- compile program and return info-log, which has to be freed
 *		- if you re-compile program, it call Delete() first
 *		- returns true on success (can still return warnings), false on failure
 */
bool CGL_Core_shader::Compile(CGLState *p_state, char *&r_p_s_info_log)
{
	__FuncGuard("CGL_Core_shader::Compile");

	Delete();
	r_p_s_info_log = 0;

	m_n_program_object = glCreateProgram();

	const GLenum p_target[] = {GL_VERTEX_SHADER, GL_GEOMETRY_SHADER_EXT, GL_FRAGMENT_SHADER};
	const char *p_source_list[] = {m_p_s_vertex_shader, m_p_s_geometry_shader, m_p_s_fragment_shader};
	const char *p_header_list[] = {
		CShaderStringTable::p_s_Core_VertexShader_String(),
		CShaderStringTable::p_s_Core_GeometryShader_String(),
		CShaderStringTable::p_s_Core_FragmentShader_String()
	};
	unsigned int *p_shader_object[] = {&m_n_vs_object, &m_n_gs_object, &m_n_fs_object};

	for(int n_unit = 0; n_unit < 3; ++ n_unit) {
		const char *p_s_source = p_source_list[n_unit];
		GLenum n_target = p_target[n_unit];
		if(*p_shader_object[n_unit] = (p_s_source)? glCreateShader(n_target) : 0) {
			unsigned int n_shader_object = *p_shader_object[n_unit];
			int n_src_length = int(strlen(p_s_source));
			glShaderSource(n_shader_object, 1, &p_s_source, &n_src_length);
			glCompileShader(n_shader_object);
			// compile ...

			int n_tmp;
			glGetShaderiv(n_shader_object, GL_COMPILE_STATUS, &n_tmp);
			bool b_compiled = n_tmp == GL_TRUE;
			int n_log_length;
			glGetShaderiv(n_shader_object, GL_INFO_LOG_LENGTH, &n_log_length);
			// query status ...

			if(n_log_length > 1) {
				const char *p_s_header = p_header_list[n_unit];
				size_t n_leave_chars = (r_p_s_info_log)? strlen(r_p_s_info_log) + 2 : 0;

				char *p_s_temp_info_log;
				if(!(p_s_temp_info_log = new(std::nothrow) char[n_leave_chars + strlen(p_s_header) + n_log_length]))
					return false;

#if defined(_MSC_VER) && !defined(__MWERKS__) && _MSC_VER >= 1400
				size_t n_bufsize = (n_leave_chars + strlen(p_s_header) + n_log_length) * sizeof(char);
				if(r_p_s_info_log) {
					strcpy_s(p_s_temp_info_log, n_bufsize, r_p_s_info_log);
					strcat_s(p_s_temp_info_log, n_bufsize, "\n\n");
					strcat_s(p_s_temp_info_log, n_bufsize, p_s_header);
				} else
					strcpy_s(p_s_temp_info_log, n_bufsize, p_s_header);
#else // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
				if(r_p_s_info_log) {
					strcpy(p_s_temp_info_log, r_p_s_info_log);
					strcat(p_s_temp_info_log, "\n\n");
					strcat(p_s_temp_info_log, p_s_header);
				} else
					strcpy(p_s_temp_info_log, p_s_header);
#endif // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400

				int n_tmp;
				glGetShaderInfoLog(n_shader_object, n_log_length, &n_tmp,
					p_s_temp_info_log + n_leave_chars + strlen(p_s_header));
				_ASSERTE(n_tmp <= n_log_length);

				if(r_p_s_info_log)
					delete[] r_p_s_info_log;
				r_p_s_info_log = p_s_temp_info_log;
			}
			// get/concat info-log

			if(!b_compiled)
				return false;
		}
		// compile shader
	}
	// compile shaders for different units in loop (should be less error prone)

	if(m_n_vs_object)
		glAttachShader(m_n_program_object, m_n_vs_object);
	if(m_n_gs_object)
		glAttachShader(m_n_program_object, m_n_gs_object);
	if(m_n_fs_object)
		glAttachShader(m_n_program_object, m_n_fs_object);
	// attach shaders to a program

	if(glGetError() == GL_NO_ERROR)
		m_b_compiled = true;

	return m_b_compiled;
}

/*
 *	virtual bool CGL_Core_shader::BindAttribLocation(int n_location, const char *p_s_attrib_name)
 *		- bind vertex attrib location
 *		- can be called only if program was successfully compiled and not linked
 *		- returns true on success, false on failure
 */
bool CGL_Core_shader::BindAttribLocation(int n_location, const char *p_s_attrib_name)
{
	__FuncGuard("CGL_Core_shader::BindAttribLocation");

	if(!m_b_compiled || m_b_linked)
		return false;
	// must be compiled, but not linked!

	glBindAttribLocation(m_n_program_object, n_location, p_s_attrib_name);

	return glGetError() == GL_NO_ERROR;
}

/*
 *	bool CGL_Core_shader::SetGeometry_InputType(GLenum n_input_type = GL_TRIANGLES)
 *		- sets geometry shader input type (one of GL_POINTS, GL_LINES,
 *		  GL_LINES_ADJACENCY_EXT, GL_TRIANGLES or GL_TRIANGLES_ADJACENCY_EXT,
 *		  default is GL_TRIANGLES)
 *		- note the shader must be compiled, but not linked and there
 *		  must be geometry shader
 *		- returns true on success, false on failure
 */
bool CGL_Core_shader::SetGeometry_InputType(GLenum n_input_type)
{
	if(!m_b_compiled || m_b_linked || !m_n_gs_object)
		return false;
	// must be compiled, but not linked, need geometry shader

	glProgramParameteriEXT(m_n_gs_object, GL_GEOMETRY_INPUT_TYPE_EXT, n_input_type);

	return glGetError() == GL_NO_ERROR;
}

/*
 *	bool CGL_Core_shader::SetGeometry_OutputType(GLenum n_output_type = GL_TRIANGLE_STRIP)
 *		- sets geometry shader output type (one of GL_POINTS,
 *		  GL_LINE_STRIP or GL_TRIANGLE_STRIP, default is GL_TRIANGLE_STRIP)
 *		- note the shader must be compiled, but not linked and there
 *		  must be geometry shader
 *		- returns true on success, false on failure
 */
bool CGL_Core_shader::SetGeometry_OutputType(GLenum n_output_type)
{
	if(!m_b_compiled || m_b_linked || !m_n_gs_object)
		return false;
	// must be compiled, but not linked, need geometry shader

	glProgramParameteriEXT(m_n_gs_object, GL_GEOMETRY_OUTPUT_TYPE_EXT, n_output_type);

	return glGetError() == GL_NO_ERROR;
}

/*
 *	static int CGL_Core_shader::n_Geometry_MaxOutputVertices()
 *		- returns maximal number of vertices emitted by geometry shader in a single
 *		  invocation (ie. maximal value of SetGeometry_VerticesOut argument)
 */
int CGL_Core_shader::n_Geometry_MaxOutputVertices()
{
	int n_max_vertex_num;
	glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT, &n_max_vertex_num);
	return n_max_vertex_num;
}

/*
 *	static int CGL_Core_shader::n_Geometry_MaxOutputComponents()
 *		- returns maximal number of all vertex components produced
 *		  by geometry shader in a single invocation
 */
int CGL_Core_shader::n_Geometry_MaxOutputComponents()
{
	int n_max_component_num;
	glGetIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT, &n_max_component_num);
	return n_max_component_num;
}

/*
 *	bool CGL_Core_shader::SetGeometry_VerticesOut(int n_max_vertex_num)
 *		- sets maximal number of vertices emitted by geometry shader in a single invocation
 *		  (default 0). note this must be set, otherwise linking shader is going to fail.
 *		- note the shader must be compiled, but not linked and there
 *		  must be geometry shader
 *		- returns true on success, false on failure
 */
bool CGL_Core_shader::SetGeometry_VerticesOut(int n_max_vertex_num)
{
	if(!m_b_compiled || m_b_linked || !m_n_gs_object)
		return false;
	// must be compiled, but not linked, need geometry shader

	glProgramParameteriEXT(m_n_gs_object, GL_GEOMETRY_VERTICES_OUT_EXT, n_max_vertex_num);

	return glGetError() == GL_NO_ERROR;
}

/*
 *	virtual bool CGL_Core_shader::Link(char *&r_p_s_info_log)
 *		- link program, return info-log which has to be freed
 *		- can be called only if program was successfully compiled and not linked
 *		- returns true on success (can still return warnings), false on failure
 */
bool CGL_Core_shader::Link(char *&r_p_s_info_log)
{
	__FuncGuard("CGL_Core_shader::Link");

	r_p_s_info_log = 0;
	if(!m_b_compiled || m_b_linked)
		return false;

	glLinkProgram(m_n_program_object);
	int n_tmp;
	glGetProgramiv(m_n_program_object, GL_LINK_STATUS, &n_tmp);
	m_b_linked = n_tmp == GL_TRUE;
	// link

	int n_length;
	glGetProgramiv(m_n_program_object, GL_INFO_LOG_LENGTH, &n_length);
	if(n_length > 1) {
		const char *p_s_header = CShaderStringTable::p_s_Core_Shader_String();
		size_t n_header_length = strlen(p_s_header);
		if(!(r_p_s_info_log = new(std::nothrow) char[n_length + n_header_length]))
			return false;
#if defined(_MSC_VER) && !defined(__MWERKS__) && _MSC_VER >= 1400
		strcpy_s(r_p_s_info_log, (n_length + n_header_length) * sizeof(char), p_s_header);
#else // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
		strcpy(r_p_s_info_log, p_s_header);
#endif // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
		glGetProgramInfoLog(m_n_program_object, n_length, &n_length, r_p_s_info_log + n_header_length);
	}
	// get info-log

	return m_b_linked;
}

/*
 *	virtual int CGL_Core_shader::n_Uniform_Num() const
 *		- return number of uniform variables or -1 on failure
 *		- note this may also include OpenGL builtin uniforms such as
 *		  gl_ModelViewProjectionMatrixTranspose
 */
int CGL_Core_shader::n_Uniform_Num() const
{
	if(!m_b_compiled || !m_b_linked)
		return -1;

	int n_uniform_num;
	/*glGetShaderiv*/glGetProgramiv(m_n_program_object, GL_ACTIVE_UNIFORMS, &n_uniform_num);

	return (glGetError() == GL_NO_ERROR)? n_uniform_num : -1;
}

/*
 *	virtual char *CGL_Core_shader::p_s_Uniform_Name(int n_index,
 *		int &r_n_content_type, int &r_n_size) const
 *		- return name of uniform variable with index n_index or 0 on failure
 *		- r_n_content_type is set to variable content type (one of uniform_Float,
 *		  uniform_Float2, ...)
 *		- r_n_size is set to size of the uniform variable (1 for scalars, 1 or more
 *		  than 1 for arrays)
 */
char *CGL_Core_shader::p_s_Uniform_Name(int n_index, int &r_n_content_type, int &r_n_size) const
{
	if(!m_b_compiled || !m_b_linked)
		return 0;

	int n_max_name_length;
	/*glGetShaderiv*/glGetProgramiv(m_n_program_object,
		GL_ACTIVE_UNIFORM_MAX_LENGTH, &n_max_name_length);

	char *p_s_temp_name;
	if(!(p_s_temp_name = new(std::nothrow) char[n_max_name_length + 1]))
		return 0;

	int n_length;
	int n_size;
	GLenum n_type;
	glGetActiveUniform(m_n_program_object, n_index, n_max_name_length, &n_length,
		&n_size, &n_type, p_s_temp_name);

	r_n_size = n_size;

	r_n_content_type = CShaderParamTypeConverter::n_EnumValue(n_type);
	// translate the value

	if(glGetError() != GL_NO_ERROR) {
		delete[] p_s_temp_name;
		return 0;
	}

	if(strlen(p_s_temp_name) + 1 == n_max_name_length)
		return p_s_temp_name;
	else {
		char *p_s_name;
		if(!(p_s_name = new(std::nothrow) char[strlen(p_s_temp_name) + 1]))
			return p_s_temp_name;
#if defined(_MSC_VER) && !defined(__MWERKS__) && _MSC_VER >= 1400
		strcpy_s(p_s_name, (strlen(p_s_temp_name) + 1) * sizeof(char), p_s_temp_name);
#else // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
		strcpy(p_s_name, p_s_temp_name);
#endif // _MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
		delete[] p_s_temp_name;
		return p_s_name;
	}
}

/*
 *	virtual int CGL_Core_shader::n_GetUniformLocation(const char *p_s_uniform_name) const
 *		- returns uniform location by uniform name
 *		- note this fails on OpenGL builtin uniforms such as
 *		  gl_ModelViewProjectionMatrixTranspose
 *		- returns -1 on failure
 */
int CGL_Core_shader::n_GetUniformLocation(const char *p_s_uniform_name) const
{
	__FuncGuard("CGL_Core_shader::n_GetUniformLocation");

	if(!m_b_compiled || !m_b_linked)
		return -1; // f_ixme - 0 or -1 - answer is -1

	return glGetUniformLocation(m_n_program_object, p_s_uniform_name);
}

/*
 *	virtual bool CGL_Core_shader::SetParam1fv(CGLState *p_state, int n_param_type,
 *		int n_location, const float *p_value, int n_count = 1)
 *		- set float uniform to value of first element in p_value array
 *		- n_param_type is safe-check only, it should be shader_param_Uniform
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_Core_shader::SetParam1fv(CGLState *p_state, int n_param_type,
	int n_location, const float *p_value, int n_count)
{
	__FuncGuard("CGL_Core_shader::SetParam1fv");

	if(!m_b_compiled || !m_b_linked || n_param_type != shader_param_Uniform)
		return false;
	//_ASSERTE(n_param_type == shader_param_Uniform);
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParam1fv(n_location, n_count, p_value);
	return true;
}

/*
 *	virtual bool CGL_Core_shader::SetParam2fv(CGLState *p_state, int n_param_type,
 *		int n_location, const float *p_value, int n_count = 1)
 *		- set float vec2 uniform to value of first two elements in p_value array
 *		- n_param_type is safe-check only, it should be shader_param_Uniform
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_Core_shader::SetParam2fv(CGLState *p_state, int n_param_type,
	int n_location, const float *p_value, int n_count)
{
	__FuncGuard("CGL_Core_shader::SetParam2fv");

	if(!m_b_compiled || !m_b_linked || n_param_type != shader_param_Uniform)
		return false;
	//_ASSERTE(n_param_type == shader_param_Uniform);
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParam2fv(n_location, n_count, p_value);
	return true;
}

/*
 *	virtual bool CGL_Core_shader::SetParam3fv(CGLState *p_state, int n_param_type,
 *		int n_location, const float *p_value, int n_count = 1)
 *		- set float vec3 uniform to value of first three element in p_value array
 *		- n_param_type is safe-check only, it should be shader_param_Uniform
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_Core_shader::SetParam3fv(CGLState *p_state, int n_param_type,
	int n_location, const float *p_value, int n_count)
{
	__FuncGuard("CGL_Core_shader::SetParam3fv");

	if(!m_b_compiled || !m_b_linked || n_param_type != shader_param_Uniform)
		return false;
	//_ASSERTE(n_param_type == shader_param_Uniform);
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParam3fv(n_location, n_count, p_value);
	return true;
}

/*
 *	virtual bool CGL_Core_shader::SetParam4fv(CGLState *p_state, int n_param_type,
 *		int n_location, const float *p_value, int n_count = 1) const
 *		- set float vec4 uniform to value of first three element in p_value array
 *		- n_param_type is safe-check only, it should be shader_param_Uniform
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_Core_shader::SetParam4fv(CGLState *p_state, int n_param_type,
	int n_location, const float *p_value, int n_count) const
{
	__FuncGuard("CGL_Core_shader::SetParam4fv");

	if(!m_b_compiled || !m_b_linked || n_param_type != shader_param_Uniform)
		return false;
	//_ASSERTE(n_param_type == shader_param_Uniform);
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParam4fv(n_location, n_count, p_value);
	return true;
}

/*
 *	virtual bool CGL_Core_shader::SetParam1i(CGLState *p_state, int n_location, int n_value)
 *		- set integer uniform (sampler) to n_value
 *		- n_location is destination register index
 *		- returns true on success, false on failure
 */
bool CGL_Core_shader::SetParam1i(CGLState *p_state, int n_location, int n_value)
{
	__FuncGuard("CGL_Core_shader::SetParam1i");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);

	_SetParam1i(n_location, n_value);
	return true;
}

/*
 *	virtual bool CGL_Core_shader::SetParam1iv(CGLState *p_state, int n_location,
 *		const int *p_value, int n_count = 1)
 *		- set integer vec2 uniform to n_value of first two elements in p_value
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_Core_shader::SetParam1iv(CGLState *p_state,
	int n_location, const int *p_value, int n_count)
{
	__FuncGuard("CGL_Core_shader::SetParam1iv");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParam1iv(n_location, n_count, p_value);
	return true;
}

/*
 *	virtual bool CGL_Core_shader::SetParam2iv(CGLState *p_state, int n_location,
 *		const int *p_value, int n_count = 1)
 *		- set integer vec2 uniform to n_value of first two elements in p_value
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_Core_shader::SetParam2iv(CGLState *p_state,
	int n_location, const int *p_value, int n_count)
{
	__FuncGuard("CGL_Core_shader::SetParam2iv");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParam2iv(n_location, n_count, p_value);
	return true;
}

/*
 *	virtual bool CGL_Core_shader::SetParam3iv(CGLState *p_state, int n_location,
 *		const int *p_value, int n_count = 1)
 *		- set integer vec3 uniform to n_value of first three elements in p_value
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_Core_shader::SetParam3iv(CGLState *p_state, int n_location,
	const int *p_value, int n_count)
{
	__FuncGuard("CGL_Core_shader::SetParam3iv");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParam3iv(n_location, n_count, p_value);
	return true;
}

/*
 *	virtual bool CGL_Core_shader::SetParam4iv(CGLState *p_state, int n_location,
 *		const int *p_value, int n_count = 1)
 *		- set integer vec4 uniform to n_value of first four elements in p_value
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_Core_shader::SetParam4iv(CGLState *p_state,
	int n_location, const int *p_value, int n_count)
{
	__FuncGuard("CGL_Core_shader::SetParam4iv");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParam4iv(n_location, n_count, p_value);
	return true;
}

/*
 *	virtual bool CGL_Core_shader::SetParam1uiv(CGLState *p_state, int n_location,
 *		const unsigned int *p_value, int n_count = 1)
 *		- set unsigned integer vec2 uniform to n_value of first two elements in p_value
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_Core_shader::SetParam1uiv(CGLState *p_state,
	int n_location, const unsigned int *p_value, int n_count)
{
	__FuncGuard("CGL_Core_shader::SetParam1iv");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParam1uiv(n_location, n_count, p_value);
	return true;
}

/*
 *	virtual bool CGL_Core_shader::SetParam2uiv(CGLState *p_state, int n_location,
 *		const unsigned int *p_value, int n_count = 1)
 *		- set unsigned integer vec2 uniform to n_value of first two elements in p_value
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_Core_shader::SetParam2uiv(CGLState *p_state,
	int n_location, const unsigned int *p_value, int n_count)
{
	__FuncGuard("CGL_Core_shader::SetParam2iv");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParam2uiv(n_location, n_count, p_value);
	return true;
}

/*
 *	virtual bool CGL_Core_shader::SetParam3uiv(CGLState *p_state, int n_location,
 *		const unsigned int *p_value, int n_count = 1)
 *		- set unsigned integer vec3 uniform to n_value of first three elements in p_value
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_Core_shader::SetParam3uiv(CGLState *p_state, int n_location,
	const unsigned int *p_value, int n_count)
{
	__FuncGuard("CGL_Core_shader::SetParam3iv");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParam3uiv(n_location, n_count, p_value);
	return true;
}

/*
 *	virtual bool CGL_Core_shader::SetParam4uiv(CGLState *p_state, int n_location,
 *		const unsigned int *p_value, int n_count = 1)
 *		- set unsigned integer vec4 uniform to n_value of first four elements in p_value
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_Core_shader::SetParam4uiv(CGLState *p_state,
	int n_location, const unsigned int *p_value, int n_count)
{
	__FuncGuard("CGL_Core_shader::SetParam4iv");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParam4uiv(n_location, n_count, p_value);
	return true;
}

/*
 *	virtual bool CGL_Core_shader::SetParamMatrix2fv(CGLState *p_state, int n_location,
 *		bool b_transpose, const float *p_value, int n_count = 1)
 *		- set 2x2 float matrix uniform to 2x2 matrix form p_value
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_Core_shader::SetParamMatrix2fv(CGLState *p_state, int n_location,
	bool b_transpose, const float *p_value, int n_count)
{
	__FuncGuard("CGL_Core_shader::SetParamMatrix2fv");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParamMatrix2fv(n_location, n_count, b_transpose, p_value);
	return true;
}

/*
 *	virtual bool CGL_Core_shader::SetParamMatrix3fv(CGLState *p_state, int n_location,
 *		bool b_transpose, const float *p_value, int n_count = 1)
 *		- set 3x3 float matrix uniform to 3x3 matrix form p_value
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_Core_shader::SetParamMatrix3fv(CGLState *p_state, int n_location,
	bool b_transpose, const float *p_value, int n_count)
{
	__FuncGuard("CGL_Core_shader::SetParamMatrix3fv");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParamMatrix3fv(n_location, n_count, b_transpose, p_value);
	return true;
}

/*
 *	virtual bool CGL_Core_shader::SetParamMatrix4fv(CGLState *p_state, int n_location,
 *		bool b_transpose, const float *p_value, int n_count = 1)
 *		- set 4x4 float matrix uniform to 4x4 matrix form p_value
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_Core_shader::SetParamMatrix4fv(CGLState *p_state, int n_location,
	bool b_transpose, const float *p_value, int n_count)
{
	__FuncGuard("CGL_Core_shader::SetParamMatrix4fv");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParamMatrix4fv(n_location, n_count, b_transpose, p_value);
	return true;
}

/*
 *	virtual bool CGL_Core_shader::SetParamMatrix2x3fv(CGLState *p_state, int n_location,
 *		bool b_transpose, const float *p_value, int n_count = 1)
 *		- set 2x3 float matrix uniform to 2x3 matrix form p_value
 *		- note this is OpenGL 2.1 function
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_Core_shader::SetParamMatrix2x3fv(CGLState *p_state, int n_location,
	bool b_transpose, const float *p_value, int n_count)
{
	__FuncGuard("CGL_Core_shader::SetParamMatrix2x3fv");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParamMatrix2x3fv(n_location, n_count, b_transpose, p_value);
	return true;
}

/*
 *	virtual bool CGL_Core_shader::SetParamMatrix3x2fv(CGLState *p_state, int n_location,
 *		bool b_transpose, const float *p_value, int n_count = 1)
 *		- set 3x2 float matrix uniform to 3x2 matrix form p_value
 *		- note this is OpenGL 2.1 function
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_Core_shader::SetParamMatrix3x2fv(CGLState *p_state, int n_location,
	bool b_transpose, const float *p_value, int n_count)
{
	__FuncGuard("CGL_Core_shader::SetParamMatrix3x2fv");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParamMatrix3x2fv(n_location, n_count, b_transpose, p_value);
	return true;
}

/*
 *	virtual bool CGL_Core_shader::SetParamMatrix2x4fv(CGLState *p_state, int n_location,
 *		bool b_transpose, const float *p_value, int n_count = 1)
 *		- set 2x4 float matrix uniform to 2x4 matrix form p_value
 *		- note this is OpenGL 2.1 function
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_Core_shader::SetParamMatrix2x4fv(CGLState *p_state, int n_location,
	bool b_transpose, const float *p_value, int n_count)
{
	__FuncGuard("CGL_Core_shader::SetParamMatrix2x4fv");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParamMatrix2x4fv(n_location, n_count, b_transpose, p_value);
	return true;
}

/*
 *	virtual bool CGL_Core_shader::SetParamMatrix4x2fv(CGLState *p_state, int n_location,
 *		bool b_transpose, const float *p_value, int n_count = 1)
 *		- set 4x2 float matrix uniform to 4x2 matrix form p_value
 *		- note this is OpenGL 2.1 function
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_Core_shader::SetParamMatrix4x2fv(CGLState *p_state, int n_location,
	bool b_transpose, const float *p_value, int n_count)
{
	__FuncGuard("CGL_Core_shader::SetParamMatrix4x2fv");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParamMatrix4x2fv(n_location, n_count, b_transpose, p_value);
	return true;
}

/*
 *	virtual bool CGL_Core_shader::SetParamMatrix3x4fv(CGLState *p_state, int n_location,
 *		bool b_transpose, const float *p_value, int n_count = 1)
 *		- set 3x4 float matrix uniform to 3x4 matrix form p_value
 *		- note this is OpenGL 2.1 function
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_Core_shader::SetParamMatrix3x4fv(CGLState *p_state, int n_location,
	bool b_transpose, const float *p_value, int n_count)
{
	__FuncGuard("CGL_Core_shader::SetParamMatrix3x4fv");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParamMatrix3x4fv(n_location, n_count, b_transpose, p_value);
	return true;
}

/*
 *	virtual bool CGL_Core_shader::SetParamMatrix4x3fv(CGLState *p_state, int n_location,
 *		bool b_transpose, const float *p_value, int n_count = 1)
 *		- set 4x3 float matrix uniform to 4x3 matrix form p_value
 *		- note this is OpenGL 2.1 function
 *		- n_location is destination register index
 *		- n_count is number of parameters to set
 *		- returns true on success, false on failure
 */
bool CGL_Core_shader::SetParamMatrix4x3fv(CGLState *p_state, int n_location,
	bool b_transpose, const float *p_value, int n_count)
{
	__FuncGuard("CGL_Core_shader::SetParamMatrix4x3fv");

	if(!m_b_compiled || !m_b_linked)
		return false;
	_Bind(p_state);

	_ASSERTE(n_location >= 0);
	_ASSERTE(p_value);

	_SetParamMatrix4x3fv(n_location, n_count, b_transpose, p_value);
	return true;
}

/*
 *	virtual void CGL_Core_shader::Bind(CGLState *p_state) const
 *		- binds shader
 */
void CGL_Core_shader::Bind(CGLState *p_state) const
{
	__FuncGuard("CGL_Core_shader::Bind");

	_Bind(p_state);
}

/*
 *	virtual void CGL_Core_shader::Release(CGLState *p_state) const
 *		- un-binds shader
 *		- use for safe switching between shaders with different api-s
 */
void CGL_Core_shader::Release(CGLState *p_state) const
{
	__FuncGuard("CGL_Core_shader::Release");

	_Release(p_state);
}

/*
 *	virtual void CGL_Core_shader::Delete()
 *		- free open-gl resources
 *		- if program is about to be used again, it must be re-compiled,
 *		  re-bound vertex attribs, re-linked and re-queried for unifroms
 */
void CGL_Core_shader::Delete()
{
	__FuncGuard("CGL_Core_shader::Delete");

	//CGLProgram::Release(p_state);

	m_b_compiled = false;
	m_b_linked = false;

	if(m_n_program_object) {
		glDeleteProgram(m_n_program_object);
		CGLState::NotifyDeleteProgramObject_GL2(m_n_program_object);
		m_n_program_object = 0;
	}
	if(m_n_vs_object) {
		glDeleteShader(m_n_vs_object);
		m_n_vs_object = 0;
	}
	if(m_n_gs_object) {
		glDeleteShader(m_n_gs_object);
		m_n_gs_object = 0;
	}
	if(m_n_fs_object) {
		glDeleteShader(m_n_fs_object);
		m_n_fs_object = 0;
	}
}

/*
 *	virtual int CGL_Core_shader::n_Api() const
 *		- return which api is used
 */
int CGL_Core_shader::n_Api() const
{
	__FuncGuard("CGL_Core_shader::n_Api");

	return shader_api_Core_shader;
}

/*
 *								=== ~CGL_Core_shader ===
 */
