FlowVis 1.0

FlowVis/shader.cpp

00001 #include <fstream>
00002 
00003 #include "shader.h"
00004 
00005 Shader::Shader(const string &path) :
00006 _success(false)
00007 {
00008         _success = init(path, false, 0, 0, 0);
00009         if (!_success) return;
00010         get_errors();
00011 }
00012 
00013 Shader::Shader(const string &path, bool geometryShader, GLenum inputType, 
00014         GLenum outputType, GLint maxOutVertices) : _success(false)
00015 {
00016         _success = init(path, geometryShader, inputType, outputType, maxOutVertices);
00017         if (!_success) return;
00018         get_errors();
00019 }
00020 
00021 Shader::~Shader()
00022 {
00023         glDeleteProgram(_program);
00024         glDeleteShader(_vertex_shader);
00025         if (_geometry_shader != 0)
00026                 glDeleteShader(_geometry_shader);
00027         glDeleteShader(_fragment_shader);
00028 }
00029 
00030 bool Shader::init(const string &path, bool geometryShader, GLenum inputType, 
00031         GLenum outputType, GLint maxOutVertices)
00032 {
00033         // Load the shader files
00034 
00035         string vertex_shader_source;
00036         if (file_exists(path+".vert")) {
00037                 vertex_shader_source = read_file(path+".vert");
00038         } else {
00039                 cerr << "Vertex shader file "
00040                         << path <<".vert does not exist." << endl;
00041                 return false;
00042         }
00043 
00044         string geometry_shader_source;
00045         if (geometryShader)
00046         {
00047                 if (file_exists(path+".geom")) {
00048                         geometry_shader_source = read_file(path+".geom");
00049                 } else {
00050                         cerr << "Geometry shader file "
00051                                 << path <<".geom does not exist." << endl;
00052                         return false;
00053                 }
00054         }
00055 
00056         string fragment_shader_source;
00057         if (file_exists(path+".frag")) {
00058                 fragment_shader_source = read_file(path+".frag");
00059         } else {
00060                 cerr << "Fragment shader file "
00061                         << path <<".frag does not exist." << endl;
00062                 return false;
00063         }
00064 
00065         // Compile the shaders
00066 
00067         _vertex_shader = compile(GL_VERTEX_SHADER, vertex_shader_source);
00068         if (_vertex_shader == 0)
00069                 return false;
00070 
00071         get_errors();
00072 
00073         if (geometryShader)
00074         {
00075                 _geometry_shader = compile(GL_GEOMETRY_SHADER_EXT, geometry_shader_source);
00076                 if (_geometry_shader == 0)
00077                         return false;
00078 
00079                 get_errors();
00080         }
00081 
00082         _fragment_shader = compile(GL_FRAGMENT_SHADER, fragment_shader_source);
00083         if (_fragment_shader == 0)
00084                 return false;
00085 
00086         get_errors();
00087 
00088         // Link the shaders into a program
00089 
00090         link(geometryShader, inputType, outputType, maxOutVertices);
00091         if (_program == 0)
00092                 return false;
00093 
00094         return true;
00095 }
00096 
00097 GLuint Shader::compile (GLenum type, const string &source)
00098 {
00099         // Create shader object
00100 
00101         GLuint shader = glCreateShader(type);
00102 
00103         if (shader == 0) {
00104                 cerr << "Could not create shader object." << endl;
00105                 return 0;
00106         }
00107 
00108         // Define shader source and compile
00109 
00110         const char* src = source.data();
00111         int len = source.size();
00112 
00113         glShaderSource(shader, 1, &src, (const GLint*)&len);
00114 
00115         glCompileShader(shader);
00116 
00117         // Check for errors
00118 
00119         int status;
00120 
00121         glGetShaderiv(shader, GL_COMPILE_STATUS, (GLint*)&status);
00122 
00123         if (status != GL_TRUE) {
00124                 cout << "Shader compilation failed." << endl;
00125                 shader_log(shader);
00126         }
00127 
00128         get_errors();
00129 
00130         return shader;    
00131 }
00132 
00133 void Shader::link(bool geometryShader, GLenum inputType, 
00134         GLenum outputType, GLint maxOutVertices)
00135 {
00136         // Create program handle
00137         _program = glCreateProgram();
00138 
00139         if (geometryShader)
00140         {
00141                 // Set geometry shader params
00142                 glProgramParameteriEXT(_program, GL_GEOMETRY_INPUT_TYPE_EXT, inputType);
00143                 get_errors();
00144                 glProgramParameteriEXT(_program, GL_GEOMETRY_OUTPUT_TYPE_EXT, outputType);
00145                 get_errors();
00146                 if (maxOutVertices == 0)
00147                         glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT, &maxOutVertices);
00148         
00149                 glProgramParameteriEXT(_program, GL_GEOMETRY_VERTICES_OUT_EXT, maxOutVertices);
00150                 get_errors();
00151         }
00152 
00153         // Attach shaders and link
00154         glAttachShader(_program, _vertex_shader);
00155         if (geometryShader)
00156                 glAttachShader(_program, _geometry_shader);
00157         glAttachShader(_program, _fragment_shader);
00158 
00159         glLinkProgram(_program);
00160 
00161         // Check for problems
00162 
00163         int status;
00164 
00165         glGetProgramiv(_program, GL_LINK_STATUS, (GLint*)&status);
00166 
00167         if (status != GL_TRUE) {
00168                 cout << "Shader linking failed." << endl;
00169                 program_log(_program);
00170 
00171                 glDeleteProgram(_program);
00172                 _program = 0;
00173         }
00174 
00175         get_errors();
00176 }
00177 
00178 bool Shader::file_exists(const string &filename)
00179 {
00180         std::ifstream ifile(filename.c_str());
00181         return ifile;
00182 }
00183 
00184 string Shader::read_file(const string &filename)
00185 {
00186         std::ifstream ifile(filename.c_str());
00187 
00188         return string(std::istreambuf_iterator<char>(ifile),
00189                 std::istreambuf_iterator<char>());
00190 }
00191 
00192 void Shader::get_errors(void)
00193 {
00194         GLenum error = glGetError();
00195 
00196         if (error != GL_NO_ERROR) {
00197                 switch (error) {
00198                 case GL_INVALID_ENUM:
00199                         cerr << "GL: enum argument out of range." << endl;
00200                         break;
00201                 case GL_INVALID_VALUE:
00202                         cerr << "GL: Numeric argument out of range." << endl;
00203                         break;
00204                 case GL_INVALID_OPERATION:
00205                         cerr << "GL: Operation illegal in current state." << endl;
00206                         break;
00207                 //case GL_INVALID_FRAMEBUFFER_OPERATION:
00208                 //      cerr << "GL: Framebuffer object is not complete." << endl;
00209                 //      break;
00210                 case GL_OUT_OF_MEMORY:
00211                         cerr << "GL: Not enough memory left to execute command." << endl;
00212                         break;
00213                 default:
00214                         cerr << "GL: Unknown error." << endl;
00215                 }
00216         }
00217 }
00218 
00219 #define LOG_BUFFER_SIZE 8096
00220 
00221 void Shader::program_log(GLuint program)
00222 {
00223         char logBuffer[LOG_BUFFER_SIZE];
00224         GLsizei length;
00225 
00226         logBuffer[0] = '\0';
00227         glGetProgramInfoLog(program, LOG_BUFFER_SIZE, &length,logBuffer);
00228 
00229         if (length > 0) {
00230                 cout << logBuffer << endl;
00231         }
00232 };
00233 
00234 void Shader::shader_log(GLuint shader)
00235 {
00236         char logBuffer[LOG_BUFFER_SIZE];
00237         GLsizei length;
00238 
00239         logBuffer[0] = '\0';
00240         glGetShaderInfoLog(shader, LOG_BUFFER_SIZE, &length,logBuffer);
00241 
00242         if (length > 0) {
00243                 cout << logBuffer << endl;
00244         }
00245 };
 All Classes Functions Variables Friends