glc_shader.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 
00003  This file is part of the GLC-lib library.
00004  Copyright (C) 2005-2008 Laurent Ribon (laumaya@users.sourceforge.net)
00005  Version 2.0.0 Beta 1, packaged on April 2010.
00006 
00007  http://glc-lib.sourceforge.net
00008 
00009  GLC-lib is free software; you can redistribute it and/or modify
00010  it under the terms of the GNU General Public License as published by
00011  the Free Software Foundation; either version 2 of the License, or
00012  (at your option) any later version.
00013 
00014  GLC-lib is distributed in the hope that it will be useful,
00015  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  GNU General Public License for more details.
00018 
00019  You should have received a copy of the GNU General Public License
00020  along with GLC-lib; if not, write to the Free Software
00021  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00022 
00023 *****************************************************************************/
00024 
00026 
00027 #include "glc_shader.h"
00028 #include <QTextStream>
00029 #include <QMutexLocker>
00030 #include "../glc_exception.h"
00031 #include "../glc_state.h"
00032 
00033 // Static member initialization
00034 QStack<GLuint> GLC_Shader::m_ProgrammStack;
00035 
00036 GLuint GLC_Shader::m_CurrentProgramm= 0;
00037 
00038 QMutex GLC_Shader::m_Mutex;
00039 
00040 
00041 GLC_Shader::GLC_Shader()
00042 : m_VertexByteArray()
00043 , m_VertexShader(0)
00044 , m_FragmentByteArray()
00045 , m_FragmentShader(0)
00046 , m_ProgramShader(0)
00047 , m_Name("Empty Shader")
00048 {
00049         qDebug() << "Create Shader";
00050 }
00051 
00052 // Construct shader with specifie vertex and fragment
00053 GLC_Shader::GLC_Shader(QFile& vertex, QFile& fragment)
00054 : m_VertexByteArray()
00055 , m_VertexShader(0)
00056 , m_FragmentByteArray()
00057 , m_FragmentShader(0)
00058 , m_ProgramShader(0)
00059 , m_Name()
00060 {
00061         qDebug() << "Create Shader";
00062         setVertexAndFragmentShader(vertex, fragment);
00063 }
00064 
00065 // Copy constructor
00066 GLC_Shader::GLC_Shader(const GLC_Shader& shader)
00067 : m_VertexByteArray(shader.m_VertexByteArray)
00068 , m_VertexShader(0)
00069 , m_FragmentByteArray(shader.m_FragmentByteArray)
00070 , m_FragmentShader(0)
00071 , m_ProgramShader(0)
00072 , m_Name(shader.m_Name)
00073 {
00074         qDebug() << "Create Shader";
00075         if (0 != shader.m_ProgramShader)
00076         {
00077                 createAndCompileProgrammShader();
00078         }
00079 }
00080 
00081 GLC_Shader::~GLC_Shader()
00082 {
00083         qDebug() << "GLC_Shader::~GLC_Shader";
00084         deleteShader();
00085 }
00086 
00088 // Get Functions
00090 
00091 // Return true if the shader can be deleted
00092 bool GLC_Shader::canBeDeleted() const
00093 {
00094         return m_CurrentProgramm != m_ProgramShader;
00095 }
00096 
00098 // OpenGL Functions
00100 
00101 // Use this shader programm
00102 void GLC_Shader::use()
00103 {
00104         if (GLC_State::isInSelectionMode()) return;
00105         // Program shader must be valid
00106         Q_ASSERT(0 != m_ProgramShader);
00107         // Test if it is a valid program shader
00108         if (glIsProgram(m_ProgramShader) != GL_TRUE)
00109         {
00110                 QString message("GLC_Shader::use() m_ProgramShader is not a valid program shader ");
00111                 GLC_Exception exception(message);
00112                 throw(exception);
00113         }
00114 
00115         QMutexLocker locker(&m_Mutex);
00116         // Test if the program shader is not already the current one
00117         if (m_CurrentProgramm != m_ProgramShader)
00118         {
00119                 if (m_CurrentProgramm != 0)
00120                 {
00121                         m_ProgrammStack.push(m_CurrentProgramm);
00122                 }
00123                 m_CurrentProgramm= m_ProgramShader;
00124                 glUseProgram(m_CurrentProgramm);
00125         }
00126 
00127 }
00128 
00129 // Use specified program shader
00130 void GLC_Shader::use(GLuint shaderId)
00131 {
00132         if (GLC_State::isInSelectionMode()) return;
00133         //qDebug() << "GLC_Shader::use(GLuint shaderId)";
00134         // Test if the program shader is not already the current one
00135         if (m_CurrentProgramm != shaderId)
00136         {
00137                 if (m_CurrentProgramm != 0)
00138                 {
00139                         m_ProgrammStack.push(shaderId);
00140                 }
00141                 m_CurrentProgramm= shaderId;
00142                 glUseProgram(m_CurrentProgramm);
00143         }
00144         else if (glIsProgram(shaderId) != GL_TRUE)      // Test if it is a valid program shader
00145         {
00146                 QString message("GLC_Shader::use(GLuint id) id is not a valid program shader ");
00147                 GLC_Exception exception(message);
00148                 throw(exception);
00149         }
00150 
00151 }
00152 
00153 
00154 // Use previous program shader
00155 void GLC_Shader::unuse()
00156 {
00157         if (GLC_State::isInSelectionMode()) return;
00158 
00159         QMutexLocker locker(&m_Mutex);
00160         if (m_ProgrammStack.isEmpty())
00161         {
00162                 m_CurrentProgramm= 0;
00163         }
00164         else
00165         {
00166                 m_CurrentProgramm= m_ProgrammStack.pop();
00167         }
00168         glUseProgram(m_CurrentProgramm);
00169 }
00170 // Compile and attach shader to a program shader
00171 void GLC_Shader::createAndCompileProgrammShader()
00172 {
00173         Q_ASSERT(0 == m_ProgramShader);
00174 
00175         createAndLinkVertexShader();
00176         createAndLinkFragmentShader();
00177 
00178         m_ProgramShader = glCreateProgram();
00179         glAttachShader(m_ProgramShader, m_VertexShader);
00180         glAttachShader(m_ProgramShader, m_FragmentShader);
00181 
00182         glLinkProgram(m_ProgramShader);
00183 
00184         // Check if the program as been linked successfully
00185         GLint params;
00186         glGetProgramiv(m_ProgramShader, GL_LINK_STATUS, &params);
00187         if (params != GL_TRUE)
00188         {
00189                 QString message("GLC_Shader::setVertexAndFragmentShader Failed to link program ");
00190                 GLC_Exception exception(message);
00191                 throw(exception);
00192         }
00193 }
00194 
00195 // Create and compile vertex shader
00196 void GLC_Shader::createAndLinkVertexShader()
00197 {
00198         const char* pVertexShaderData= m_VertexByteArray.data();
00199 
00200         m_VertexShader = glCreateShader(GL_VERTEX_SHADER);
00201         glShaderSource(m_VertexShader, 1, &pVertexShaderData, NULL);
00202         glCompileShader(m_VertexShader);
00203 
00204         // Check if the shader compilation is successful
00205         GLint params;
00206         glGetShaderiv(m_VertexShader, GL_COMPILE_STATUS, &params);
00207         if (params != GL_TRUE)
00208         {
00209                 QString message("GLC_Shader::createAndLinkVertexShader Failed to compile Vertex shader");
00210                 GLC_Exception exception(message);
00211                 throw(exception);
00212         }
00213 }
00214 //Delete the shader
00215 void GLC_Shader::deleteShader()
00216 {
00217         qDebug() << "delete Shader";
00218         if (m_ProgramShader != 0)
00219         {
00220                 // Test if the shader is the current one
00221                 if (m_CurrentProgramm == m_ProgramShader)
00222                 {
00223                         qDebug() << "Warning deleting current shader";
00224                 }
00225                 //removing shader id from the stack
00226                 if (m_ProgrammStack.contains(m_ProgramShader))
00227                 {
00228                         int indexToDelete= m_ProgrammStack.indexOf(m_ProgramShader);
00229                         while (indexToDelete != -1)
00230                         {
00231                                 m_ProgrammStack.remove(indexToDelete);
00232                                 indexToDelete= m_ProgrammStack.indexOf(m_ProgramShader);
00233                         }
00234                 }
00235                         // Detach shader associated with the program
00236                 glDetachShader(m_ProgramShader, m_VertexShader);
00237                 glDetachShader(m_ProgramShader, m_FragmentShader);
00238                 // Delete the shader
00239                 glDeleteShader(m_VertexShader);
00240                 m_VertexShader= 0;
00241                 glDeleteShader(m_FragmentShader);
00242                 m_FragmentShader= 0;
00243                 // Delete the program
00244                 glDeleteProgram(m_ProgramShader);
00245                 m_ProgramShader= 0;
00246         }
00247 
00248 }
00249 
00250 // Create and compile fragment shader
00251 void GLC_Shader::createAndLinkFragmentShader()
00252 {
00253         const char* pFragmentShaderData= m_FragmentByteArray.data();
00254 
00255         m_FragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
00256         glShaderSource(m_FragmentShader, 1, &pFragmentShaderData, NULL);
00257         glCompileShader(m_FragmentShader);
00258 
00259         // Check if the shader compilation is successful
00260         GLint params;
00261         glGetShaderiv(m_FragmentShader, GL_COMPILE_STATUS, &params);
00262         if (params != GL_TRUE)
00263         {
00264                 QString message("GLC_Shader::createAndLinkFragmentShader Failed to compile fragment shader");
00265                 GLC_Exception exception(message);
00266                 throw(exception);
00267         }
00268 }
00269 
00271 // Set Functions
00273 
00274 // Set Vertex and fragment shader
00275 void GLC_Shader::setVertexAndFragmentShader(QFile& vertexFile, QFile& fragmentFile)
00276 {
00277         m_Name= QFileInfo(vertexFile).baseName();
00278         setVertexShader(vertexFile);
00279         setFragmentShader(fragmentFile);
00280 }
00281 
00282 // Replace this shader by a copy of another shader
00283 void GLC_Shader::replaceShader(const GLC_Shader& sourceShader)
00284 {
00285         Q_ASSERT(isUsable() == sourceShader.isUsable());
00286 
00287         // Test if the source shader is the same than this shader
00288         if (this == &sourceShader)
00289         {
00290                 return;
00291         }
00292         m_VertexByteArray= sourceShader.m_VertexByteArray;
00293         m_FragmentByteArray= sourceShader.m_FragmentByteArray;
00294 
00295         if (isUsable())
00296         {
00297                 const GLuint oldShaderId= m_ProgramShader;
00298 
00299                 // Detach shader associated with the program
00300                 glDetachShader(m_ProgramShader, m_VertexShader);
00301                 glDetachShader(m_ProgramShader, m_FragmentShader);
00302                 // Delete the shader
00303                 glDeleteShader(m_VertexShader);
00304                 glDeleteShader(m_FragmentShader);
00305                 // Delete the program
00306                 glDeleteProgram(m_ProgramShader);
00307 
00308                 // Init shader ID
00309                 m_ProgramShader= 0;
00310                 m_VertexShader= 0;
00311                 m_FragmentShader= 0;
00312 
00313                 // Rebuilt shader
00314                 createAndCompileProgrammShader();
00315 
00316                 // Update the shader program stack
00317                 if (m_ProgrammStack.contains(oldShaderId))
00318                 {
00319                         int indexToReplace= m_ProgrammStack.indexOf(oldShaderId);
00320                         while (indexToReplace != -1)
00321                         {
00322                                 m_ProgrammStack.replace(indexToReplace, m_ProgramShader);
00323                                 indexToReplace= m_ProgrammStack.indexOf(oldShaderId);
00324                         }
00325                 }
00326                 // Check the value of current shader
00327                 if (oldShaderId == m_CurrentProgramm)
00328                 {
00329                         m_CurrentProgramm= m_ProgramShader;
00330                         // Use the new One
00331                         glUseProgram(m_CurrentProgramm);
00332                 }
00333         }
00334 }
00335 
00337 // Private services Functions
00339 // Set Vertex shader
00340 void GLC_Shader::setVertexShader(QFile& vertexFile)
00341 {
00342         Q_ASSERT(0 == m_ProgramShader);
00343         m_VertexByteArray= readShaderFile(vertexFile);
00344 }
00345 
00346 // Set fragment shader
00347 void GLC_Shader::setFragmentShader(QFile& fragmentFile)
00348 {
00349         Q_ASSERT(0 == m_ProgramShader);
00350         m_FragmentByteArray= readShaderFile(fragmentFile);
00351 }
00352 
00353 // Return char* of an Ascii file
00354 QByteArray GLC_Shader::readShaderFile(QFile& shaderFile)
00355 {
00356         if (!shaderFile.open(QIODevice::ReadOnly))
00357         {
00358                 QString message(QString("GLC_Shader::readShaderFile Failed to open file : ") + shaderFile.fileName());
00359                 GLC_Exception exception(message);
00360                 throw(exception);
00361         }
00362         QByteArray result(shaderFile.readAll());
00363         result.append('\0');
00364         return result;
00365 }
00366 

SourceForge.net Logo

©2005 Laurent Ribon