1 /*
2  This Source Code Form is subject to the terms of the Mozilla Public
3  License, v. 2.0. If a copy of the MPL was not distributed with this
4  file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 */
6 
7 #include "shader.h"
8 
9 
10 namespace PatateCommon
11 {
12 
13 
14 static const char* pVSName = "VS";
15 static const char* pTessCSName = "TessCS";
16 static const char* pTessESName = "TessES";
17 static const char* pGSName = "GS";
18 static const char* pFSName = "FS";
19 
ShaderType2ShaderName(GLuint _Type)20 inline const char* ShaderType2ShaderName(GLuint _Type)
21 {
22     switch (_Type)
23     {
24     case GL_VERTEX_SHADER:
25         return pVSName;
26     case GL_TESS_CONTROL_SHADER:
27         return pTessCSName;
28     case GL_TESS_EVALUATION_SHADER:
29         return pTessESName;
30     case GL_GEOMETRY_SHADER:
31         return pGSName;
32     case GL_FRAGMENT_SHADER:
33         return pFSName;
34     default:
35         assert(0);
36     }
37 
38     return NULL;
39 }
40 
Shader()41 Shader::Shader()
42     : m_shaderProg(0), m_status(UNINITIALIZED)
43 {
44 }
45 
46 
~Shader()47 Shader::~Shader()
48 {
49     if(getShaderId())
50     {
51         destroy();
52     }
53 }
54 
55 
create()56 bool Shader::create()
57 {
58     m_shaderProg = glCreateProgram();
59 
60     if (m_shaderProg == 0)
61     {
62         fprintf(stderr, "Error creating shader program\n");
63         return false;
64     }
65 
66     m_status = NOT_COMPILED;
67     return true;
68 }
69 
70 
destroy()71 void Shader::destroy()
72 {
73     PATATE_ASSERT_NO_GL_ERROR();
74 
75     glDeleteProgram(m_shaderProg);
76 
77     if(glGetError() == GL_NO_ERROR)
78         m_shaderProg = 0;
79     m_status = UNINITIALIZED;
80 }
81 
82 
use()83 void Shader::use()
84 {
85     glUseProgram(m_shaderProg);
86 }
87 
88 
setGLSLVersionHeader(const std::string & header)89 void Shader::setGLSLVersionHeader(const std::string& header)
90 {
91     m_versionHeader = header;
92 }
93 
94 
addShader(GLenum _ShaderType,const char * _pShaderText)95 bool Shader::addShader(GLenum _ShaderType, const char* _pShaderText)
96 {
97     PATATE_ASSERT_NO_GL_ERROR();
98 
99     GLuint ShaderObj = glCreateShader(_ShaderType);
100 
101     if (ShaderObj == 0)
102     {
103         fprintf(stderr, "Error creating shader type %d\n", _ShaderType);
104         return false;
105     }
106 
107     m_shaderObjList.push_back(ShaderObj);
108 
109     const GLchar* p[2];
110     p[0] = m_versionHeader.empty()? 0: &m_versionHeader[0];
111     p[1] = _pShaderText;
112     GLint Lengths[2];
113     Lengths[0] = m_versionHeader.size();
114     Lengths[1] = strlen(_pShaderText);
115     glShaderSource(ShaderObj, 2, p, Lengths);
116 
117     glCompileShader(ShaderObj);
118 
119     GLint success;
120     glGetShaderiv(ShaderObj, GL_COMPILE_STATUS, &success);
121 
122     if (!success)
123     {
124         GLchar InfoLog[1024];
125         glGetShaderInfoLog(ShaderObj, 1024, NULL, InfoLog);
126         fprintf(stderr, "Error compiling %s: '%s'\n", ShaderType2ShaderName(_ShaderType), InfoLog);
127         return false;
128     }
129 
130     glAttachShader(m_shaderProg, ShaderObj);
131 
132     return glGetError() == GL_NO_ERROR;
133 }
134 
135 
addShaderFromFile(GLenum _ShaderType,const char * _pFilename)136 bool Shader::addShaderFromFile(GLenum _ShaderType, const char* _pFilename)
137 {
138     FILE* fp;
139     size_t filesize;
140     char* pShaderText;
141 
142     fp = fopen(_pFilename, "rb");
143 
144     if(!fp)
145     {
146         return 0;
147     }
148 
149     fseek(fp, 0, SEEK_END);
150     filesize = ftell(fp);
151     fseek(fp, 0, SEEK_SET);
152 
153     pShaderText = new char[filesize + 1];
154     if(!pShaderText)
155     {
156         return 0;
157     }
158 
159     fread(pShaderText, 1, filesize, fp);
160     pShaderText[filesize] = 0;
161     fclose(fp);
162 
163     bool res = addShader(_ShaderType, pShaderText);
164 
165     delete [] pShaderText;
166 
167     return res;
168 }
169 
170 
clearShaderList()171 void Shader::clearShaderList()
172 {
173     for (ShaderObjList::iterator it = m_shaderObjList.begin() ; it != m_shaderObjList.end() ; it++)
174     {
175         glDetachShader(m_shaderProg, *it);
176         glDeleteShader(*it);
177     }
178     m_shaderObjList.clear();
179 }
180 
181 
finalize()182 bool Shader::finalize()
183 {
184     PATATE_ASSERT_NO_GL_ERROR();
185 
186     GLint Success = 0;
187     GLchar ErrorLog[1024] = { 0 };
188 
189     m_status = COMPILATION_FAILED;
190 
191     glLinkProgram(m_shaderProg);
192 
193     glGetProgramiv(m_shaderProg, GL_LINK_STATUS, &Success);
194     if (Success == 0)
195     {
196         glGetProgramInfoLog(m_shaderProg, sizeof(ErrorLog), NULL, ErrorLog);
197         fprintf(stderr, "Error linking shader program: '%s'\n", ErrorLog);
198         return false;
199     }
200 
201     glValidateProgram(m_shaderProg);
202     glGetProgramiv(m_shaderProg, GL_VALIDATE_STATUS, &Success);
203     if (!Success)
204     {
205         glGetProgramInfoLog(m_shaderProg, sizeof(ErrorLog), NULL, ErrorLog);
206         fprintf(stderr, "Invalid shader program: '%s'\n", ErrorLog);
207         return false;
208     }
209 
210     if(glGetError() == GL_NO_ERROR)
211     {
212         clearShaderList();
213         m_status = COMPILATION_SUCCESSFULL;
214     }
215 
216     return m_status == COMPILATION_SUCCESSFULL;
217 }
218 
219 
bindAttributeLocation(const char * name,unsigned location)220 void Shader::bindAttributeLocation(const char* name, unsigned location)
221 {
222     glBindAttribLocation(m_shaderProg, location, name);
223 }
224 
225 
getUniformLocation(const char * _pUniformName)226 GLint Shader::getUniformLocation(const char* _pUniformName)
227 {
228     GLint location = glGetUniformLocation(m_shaderProg, _pUniformName);
229 
230     if (location < 0)
231     {
232         fprintf(stderr, "Warning! Unable to get the location of uniform '%s'\n", _pUniformName);
233     }
234 
235     return location;
236 }
237 
getProgramParam(GLint _param)238 GLint Shader::getProgramParam(GLint _param)
239 {
240     GLint ret;
241     glGetProgramiv(m_shaderProg, _param, &ret);
242     return ret;
243 }
244 
245 
246 }
247