hx3d  1
2D/3D Simple Game Framework
shader.cpp
1 /*
2  Shader.
3  Copyright (C) 2015 Denis BOURGE
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Lesser General Public
7  License as published by the Free Software Foundation; either
8  version 2.1 of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public
16  License along with this library; if not, write to the Free Software
17  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
18  USA
19 */
20 
21 #include "hx3d/graphics/shader.hpp"
22 
23 #include "hx3d/utils/file.hpp"
24 #include "hx3d/utils/log.hpp"
25 
26 #include <glm/gtc/type_ptr.hpp>
27 
28 namespace hx3d {
29 namespace graphics {
30 
31 bool Shader::_programsAnalyzed = false;
32 
33 Shader::Shader(std::string pathToShader):
34  _vertexID(0),
35  _fragmentID(0),
36  _programID(0)
37 {
38  std::string vertexFile = pathToShader + ".vert.glsl";
39  std::string fragmentFile = pathToShader + ".frag.glsl";
40 
41  std::string vertexContent = File::loadAsciiFile(vertexFile)->toString();
42  std::string fragmentContent = File::loadAsciiFile(fragmentFile)->toString();
43 
44  if (vertexContent == "" || fragmentContent == "") {
45  Log.Error("Shader ERROR !");
46  }
47 
48  Log.Info("Loading shader `%s`...", pathToShader.c_str());
49 
50  if (compile(vertexContent, fragmentContent)) {
51  Log.Info("Shader `%s` loaded.", pathToShader.c_str());
52  } else {
53  Log.Error("Shader `%s` has failed.", pathToShader.c_str());
54  }
55 }
56 
57 Shader::Shader(std::string vert, std::string frag):
58  _vertexID(0),
59  _fragmentID(0),
60  _programID(0)
61 {
62  compile(vert, frag);
63 }
64 
65 Shader::~Shader() {
66 
67  if(glIsShader(_vertexID) == GL_TRUE)
68  glDeleteShader(_vertexID);
69 
70  if(glIsShader(_fragmentID) == GL_TRUE)
71  glDeleteShader(_fragmentID);
72 
73  if(glIsProgram(_programID) == GL_TRUE)
74  glDeleteProgram(_programID);
75 }
76 
77 bool Shader::compile(const std::string& vert, const std::string& frag) {
78 
79  if (!compile(_vertexID, GL_VERTEX_SHADER, vert)) {
80  return false;
81  }
82 
83  Log.Shader("\tVertex shader OK");
84 
85  if (!compile(_fragmentID, GL_FRAGMENT_SHADER, frag)) {
86  return false;
87  }
88 
89  Log.Shader("\tFragment shader OK");
90 
91  if (!createProgram())
92  return false;
93 
94  Log.Shader("\tProgram OK");
95 
96  return true;
97 }
98 
99 bool Shader::compile(GLuint &shaderId, GLenum type, const std::string& content) {
100 
101  shaderId = glCreateShader(type);
102  const GLchar* code = content.c_str();
103 
104  glShaderSource(shaderId, 1, &code, 0);
105  glCompileShader(shaderId);
106 
107  GLint error(0);
108  glGetShaderiv(shaderId, GL_COMPILE_STATUS, &error);
109 
110  if (error != GL_TRUE) {
111  GLint error_size(0);
112  glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &error_size);
113 
114  char* error_msg = new char[error_size + 1];
115  glGetShaderInfoLog(shaderId, error_size, &error_size, error_msg);
116  error_msg[error_size] = '\0';
117 
118  Log.Shader(error_msg);
119 
120  delete[] error_msg;
121  glDeleteShader(shaderId);
122 
123  return false;
124  }
125 
126  return true;
127 }
128 
130  _programID = glCreateProgram();
131 
132  glAttachShader(_programID, _vertexID);
133  glAttachShader(_programID, _fragmentID);
134 
135  glLinkProgram(_programID);
136 
137  GLint error(0);
138  glGetProgramiv(_programID, GL_LINK_STATUS, &error);
139 
140  if (error != GL_TRUE) {
141  GLint error_size(0);
142  glGetProgramiv(_programID, GL_INFO_LOG_LENGTH, &error_size);
143 
144  char* error_msg = new char[error_size + 1];
145  glGetShaderInfoLog(_programID, error_size, &error_size, error_msg);
146  error_msg[error_size] = '\0';
147 
148  Log.Shader(error_msg);
149 
150  delete[] error_msg;
151  glDeleteProgram(_programID);
152 
153  return false;
154  }
155 
156  if (_programsAnalyzed) {
157  Log.Shader("Shader analysis");
158  Log.Shader("---------------");
159  }
160 
162  analyzeUniforms();
163 
164  if (_programsAnalyzed) {
165  Log.Shader("---------------");
166  }
167 
168  return true;
169 }
170 
171 GLint Shader::getAttribute(std::string name) {
172  if (_activeAttributes.find(name) != _activeAttributes.end()) {
173  return _activeAttributes[name];
174  } else {
175  Log.Error("Attribute `%s` does not exists", name.c_str());
176  return -1;
177  }
178 }
179 
180 GLint Shader::getUniform(std::string name) {
181  if (_activeUniforms.find(name) != _activeUniforms.end()) {
182  return _activeUniforms[name];
183  } else {
184  Log.Error("Uniform `%s` does not exists", name.c_str());
185  return -1;
186  }
187 }
188 
190  GLint attributesNum(0);
191  GLint attributeMaxSize(0);
192 
193  glGetProgramiv(_programID, GL_ACTIVE_ATTRIBUTES, &attributesNum);
194  glGetProgramiv(_programID, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &attributeMaxSize);
195 
196  if (_programsAnalyzed) {
197  Log.Shader("Attributes: %d", attributesNum);
198  }
199 
200  GLchar* buf = new char[attributeMaxSize + 1];
201 
202  for (GLint i = 0; i < attributesNum; ++i) {
203  GLint size;
204  GLenum type;
205 
206  glGetActiveAttrib(_programID, i, attributeMaxSize, nullptr, &size, &type, buf);
207 
208  if (_programsAnalyzed) {
209  Log.Shader("- %s (%s)", buf, getParameterType(type).c_str());
210  }
211 
212  GLint loc = glGetAttribLocation(_programID, buf);
213  if (loc == -1) {
214  Log.Error("Attribute location error: %s", buf);
215  } else {
216  _activeAttributes[buf] = loc;
217  if (_programsAnalyzed) {
218  Log.Shader("\tBound to %d", loc);
219  }
220  }
221  }
222 
223  delete[] buf;
224 }
225 
227  GLint uniformsNum(0);
228  GLint uniformMaxSize(0);
229 
230  glGetProgramiv(_programID, GL_ACTIVE_UNIFORMS, &uniformsNum);
231  glGetProgramiv(_programID, GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniformMaxSize);
232 
233  if (_programsAnalyzed) {
234  Log.Shader("Uniforms: %d", uniformsNum);
235  }
236 
237  GLchar* buf = new char[uniformMaxSize + 1];
238 
239  for (GLint i = 0; i < uniformsNum; ++i) {
240  GLint size;
241  GLenum type;
242 
243  glGetActiveUniform(_programID, i, uniformMaxSize, nullptr, &size, &type, buf);
244 
245  if (_programsAnalyzed) {
246  Log.Shader("- %s (%s)", buf, getParameterType(type).c_str());
247  }
248 
249  GLint loc = glGetUniformLocation(_programID, buf);
250  if (loc == -1) {
251  Log.Error("Uniform location error: %s", buf);
252  } else {
253  _activeUniforms[buf] = loc;
254 
255  if (_programsAnalyzed) {
256  Log.Shader("\tBound to %d", loc);
257  }
258  }
259  }
260 
261  delete[] buf;
262 }
263 
264 std::string Shader::getParameterType(GLenum type) {
265 
266  switch (type) {
267 
268  case GL_FLOAT:
269  return "float";
270  case GL_FLOAT_VEC2:
271  return "vec2";
272  case GL_FLOAT_VEC3:
273  return "vec3";
274  case GL_FLOAT_VEC4:
275  return "vec4";
276 
277  case GL_INT:
278  return "int";
279  case GL_INT_VEC2:
280  return "ivec2";
281  case GL_INT_VEC3:
282  return "ivec3";
283  case GL_INT_VEC4:
284  return "ivec4";
285 
286  case GL_BOOL:
287  return "bool";
288  case GL_BOOL_VEC2:
289  return "bvec2";
290  case GL_BOOL_VEC3:
291  return "bvec3";
292  case GL_BOOL_VEC4:
293  return "bvec4";
294 
295  case GL_FLOAT_MAT2:
296  return "mat2";
297  case GL_FLOAT_MAT3:
298  return "mat3";
299  case GL_FLOAT_MAT4:
300  return "mat4";
301 
302  case GL_SAMPLER_2D:
303  return "sampler2D";
304  case GL_SAMPLER_CUBE:
305  return "samplerCube";
306 
307  default:
308  return "unknown";
309  }
310 }
311 
312 void Shader::use(Ptr<Shader> shader) {
313  glUseProgram(shader->_programID);
314 }
315 
317  glUseProgram(0);
318 }
319 
320 void Shader::setProgramAnalyzing(bool value) {
321  _programsAnalyzed = value;
322 }
323 
324 
325 GLuint Shader::getProgramID() const {
326  return _programID;
327 }
328 
329 void Shader::setUniform1f(std::string uniform, float value) {
330  int loc = glGetUniformLocation(_programID, uniform.c_str());
331  glUniform1f(loc, value);
332 }
333 
334 void Shader::setUniform2f(std::string uniform, glm::vec2 vector) {
335  int loc = glGetUniformLocation(_programID, uniform.c_str());
336  glUniform2f(loc, vector.x, vector.y);
337 }
338 
339 void Shader::setUniform3f(std::string uniform, glm::vec3 vector) {
340  int loc = glGetUniformLocation(_programID, uniform.c_str());
341  glUniform3f(loc, vector.x, vector.y, vector.z);
342 }
343 
344 void Shader::setUniform4f(std::string uniform, glm::vec4 vector) {
345  int loc = glGetUniformLocation(_programID, uniform.c_str());
346  glUniform4f(loc, vector.x, vector.y, vector.z, vector.w);
347 }
348 
349 void Shader::setUniformMatrix3f(std::string uniform, glm::mat3 matrix) {
350  int loc = glGetUniformLocation(_programID, uniform.c_str());
351  glUniformMatrix3fv(loc, 1, GL_FALSE, glm::value_ptr(matrix));
352 }
353 
354 void Shader::setUniformMatrix4f(std::string uniform, glm::mat4 matrix) {
355  int loc = glGetUniformLocation(_programID, uniform.c_str());
356  glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(matrix));
357 }
358 
359 } /* graphics */
360 } /* hx3d */
GLuint _vertexID
Vertex shader ID.
Definition: shader.hpp:203
void setUniform4f(std::string uniform, glm::vec4 vector)
Send a vec4 to the shader.
Definition: shader.cpp:344
GLuint _programID
Shader program ID.
Definition: shader.hpp:207
void setUniform2f(std::string uniform, glm::vec2 vector)
Send a vec2 to the shader.
Definition: shader.cpp:334
static void use(Ptr< Shader > shader)
Use the shader as the current shader.
Definition: shader.cpp:312
void setUniformMatrix3f(std::string uniform, glm::mat3 matrix)
Send a mat3 to the shader.
Definition: shader.cpp:349
static bool _programsAnalyzed
Are the programs analyzed ?
Definition: shader.hpp:214
std::string getParameterType(GLenum type)
Get the parameter type (debug mode).
Definition: shader.cpp:264
hx3d framework namespace
Definition: audio.hpp:26
static Ptr< File > loadAsciiFile(std::string path)
Load an ascii file from a path.
Definition: file.cpp:52
bool compile(const std::string &vert, const std::string &frag)
Compile the vertex and fragment shaders.
Definition: shader.cpp:77
GLint getUniform(std::string name)
Get the wanted uniform id.
Definition: shader.cpp:180
void setUniform1f(std::string uniform, float value)
Send a single float to the shader.
Definition: shader.cpp:329
GLuint _fragmentID
Fragment shader ID.
Definition: shader.hpp:205
GLuint getProgramID() const
Get the program ID.
Definition: shader.cpp:325
void analyzeAttributes()
Analyze the shader attributes (debug mode).
Definition: shader.cpp:189
void Error(const std::string fmt,...)
Write an error message.
Definition: log.cpp:72
std::map< std::string, GLint > _activeAttributes
Active attributes map.
Definition: shader.hpp:210
void analyzeUniforms()
Analyze the shader uniforms (debug mode).
Definition: shader.cpp:226
static hx3d::LogImpl Log
Current log implementation.
Definition: log.hpp:91
void setUniform3f(std::string uniform, glm::vec3 vector)
Send a vec3 to the shader.
Definition: shader.cpp:339
std::map< std::string, GLint > _activeUniforms
Active uniforms map.
Definition: shader.hpp:212
bool createProgram()
Create the shader program.
Definition: shader.cpp:129
static void disable()
Clear the current shader.
Definition: shader.cpp:316
static void setProgramAnalyzing(bool value)
Analyse the shaders (debug mode).
Definition: shader.cpp:320
Shader(std::string pathToShader)
Create a shader from a path. The path must be without extension, e.g. shaders/test.
Definition: shader.cpp:33
GLint getAttribute(std::string name)
Get the wanted attribute id.
Definition: shader.cpp:171
void setUniformMatrix4f(std::string uniform, glm::mat4 matrix)
Send a mat4 to the shader.
Definition: shader.cpp:354
std::shared_ptr< T > Ptr
Quick-typing shared ptr.
Definition: ptr.hpp:34
void Shader(const std::string fmt,...)
Write a shader message.
Definition: log.cpp:65
void Info(const std::string fmt,...)
Write an info message.
Definition: log.cpp:58