@ -13,6 +13,7 @@
// TODO: do glValidateProgram, like in the OpenGL template (see bottom)
// TODO: add error checking at set_uniforms?
// TODO: use an uniform map? (benchmark first!)
// TODO: allow arrays is uniforms (now all counts are 1)
namespace J {
@ -23,6 +24,7 @@ enum {
} ;
class shader {
// NOTE: it could be hardcoded to use vertex_shader and fragment_shader.
typedef std : : map < GLenum , GLuint > ShaderMap ;
GLuint program ;
@ -30,6 +32,8 @@ class shader {
public :
// ***********
// constructor
shader ( std : : string vertex_shader_filename , std : : string fragment_shader_filename ) :
program ( 0 ) , shaders ( ) {
program = glCreateProgram ( ) ;
@ -42,13 +46,13 @@ public:
std : : ifstream vertex_shader ( vertex_shader_filename . c_str ( ) ) ;
if ( ! vertex_shader )
throw std : : runtime_error ( vertex_shader_filename + " couldn't be opened " ) ;
read _shader( vertex_shader , GL_VERTEX_SHADER ) ;
compile _shader( vertex_shader , GL_VERTEX_SHADER ) ;
}
{ // fragment shader
std : : ifstream fragment_shader ( fragment_shader_filename . c_str ( ) ) ;
if ( ! fragment_shader )
throw std : : runtime_error ( fragment_shader_filename + " couldn't be opened " ) ;
read _shader( fragment_shader , GL_FRAGMENT_SHADER ) ;
compile _shader( fragment_shader , GL_FRAGMENT_SHADER ) ;
}
{ // TODO: think of a nice way to implement this
// Bind attribute locations.
@ -69,12 +73,13 @@ public:
glDeleteShader ( shader ) ;
// NOTE: If a shader object to be deleted is attached to a program object, it will be flagged for deletion, but it will not be deleted until it is no longer attached to any program object
}
glDeleteProgram ( program ) ;
end ( ) ;
glDeleteProgram ( program ) ;
}
// *****
// usage
void begin ( ) {
glUseProgram ( program ) ;
}
@ -83,6 +88,10 @@ public:
glUseProgram ( 0 ) ;
}
// ***************
// uniform setters
// float vectors (multiple values)
void set_uniform ( char const * name , float x ) const {
glUniform1f ( glGetUniformLocation ( program , name ) , x ) ;
}
@ -99,6 +108,7 @@ public:
glUniform4f ( glGetUniformLocation ( program , name ) , x , y , z , w ) ;
}
// integer vectors (multiple values)
void set_uniform ( char const * name , int x ) const {
glUniform1i ( glGetUniformLocation ( program , name ) , x ) ;
}
@ -114,32 +124,79 @@ public:
void set_uniform ( char const * name , int x , int y , int z , int w ) const {
glUniform4i ( glGetUniformLocation ( program , name ) , x , y , z , w ) ;
}
// Float vectors (array)
void set_uniform ( char const * name , const GLfloat ( & value ) [ 4 ] ) const {
glUniform4fv ( glGetUniformLocation ( program , name ) , 1 , value ) ;
}
void set_uniform ( char const * name , const GLfloat ( & value ) [ 3 ] ) const {
glUniform3fv ( glGetUniformLocation ( program , name ) , 1 , value ) ;
}
void set_uniform ( char const * name , const GLfloat ( & value ) [ 2 ] ) const {
glUniform2fv ( glGetUniformLocation ( program , name ) , 1 , value ) ;
}
void set_uniform ( char const * name , const GLfloat ( & value ) [ 1 ] ) const {
glUniform1fv ( glGetUniformLocation ( program , name ) , 1 , value ) ;
}
// Integer vectors (array)
void set_uniform ( char const * name , const GLint ( & value ) [ 4 ] ) const {
glUniform4iv ( glGetUniformLocation ( program , name ) , 1 , value ) ;
}
void set_uniform ( char const * name , const GLint ( & value ) [ 3 ] ) const {
glUniform3iv ( glGetUniformLocation ( program , name ) , 1 , value ) ;
}
void set_uniform ( char const * name , const GLint ( & value ) [ 2 ] ) const {
glUniform2iv ( glGetUniformLocation ( program , name ) , 1 , value ) ;
}
void set_uniform ( char const * name , const GLint ( & value ) [ 1 ] ) const {
glUniform1iv ( glGetUniformLocation ( program , name ) , 1 , value ) ;
}
// TODO: add support for other matrices (not only 4x4), in ES2 only square matrices
void set_matrix ( char const * name , bool trans , const GLfloat * value ) const {
// matrices (in ES2 only square matrices)
void set_unifor m ( char const * name , const GLfloat ( & value ) [ 16 ] , GLboolean trans = GL_FALSE ) const {
glUniformMatrix4fv ( glGetUniformLocation ( program , name ) , 1 , trans , value ) ;
}
// TODO: add support for other vectors (not only length 4)
void set_uniform ( char const * name , const GLfloat * value , GLsizei count = 1 ) const {
glUniform4fv ( glGetUniformLocation ( program , name ) , count , value ) ;
void set_uniform ( char const * name , const GLfloat ( & value ) [ 9 ] , GLboolean trans = GL_FALSE ) const {
glUniformMatrix3fv ( glGetUniformLocation ( program , name ) , 1 , trans , value ) ;
}
// TODO: add support for other vectors (not only length 4)
void set_uniform ( char const * name , const GLint * value , GLsizei count = 1 ) const {
glUniform4iv ( glGetUniformLocation ( program , name ) , count , value ) ;
void set_uniform ( char const * name , const GLfloat ( & value ) [ 4 ] , GLboolean trans = GL_FALSE ) const {
glUniformMatrix2fv ( glGetUniformLocation ( program , name ) , 1 , trans , value ) ;
}
// textures (see todo above)
void set_texture ( const char * name , GLenum target , GLuint tex , int textureLocation ) const {
glActiveTexture ( GL_TEXTURE0 + textureLocation ) ;
glBindTexture ( target , tex ) ;
set_uniform ( name , textureLocation ) ;
}
// *********
// validator
void validate ( ) {
GLint status ;
glValidateProgram ( program ) ;
glGetProgramiv ( program , GL_VALIDATE_STATUS , & status ) ;
if ( status = = GL_FALSE ) {
std : : cerr < < " validator reports: " < < std : : endl ;
show_log ( ) ;
throw std : : runtime_error ( " Program not valid " ) ;
}
}
private :
// FIXME: this also compiles, bad name
void read_shader ( std : : istream & file , GLenum type ) {
// *******************
// compiling / linking
void compile_shader ( std : : istream & file , GLenum type ) {
// get the c-string, the shortest way (not fastest)
std : : string buffer ( ( std : : istreambuf_iterator < char > ( file ) ) , std : : istreambuf_iterator < char > ( ) ) ;
const char * sptr = buffer . c_str ( ) ;
@ -150,21 +207,9 @@ private:
glShaderSource ( shader , 1 , & sptr , & ssize ) ;
glCompileShader ( shader ) ;
# if defined(DEBUG)
// check compile status
GLint status = GL_FALSE ;
glGetShaderiv ( shader , GL_COMPILE_STATUS , & status ) ;
if ( status = = GL_FALSE | | shader = = 0 ) {
GLsizei infoLength = 0 ;
glGetShaderiv ( shader , GL_INFO_LOG_LENGTH , & infoLength ) ;
char * infoBuffer = new GLchar [ infoLength ] ;
glGetShaderInfoLog ( shader , infoLength , & infoLength , infoBuffer ) ;
std : : cerr < < " source: \n " < < buffer < < std : : endl ;
std : : cerr < < " shader reports: \n " < < infoBuffer < < std : : endl ;
delete [ ] infoBuffer ;
throw std : : runtime_error ( " Shader failed to compile " ) ;
}
# endif
# if defined(DEBUG)
check_compile_status ( shader , buffer ) ;
# endif
// put it in tha map
shaders [ type ] = shader ;
@ -181,47 +226,42 @@ private:
// link
glLinkProgram ( program ) ;
# if defined(DEBUG)
// check link status
# if defined(DEBUG)
check_link_status ( ) ;
# endif
}
// ***************
// status checking
void check_compile_status ( GLint shader , std : : string source = " " ) {
GLint status = GL_FALSE ;
glGetShaderiv ( shader , GL_COMPILE_STATUS , & status ) ;
if ( status = = GL_FALSE | | shader = = 0 ) {
std : : cerr < < " source: \n " < < source < < std : : endl ;
std : : cerr < < " shader reports: " < < std : : endl ;
show_log ( ) ;
throw std : : runtime_error ( " Shader failed to compile " ) ;
}
}
void check_link_status ( ) {
GLint status ;
glGetProgramiv ( program , GL_LINK_STATUS , & status ) ;
if ( status = = GL_FALSE ) {
GLsizei infoLength = 0 ;
glGetProgramiv ( program , GL_INFO_LOG_LENGTH , & infoLength ) ;
char * infoBuffer = new GLchar [ infoLength ] ;
glGetProgramInfoLog ( program , infoLength , & infoLength , infoBuffer ) ;
std : : cerr < < " linker reports: \n " < < infoBuffer < < std : : endl ;
delete [ ] infoBuffer ;
std : : cerr < < " linker reports: " < < std : : endl ;
show_log ( ) ;
throw std : : runtime_error ( " Shader failed to link " ) ;
}
# endif
}
/*
// Validate program before drawing. This is a good check, but only really necessary in a debug build.
- ( BOOL ) validateProgram : ( GLuint ) prog
{
GLint logLength , status ;
glValidateProgram ( prog ) ;
glGetProgramiv ( prog , GL_INFO_LOG_LENGTH , & logLength ) ;
if ( logLength > 0 )
{
GLchar * log = ( GLchar * ) malloc ( logLength ) ;
glGetProgramInfoLog ( prog , logLength , & logLength , log ) ;
NSLog ( @ " Program validate log: \n %s " , log ) ;
free ( log ) ;
}
glGetProgramiv ( prog , GL_VALIDATE_STATUS , & status ) ;
if ( status = = 0 )
return FALSE ;
return TRUE ;
}
*/
}
void show_log ( std : : ostream & out = std : : cerr ) {
GLsizei infoLength = 0 ;
glGetProgramiv ( program , GL_INFO_LOG_LENGTH , & infoLength ) ;
char * infoBuffer = new GLchar [ infoLength ] ;
glGetProgramInfoLog ( program , infoLength , & infoLength , infoBuffer ) ;
out < < infoBuffer < < std : : endl ;
delete [ ] infoBuffer ;
}
} ;
} // namespace J