Added by an anonymous coder 7 months, 3 weeks 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
{
public:
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(){
glUseProgram(prog_glname_);
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
glm::mat4,
int > uniform_types;
typedef mpl::vector< glm::vec2,
glm::vec3,
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
&& "YOU CANNOT COMPILE A CALL TO UPDATE_UNIFORM FUNCTION WITH A NON RECOGNIZED TYPE"));
// 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);
else
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);
break;
}
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));
break;
}
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));
break;
}
case 6: { // int
GLint buildable = forward<GLint, uniform_t>(value);
glUniform1i(uniform_location, buildable);
}
}
check_gl_error(SCUD_PROG_POS);
}
static void unset(){
glUseProgram(0);
last_set_prog_ = 0;
}
private:
GLuint prog_glname_;
static GLuint last_set_prog_;
};
}
#endif //SHADER_OBJECTS_HPP_INC_01_10_2009__184855354_
Not logged in (Log in)