glsl shader C++ manager

Added by an anonymous coder 2 years, 7 months ago.

 * File  : shader_objects.hpp
 * Author: Lightness1024!
 * Date  : 01/10/2009

#ifndef SHADER_OBJECTS_HPP_INC_01_10_2009__184855354_
#define SHADER_OBJECTS_HPP_INC_01_10_2009__184855354_ 1

#include <manager_base.hpp>
#include <boost/format.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/contains.hpp>
#include <boost/mpl/find.hpp>
#include <boost/mpl/size.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/array.hpp>
#include <boost/scoped_ptr.hpp>
#include <stdio.h>
#include <GL/glew.h>
#include <iostream>
#include <math/glm/virtrev/address.hpp>
#include <gl_tbx.hpp>
#include <tbx/config.hpp>

extern boost::scoped_ptr<tbx::config> conf;

namespace gfx
	namespace detail
		char* get_shader_source(const char * szfilename);
		int load_program(char const* vtx_code_src, char const* frag_code_src);

	namespace mpl = boost::mpl;
	// forwarders of type, one will just copy the input into the return value if the argument is of the
	// same type than the required output. the second will ignore the argument, and return a default constructed return type.
	// these function exist to enable compilation of function working of 'mat' when the argument is of type 'vec', which are incompatible.
	template< typename target_t, typename src_t >
	target_t forward(src_t const& val, typename boost::enable_if<boost::is_same<target_t, src_t> >::type* dummy = 0)
		return val;

	template< typename target_t, typename src_t >
	target_t forward(src_t const& val, typename boost::disable_if<boost::is_same<target_t, src_t> >::type* dummy = 0)
		return target_t();

 	//! represents a GLSL program that contains code for vertex and fragment shaders.
 	class glsl_program
		glsl_program(char const* vtx_code_src, char const* frag_code_src) {
			prog_glname_ = detail::load_program(vtx_code_src, frag_code_src);
			if (prog_glname_ == 0){
				throw std::runtime_error(
					(boost::format("couldn't load shader files: %1% and/or %2%")
					 % vtx_code_src
					 % frag_code_src).str());

		void set(){
			last_set_prog_ = prog_glname_;

		//! all uniform types we can manage:
		typedef mpl::vector< float,     // 0
							 glm::vec2, // 1
							 glm::vec3, // 2
							 glm::vec4, // 3
							 glm::mat3, // 4
							 int >      uniform_types;

		typedef mpl::vector< glm::vec2,
							 glm::vec4> vec_types;

		typedef mpl::vector< glm::mat3,
							 glm::mat4> mat_types;

		template< typename check_against_t >
		struct is_type_handled_uniform{
			static bool const value = mpl::contains< uniform_types, check_against_t >::type::value;

		template< typename uniform_t >
		void update_uniform(char const* name, uniform_t const& value){
			// check that the function is not used outside of its managed types (c.f. uniform_types):
			static_assert(( is_type_handled_uniform< uniform_t >::value
			// other checks:
			assert(name && "CANNOT PASS NULL AS NAME");
			assert(prog_glname_ > 0 && "CANNOT USE UPDATE_UNIFORM ON NON-LINKED PROGRAM");
			assert(last_set_prog_ == prog_glname_ && "CANNOT USE UPDATE_UNIFORM ON NON-ATTACHED PROGRAM");
			// type of functions from the gl specification:
			typedef void (*gl_func_fv_t) (GLint, GLsizei, GLfloat const*);             // vectors
			typedef void (*gl_func_mat_t) (GLint, GLsizei, GLboolean, GLfloat const*); // matrices
			// define an array of functions for vectors:
			boost::array< gl_func_fv_t, 3 > const
				set_uniform_fv = {{glUniform2fv, glUniform3fv, glUniform4fv}};
			// array of functions for matrices:
			boost::array< gl_func_mat_t, 2 > const
				set_uniform_mat = {{glUniformMatrix3fv, glUniformMatrix4fv}};
			// find client's type position in sequence:
			size_t type_pos = mpl::find< uniform_types, uniform_t >::type::pos::value;
			// find uniform location in the shader program:
			size_t uniform_location = glGetUniformLocation(prog_glname_, name);
			if (uniform_location == -1) {
				std::string err_msg =
					(boost::format("attempt to modify uniform \"%1%\", but wasn't found in the shader program."
								   "\n  note: this is a hard error. you can make it soft by adding\"continue_on_uniform_issues=bool:true\" to your scud.conf")
					 % name).str();
				if (!conf->property<bool>("continue_on_uniform_issues", false))
					throw std::runtime_error(err_msg);
					std::cout << err_msg << std::endl;
			// execute appropriate gl function to set the uniform:
			assert(type_pos <= mpl::size<uniform_types>::type::value);
			//std::cout << "type pos:" << type_pos << std::endl;
			switch (type_pos){
				case 0: {  // float
					GLfloat buildable = forward<GLfloat, uniform_t>(value);
					glUniform1f(uniform_location, buildable);
				case 1: case 2: case 3: {   // vecs
					// clamp uniform_t to a vec type to avoid build error
					typedef typename mpl::contains< vec_types, uniform_t >::type is_vec;
					typedef typename mpl::find< vec_types, uniform_t >::type found_among_vecs_iter;
					typedef typename mpl::deref<found_among_vecs_iter>::type found_among_vecs_t;
					typedef typename mpl::if_< is_vec, found_among_vecs_t, glm::vec4 >::type best_vec_t;

					best_vec_t buildable = forward<best_vec_t, uniform_t>(value);
					set_uniform_fv[type_pos - 1](uniform_location, 1, glm::address(buildable));
				case 4: case 5: {    // mats
					typedef typename mpl::contains< mat_types, uniform_t >::type is_mat;
					typedef typename mpl::find< mat_types, uniform_t >::type found_among_mats_iter;
					typedef typename mpl::deref< found_among_mats_iter >::type found_among_mats_t;
					typedef typename mpl::if_< is_mat, found_among_mats_t, glm::mat4 >::type best_mat_t;

					best_mat_t buildable = forward<best_mat_t, uniform_t>(value);
					set_uniform_mat[type_pos - 4](uniform_location, 1, GL_FALSE, glm::address(buildable));
				case 6: {   // int
					GLint buildable = forward<GLint, uniform_t>(value);
					glUniform1i(uniform_location, buildable);

		static void unset(){
			last_set_prog_ = 0;

		GLuint prog_glname_;
		static GLuint last_set_prog_;

#endif //SHADER_OBJECTS_HPP_INC_01_10_2009__184855354_

Not logged in (Log in)