FlowVis 1.0
|
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 };