GLSLShader.cpp

Go to the documentation of this file.
00001 /******************************************************************************
00002 *       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 3      *
00003 *                (c) 2006-2008 MGH, INRIA, USTL, UJF, CNRS                    *
00004 *                                                                             *
00005 * This library is free software; you can redistribute it and/or modify it     *
00006 * under the terms of the GNU Lesser General Public License as published by    *
00007 * the Free Software Foundation; either version 2.1 of the License, or (at     *
00008 * your option) any later version.                                             *
00009 *                                                                             *
00010 * This library is distributed in the hope that it will be useful, but WITHOUT *
00011 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
00012 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
00013 * for more details.                                                           *
00014 *                                                                             *
00015 * You should have received a copy of the GNU Lesser General Public License    *
00016 * along with this library; if not, write to the Free Software Foundation,     *
00017 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
00018 *******************************************************************************
00019 *                              SOFA :: Framework                              *
00020 *                                                                             *
00021 * Authors: M. Adam, J. Allard, B. Andre, P-J. Bensoussan, S. Cotin, C. Duriez,*
00022 * H. Delingette, F. Falipou, F. Faure, S. Fonteneau, L. Heigeas, C. Mendoza,  *
00023 * M. Nesme, P. Neumann, J-P. de la Plata Alcade, F. Poyer and F. Roy          *
00024 *                                                                             *
00025 * Contact information: contact@sofa-framework.org                             *
00026 ******************************************************************************/
00027 #include <sofa/helper/gl/GLSLShader.h>
00028 #include <stdlib.h>
00029 #include <math.h>
00030 #include <fstream>
00031 #include <iostream>
00032 
00033 namespace sofa
00034 {
00035 
00036 namespace helper
00037 {
00038 
00039 namespace gl
00040 {
00041 
00042 bool GLSLShader::InitGLSL()
00043 {
00044     GLenum err = glewInit();
00045     if (GLEW_OK != err)
00046     {
00047         /* Problem: glewInit failed, something is seriously wrong. */
00048         fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
00049         return false;
00050     }
00051 //     fprintf(stdout, "GLSLShader: Using GLEW %s\n", glewGetString(GLEW_VERSION));
00052     
00053     // Make sure find the GL_ARB_shader_objects extension so we can use shaders.
00054     if(!GLEW_ARB_shader_objects)
00055     {
00056         fprintf(stderr, "Error: GL_ARB_shader_objects extension not supported!\n");
00057         return false;
00058     }
00059     
00060     // Make sure we support the GLSL shading language 1.0
00061     if(!GLEW_ARB_shading_language_100)
00062     {
00063         fprintf(stderr, "Error: GL_ARB_shading_language_100 extension not supported!\n");
00064         return false;
00065     }
00066     // Return a success!
00067     return true;
00068 }
00069 
00070 GLSLShader::GLSLShader()
00071 {
00072     m_hVertexShader = 0; //NULL;
00073     m_hGeometryShader = 0; //NULL;
00074     m_hFragmentShader = 0; //NULL;
00075     m_hProgramObject = 0; //NULL;
00076     geometry_input_type = -1;
00077     geometry_output_type = -1;
00078     geometry_vertices_out = -1;
00079     header = "";
00080 }
00081 
00082 GLSLShader::~GLSLShader()
00083 {
00084     // BUGFIX: if the GL context is gone, this can crash the application on exit -- Jeremie A.
00085     //Release();
00086 }
00087 
00088 void GLSLShader::AddHeader(const std::string &header)
00089 {
00090     this->header += header;
00091     this->header += "\n";
00092 }
00093 
00094 void GLSLShader::AddDefineMacro(const std::string &name, const std::string &value)
00095 {
00096     AddHeader("#define " + name + " " + value);
00097 }
00098 
00100 std::string GLSLShader::LoadTextFile(const std::string& strFile)
00101 {
00102     // Open the file passed in
00103     std::ifstream fin(strFile.c_str());
00104 
00105     // Make sure we opened the file correctly
00106     if(!fin)
00107         return "";
00108 
00109     std::string strLine = "";
00110     std::string strText = "";
00111 
00112     // Go through and store each line in the text file within a "string" object
00113     while(std::getline(fin, strLine))
00114     {
00115         strText = strText + "\n" + strLine;
00116     }
00117 
00118     // Close our file
00119     fin.close();
00120 
00121     // Return the text file's data
00122     return strText;
00123 }
00124 
00126 bool GLSLShader::CompileShader(GLint target, const std::string& source, GLhandleARB& shader)
00127 {
00128     const char* stype = "";
00129     if (target == GL_VERTEX_SHADER_ARB) stype = "vertex";
00130     else if (target == GL_FRAGMENT_SHADER_ARB) stype = "fragment";
00131 #ifdef GL_GEOMETRY_SHADER_EXT
00132     else if (target == GL_GEOMETRY_SHADER_EXT) stype = "geometry";
00133 #endif
00134 
00135     shader = glCreateShaderObjectARB(target);
00136 
00137     const char* src = source.c_str();
00138     
00139     glShaderSourceARB(shader, 1, &src, NULL);
00140     
00141     glCompileShaderARB(shader);
00142 
00143     GLint compiled = 0, length = 0, laux = 0;
00144     glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &compiled);
00145     if (!compiled) std::cerr << "ERROR: Compilation of "<<stype<<" shader failed:\n"<<src<<std::endl;
00146 //     else std::cout << "Compilation of "<<stype<<" shader OK" << std::endl;
00147     glGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
00148     if (length)
00149     {
00150         GLcharARB *logString = (GLcharARB *)malloc((length+1) * sizeof(GLcharARB));
00151         glGetInfoLogARB(shader, length, &laux, logString);
00152         std::cerr << logString << std::endl;
00153         free(logString);
00154     }
00155     return (compiled!=0);
00156 }
00157 
00159 void GLSLShader::InitShaders(const std::string& strVertex, const std::string& strGeometry, const std::string& strFragment)
00160 {
00161     // Make sure the user passed in at least a vertex and fragment shader file
00162     if(!strVertex.length() || !strFragment.length())
00163     return;
00164 
00165     // If any of our shader pointers are set, let's free them first.
00166     if(m_hVertexShader || m_hGeometryShader || m_hFragmentShader || m_hProgramObject)
00167     Release();
00168 
00169     bool ready = true;
00170     
00171     // Now we load and compile the shaders from their respective files
00172     ready &= CompileShader( GL_VERTEX_SHADER_ARB, header + LoadTextFile(strVertex), m_hVertexShader );
00173     if (!strGeometry.empty())
00174     {
00175 #ifdef GL_GEOMETRY_SHADER_EXT
00176     ready &= CompileShader( GL_GEOMETRY_SHADER_EXT, LoadTextFile(strGeometry), m_hGeometryShader );
00177 #else
00178     std::cerr << "SHADER ERROR: GL_GEOMETRY_SHADER_EXT not defined. Please use a recent version of GLEW.\n";
00179     ready = false;
00180 #endif
00181     }
00182     ready &= CompileShader( GL_FRAGMENT_SHADER_ARB, header + LoadTextFile(strFragment), m_hFragmentShader );
00183 
00184     if (!ready)
00185     {
00186     std::cerr << "SHADER compilation failed.\n";
00187     return;
00188     }
00189 
00190     // Next we create a program object to represent our shaders
00191     m_hProgramObject = glCreateProgramObjectARB();
00192 
00193     // We attach each shader we just loaded to our program object
00194     glAttachObjectARB(m_hProgramObject, m_hVertexShader);
00195 #ifdef GL_GEOMETRY_SHADER_EXT
00196     if (m_hGeometryShader)
00197     glAttachObjectARB(m_hProgramObject, m_hGeometryShader);
00198 #endif
00199     glAttachObjectARB(m_hProgramObject, m_hFragmentShader);
00200 
00201 #ifdef GL_GEOMETRY_SHADER_EXT
00202     if (m_hGeometryShader)
00203     {
00204         if (geometry_input_type != -1) glProgramParameteriEXT(m_hProgramObject, GL_GEOMETRY_INPUT_TYPE_EXT, geometry_input_type );
00205         if (geometry_output_type != -1) glProgramParameteriEXT(m_hProgramObject, GL_GEOMETRY_OUTPUT_TYPE_EXT, geometry_output_type );
00206         if (geometry_vertices_out != -1) glProgramParameteriEXT(m_hProgramObject, GL_GEOMETRY_VERTICES_OUT_EXT, geometry_vertices_out );
00207     }
00208 #endif
00209     // Our last init function is to link our program object with OpenGL
00210     glLinkProgramARB(m_hProgramObject);
00211 
00212     GLint linked = 0, length = 0, laux = 0;
00213     glGetObjectParameterivARB(m_hProgramObject, GL_OBJECT_LINK_STATUS_ARB, &linked);
00214     if (!linked) std::cerr << "ERROR: Link of program shader failed:\n"<<std::endl;
00215 //     else std::cout << "Link of program shader OK" << std::endl;
00216     glGetObjectParameterivARB(m_hProgramObject, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
00217     if (length)
00218     {
00219         GLcharARB *logString = (GLcharARB *)malloc((length+1) * sizeof(GLcharARB));
00220         glGetInfoLogARB(m_hProgramObject, length, &laux, logString);
00221         std::cerr << logString << std::endl;
00222         free(logString);
00223     }
00224     
00225     // Now, let's turn off the shader initially.
00226     glUseProgramObjectARB(0);
00227 }
00228 
00229 
00230 void GLSLShader::SetInt(GLint variable, int newValue)                              { if (variable!=-1) glUniform1iARB(variable, newValue);       }
00231 void GLSLShader::SetInt2(GLint variable, int i1, int i2)                           { if (variable!=-1) glUniform2iARB(variable, i1, i2);         }
00232 void GLSLShader::SetInt3(GLint variable, int i1, int i2, int i3)                   { if (variable!=-1) glUniform3iARB(variable, i1, i2, i3);     }
00233 void GLSLShader::SetInt4(GLint variable, int i1, int i2, int i3, int i4)           { if (variable!=-1) glUniform4iARB(variable, i1, i2, i3, i4); }
00234 void GLSLShader::SetFloat(GLint variable, float newValue)                          { if (variable!=-1) glUniform1fARB(variable, newValue);       }
00235 void GLSLShader::SetFloat2(GLint variable, float v0, float v1)                     { if (variable!=-1) glUniform2fARB(variable, v0, v1);         }
00236 void GLSLShader::SetFloat3(GLint variable, float v0, float v1, float v2)           { if (variable!=-1) glUniform3fARB(variable, v0, v1, v2);     }
00237 void GLSLShader::SetFloat4(GLint variable, float v0, float v1, float v2, float v3) { if (variable!=-1) glUniform4fARB(variable, v0, v1, v2, v3); }
00238 
00239 void GLSLShader::SetIntVector(GLint variable, GLsizei count, const GLint *value)     { if (variable!=-1) glUniform1ivARB(variable, count, value);   }
00240 void GLSLShader::SetIntVector2(GLint variable, GLsizei count, const GLint *value)    { if (variable!=-1) glUniform2ivARB(variable, count, value);   }
00241 void GLSLShader::SetIntVector3(GLint variable, GLsizei count, const GLint *value)    { if (variable!=-1) glUniform3ivARB(variable, count, value);   }
00242 void GLSLShader::SetIntVector4(GLint variable, GLsizei count, const GLint *value)    { if (variable!=-1) glUniform4ivARB(variable, count, value);   }
00243 
00244 void GLSLShader::SetFloatVector(GLint variable, GLsizei count, const float *value) { if (variable!=-1) glUniform1fvARB(variable, count, value);   }
00245 void GLSLShader::SetFloatVector2(GLint variable, GLsizei count, const float *value){ if (variable!=-1) glUniform2fvARB(variable, count, value);   }
00246 void GLSLShader::SetFloatVector3(GLint variable, GLsizei count, const float *value){ if (variable!=-1) glUniform3fvARB(variable, count, value);   }
00247 void GLSLShader::SetFloatVector4(GLint variable, GLsizei count, const float *value){ if (variable!=-1) glUniform4fvARB(variable, count, value);   }
00248 
00249 
00250 // These 2 functions turn on and off our shader
00251 void GLSLShader::TurnOn()   { if (m_hProgramObject) glUseProgramObjectARB(m_hProgramObject); }
00252 void GLSLShader::TurnOff()  { if (m_hProgramObject) glUseProgramObjectARB(0);                }
00253 
00255 GLint GLSLShader::GetVariable(std::string strVariable)
00256 {
00257     // If we don't have an active program object, let's return -1
00258     if(!m_hProgramObject)
00259         return -1;
00260 
00261     // This returns the variable ID for a variable that is used to find
00262     // the address of that variable in memory.
00263     return glGetUniformLocationARB(m_hProgramObject, strVariable.c_str());
00264 }
00265 
00266 
00268 void GLSLShader::Release()
00269 {
00270     // If our vertex shader pointer is valid, free it
00271     if(m_hVertexShader)
00272     {
00273         glDetachObjectARB(m_hProgramObject, m_hVertexShader);
00274         glDeleteObjectARB(m_hVertexShader);
00275         m_hVertexShader = 0; //NULL;
00276     }
00277 
00278     // If our geometry shader pointer is valid, free it
00279     if(m_hGeometryShader)
00280     {
00281         glDetachObjectARB(m_hProgramObject, m_hGeometryShader);
00282         glDeleteObjectARB(m_hGeometryShader);
00283         m_hGeometryShader = 0; //NULL;
00284     }
00285 
00286     // If our fragment shader pointer is valid, free it
00287     if(m_hFragmentShader)
00288     {
00289         glDetachObjectARB(m_hProgramObject, m_hFragmentShader);
00290         glDeleteObjectARB(m_hFragmentShader);
00291         m_hFragmentShader = 0; //NULL;
00292     }
00293 
00294     // If our program object pointer is valid, free it
00295     if(m_hProgramObject)
00296     {
00297         glDeleteObjectARB(m_hProgramObject);
00298         m_hProgramObject = 0; //NULL;
00299     }
00300 }
00301 
00302 } // namespace gl
00303 
00304 } // namespace helper
00305 
00306 } // namespace sofa

Generated on Sun Nov 23 02:29:29 2008 for Sofa by  doxygen 1.5.7.1