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  http://glc-lib.sourceforge.net
00006 
00007  GLC-lib is free software; you can redistribute it and/or modify
00008  it under the terms of the GNU Lesser General Public License as published by
00009  the Free Software Foundation; either version 3 of the License, or
00010  (at your option) any later version.
00011 
00012  GLC-lib is distributed in the hope that it will be useful,
00013  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  GNU Lesser General Public License for more details.
00016 
00017  You should have received a copy of the GNU Lesser General Public License
00018  along with GLC-lib; if not, write to the Free Software
00019  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00020 
00021 *****************************************************************************/
00022 
00024 
00025 #include "glc_shader.h"
00026 #include <QTextStream>
00027 #include <QMutexLocker>
00028 #include "../glc_exception.h"
00029 #include "../glc_state.h"
00030 
00031 // Static member initialization
00032 QStack<GLC_uint> GLC_Shader::m_ShadingGroupStack;
00033 GLuint GLC_Shader::m_CurrentShadingGroupId= 0;
00034 QHash<GLC_uint, GLC_Shader*> GLC_Shader::m_ShaderProgramHash;
00035 
00036 GLC_Shader::GLC_Shader()
00037 : m_VertexShader(QGLShader::Vertex)
00038 , m_FragmentShader(QGLShader::Fragment)
00039 , m_ProgramShader()
00040 , m_ProgramShaderId(glc::GLC_GenShaderGroupID())
00041 , m_Name("Empty Shader")
00042 {
00043         m_ShaderProgramHash.insert(m_ProgramShaderId, this);
00044 }
00045 
00046 GLC_Shader::GLC_Shader(QFile& vertex, QFile& fragment)
00047 : m_VertexShader(QGLShader::Vertex)
00048 , m_FragmentShader(QGLShader::Fragment)
00049 , m_ProgramShader()
00050 , m_ProgramShaderId(glc::GLC_GenShaderGroupID())
00051 , m_Name("Empty Shader")
00052 {
00053         m_ShaderProgramHash.insert(m_ProgramShaderId, this);
00054         setVertexAndFragmentShader(vertex, fragment);
00055 }
00056 
00057 GLC_Shader::GLC_Shader(const GLC_Shader& shader)
00058 : m_VertexShader(QGLShader::Vertex)
00059 , m_FragmentShader(QGLShader::Fragment)
00060 , m_ProgramShader()
00061 , m_ProgramShaderId(glc::GLC_GenShaderGroupID())
00062 , m_Name(shader.m_Name)
00063 {
00064         m_ShaderProgramHash.insert(m_ProgramShaderId, this);
00065 
00066         if (shader.m_VertexShader.isCompiled())
00067         {
00068                 m_VertexShader.compileSourceCode(shader.m_VertexShader.sourceCode());
00069         }
00070         if (shader.m_FragmentShader.isCompiled())
00071         {
00072                 m_FragmentShader.compileSourceCode(shader.m_FragmentShader.sourceCode());
00073         }
00074 
00075         createAndCompileProgrammShader();
00076 }
00077 
00078 GLC_Shader::~GLC_Shader()
00079 {
00080         deleteShader();
00081 }
00082 
00084 // Get Functions
00086 
00087 bool GLC_Shader::canBeDeleted() const
00088 {
00089         return m_CurrentShadingGroupId != m_ProgramShaderId;
00090 }
00091 
00092 int GLC_Shader::shaderCount()
00093 {
00094         return m_ShaderProgramHash.size();
00095 }
00096 
00097 bool GLC_Shader::asShader(GLC_uint shadingGroupId)
00098 {
00099         return m_ShaderProgramHash.contains(shadingGroupId);
00100 }
00101 
00102 GLC_Shader* GLC_Shader::shaderHandle(GLC_uint shadingGroupId)
00103 {
00104         return m_ShaderProgramHash.value(shadingGroupId);
00105 }
00106 
00107 bool GLC_Shader::hasActiveShader()
00108 {
00109         return 0 != m_CurrentShadingGroupId;
00110 }
00111 
00112 GLC_Shader* GLC_Shader::currentShaderHandle()
00113 {
00114         return m_ShaderProgramHash.value(m_CurrentShadingGroupId);
00115 }
00116 
00118 // OpenGL Functions
00120 
00121 void GLC_Shader::use()
00122 {
00123         if (GLC_State::isInSelectionMode()) return;
00124         // Program shader must be valid
00125         Q_ASSERT(m_ProgramShader.isLinked());
00126 
00127         m_ShadingGroupStack.push(m_ProgramShaderId);
00128         // Test if the program shader is not already the current one
00129         if (m_CurrentShadingGroupId != m_ProgramShaderId)
00130         {
00131                 m_CurrentShadingGroupId= m_ProgramShaderId;
00132                 m_ShaderProgramHash.value(m_CurrentShadingGroupId)->m_ProgramShader.bind();
00133         }
00134 
00135 }
00136 
00137 bool GLC_Shader::use(GLuint shaderId)
00138 {
00139         Q_ASSERT(0 != shaderId);
00140         if (GLC_State::isInSelectionMode()) return false;
00141 
00142         if (m_ShaderProgramHash.contains(shaderId))
00143         {
00144                 m_ShadingGroupStack.push(shaderId);
00145                 // Test if the program shader is not already the current one
00146                 if (m_CurrentShadingGroupId != shaderId)
00147                 {
00148                         m_CurrentShadingGroupId= shaderId;
00149                         m_ShaderProgramHash.value(m_CurrentShadingGroupId)->m_ProgramShader.bind();
00150                 }
00151                 return true;
00152         }
00153         else
00154         {
00155                 return false;
00156         }
00157 }
00158 
00159 void GLC_Shader::unuse()
00160 {
00161 
00162         if (GLC_State::isInSelectionMode()) return;
00163 
00164         Q_ASSERT(!m_ShadingGroupStack.isEmpty());
00165 
00166         const GLC_uint stackShadingGroupId= m_ShadingGroupStack.pop();
00167         if (m_ShadingGroupStack.isEmpty())
00168         {
00169                 m_CurrentShadingGroupId= 0;
00170                 m_ShaderProgramHash.value(stackShadingGroupId)->m_ProgramShader.release();
00171         }
00172         else
00173         {
00174                 m_CurrentShadingGroupId= m_ShadingGroupStack.top();
00175                 m_ShaderProgramHash.value(m_CurrentShadingGroupId)->m_ProgramShader.bind();
00176         }
00177 }
00178 
00179 void GLC_Shader::createAndCompileProgrammShader()
00180 {
00181         m_ProgramShader.addShader(&m_VertexShader);
00182         m_ProgramShader.addShader(&m_FragmentShader);
00183 
00184         if (!m_ProgramShader.link())
00185         {
00186                 QString message("GLC_Shader::setVertexAndFragmentShader Failed to link program ");
00187                 GLC_Exception exception(message);
00188                 throw(exception);
00189         }
00190 }
00191 
00192 void GLC_Shader::deleteShader()
00193 {
00194         if (m_ProgramShaderId != 0)
00195         {
00196                 // Test if the shader is the current one
00197                 if (m_CurrentShadingGroupId == m_ProgramShaderId)
00198                 {
00199                         qDebug() << "Warning deleting current shader";
00200                 }
00201                 //removing shader id from the stack
00202                 if (m_ShadingGroupStack.contains(m_ProgramShaderId))
00203                 {
00204                         int indexToDelete= m_ShadingGroupStack.indexOf(m_ProgramShaderId);
00205                         while (indexToDelete != -1)
00206                         {
00207                                 m_ShadingGroupStack.remove(indexToDelete);
00208                                 indexToDelete= m_ShadingGroupStack.indexOf(m_ProgramShaderId);
00209                         }
00210                 }
00211                 m_ShaderProgramHash.remove(m_ProgramShaderId);
00212         }
00213 
00214 }
00215 
00217 // Set Functions
00219 
00220 
00221 void GLC_Shader::setVertexAndFragmentShader(QFile& vertexFile, QFile& fragmentFile)
00222 {
00223         m_Name= QFileInfo(vertexFile).baseName();
00224         vertexFile.open(QIODevice::ReadOnly);
00225         m_VertexShader.compileSourceCode(vertexFile.readAll());
00226         vertexFile.close();
00227 
00228         fragmentFile.open(QIODevice::ReadOnly);
00229         m_FragmentShader.compileSourceCode(fragmentFile.readAll());
00230         fragmentFile.close();
00231 }
00232 
00233 
00234 void GLC_Shader::replaceShader(const GLC_Shader& sourceShader)
00235 {
00236         Q_ASSERT(isUsable() == sourceShader.isUsable());
00237 
00238         // Test if the source shader is the same than this shader
00239         if (this == &sourceShader)
00240         {
00241                 return;
00242         }
00243         m_ProgramShader.removeAllShaders();
00244 
00245         if (sourceShader.m_VertexShader.isCompiled())
00246         {
00247                 m_VertexShader.compileSourceCode(sourceShader.m_VertexShader.sourceCode());
00248         }
00249         if (sourceShader.m_FragmentShader.isCompiled())
00250         {
00251                 m_FragmentShader.compileSourceCode(sourceShader.m_FragmentShader.sourceCode());
00252         }
00253 
00254         m_ProgramShader.link();
00255 
00256 }
00257 

SourceForge.net Logo

©2005-2011 Laurent Ribon