/*
								+---------------------------------+
								|                                 |
								|  ***   OpenGL 3.0 shader   ***  |
								|                                 |
								|  Copyright  © -tHE SWINe- 2009  |
								|                                 |
								|            Shader3.h            |
								|                                 |
								+---------------------------------+
*/

#pragma once
#ifndef __GL30_SHADER_INCLUDED
#define __GL30_SHADER_INCLUDED

/**
 *	@file gl3/Shader3.h
 *	@author -tHE SWINe-
 *	@date 2009
 *	@brief OpenGL 3.0 shaders
 *
 *	@todo Write documentation for this, make sure all useful extensions are implemented.
 *	@todo Implement GL_ARB_uniform_buffer_object (OpenGL 3.1 core).
 *	@todo Implement standalone vertex / geometry / fragment shaders which connect at runtime (todo - which extension is that?)
 *	@todo Add support for tesselation shaders (and any more shaders?).
 *
 *	@date 2012-06-19
 *
 *	Moved multiple inclusion guard before file documentation comment.
 *
 */

#include "OpenGL30.h"

/*
 *	class CGL3Shader
 *		- class, encapsulating OpenGL 3 high-level vertex and fragment shaders
 */
class CGL3Shader {
protected:
	GLuint m_n_program_object;
	GLuint m_n_vs_object, m_n_gs_object, m_n_fs_object;

	bool m_b_compiled, m_b_linked;

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

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

	/*
	 *	virtual bool CGL3Shader::Compile(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 Compile(const char *p_s_vertex_shader, const char *p_s_geometry_shader,
		const char *p_s_fragment_shader, std::string &r_s_info_log);

	/*
	 *	virtual bool CGL3Shader::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 BindAttribLocation(int n_location, const char *p_s_attrib_name);

	/*
	 *	bool CGL3Shader::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 SetGeometry_InputType(GLenum n_input_type = GL_TRIANGLES);

	/*
	 *	bool CGL3Shader::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 SetGeometry_OutputType(GLenum n_output_type = GL_TRIANGLE_STRIP);

	/*
	 *	static int CGL3Shader::n_Geometry_MaxOutputVertices()
	 *		- returns maximal number of vertices emitted by geometry shader in a single
	 *		  invocation (ie. maximal value of SetGeometry_VerticesOut argument)
	 */
	static int n_Geometry_MaxOutputVertices();

	/*
	 *	static int CGL3Shader::n_Geometry_MaxOutputComponents()
	 *		- returns maximal number of all vertex components produced
	 *		  by geometry shader in a single invocation
	 */
	static int n_Geometry_MaxOutputComponents();

	/*
	 *	bool CGL3Shader::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.
	 *		- maximal value of n_max_vertex_num is constrained by n_Geometry_MaxOutputVertices()
	 *		  and indirectly by n_Geometry_MaxOutputComponents()
	 *		- note the shader must be compiled, but not linked and there
	 *		  must be geometry shader
	 *		- returns true on success, false on failure
	 */
	bool SetGeometry_VerticesOut(int n_max_vertex_num);

	/*
	 *	virtual bool CGL3Shader::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 Link(std::string &r_s_info_log);

	/*
	 *	virtual int CGL3Shader::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 n_Uniform_Num() const;

	/*
	 *	virtual char *CGL3Shader::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 *p_s_Uniform_Name(int n_index, GLenum &r_n_content_type, int &r_n_size) const;

	/*
	 *	virtual int CGL3Shader::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 n_GetUniformLocation(const char *p_s_uniform_name) const;

	/*
	 *	virtual void CGL3Shader::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 Delete();

	inline void Bind() const;
	inline void Release() const;

	// the following functions  don't do any parameter checking, they do assume shader is bound
	inline void SetUniform1fv(int n_location, int n_count, const float *p_value) const;
	inline void SetUniform2fv(int n_location, int n_count, const float *p_value) const;
	inline void SetUniform3fv(int n_location, int n_count, const float *p_value) const;
	inline void SetUniform4fv(int n_location, int n_count, const float *p_value) const;
	inline void SetUniform1i(int n_location, int n_value) const;
	inline void SetUniform1iv(int n_location, int n_count, const int *p_value) const;
	inline void SetUniform2iv(int n_location, int n_count, const int *p_value) const;
	inline void SetUniform3iv(int n_location, int n_count, const int *p_value) const;
	inline void SetUniform4iv(int n_location, int n_count, const int *p_value) const;
	inline void SetUniformMatrix2fv(int n_location,
		int n_count, bool b_transpose, const float *p_value) const;
	inline void SetUniformMatrix3fv(int n_location,
		int n_count, bool b_transpose, const float *p_value) const;
	inline void SetUniformMatrix4fv(int n_location,
		int n_count, bool b_transpose, const float *p_value) const;

	// OpenGL 2.1
	inline void SetUniformMatrix2x3fv(int n_location,
		int n_count, bool b_transpose, const float *p_value) const;
	inline void SetUniformMatrix3x2fv(int n_location,
		int n_count, bool b_transpose, const float *p_value) const;
	inline void SetUniformMatrix2x4fv(int n_location,
		int n_count, bool b_transpose, const float *p_value) const;
	inline void SetUniformMatrix4x2fv(int n_location,
		int n_count, bool b_transpose, const float *p_value) const;
	inline void SetUniformMatrix3x4fv(int n_location,
		int n_count, bool b_transpose, const float *p_value) const;
	inline void SetUniformMatrix4x3fv(int n_location,
		int n_count, bool b_transpose, const float *p_value) const;

	// GL_EXT_gpu_shader4
	inline void SetUniform1uiv(int n_location, int n_count, const unsigned int *p_value) const;
	inline void SetUniform2uiv(int n_location, int n_count, const unsigned int *p_value) const;
	inline void SetUniform3uiv(int n_location, int n_count, const unsigned int *p_value) const;
	inline void SetUniform4uiv(int n_location, int n_count, const unsigned int *p_value) const;
};

#include "Shader3.inl"
// fast inline functions

#endif // !__GL30_SHADER_INCLUDED
