Symphony Of Empires
shader.cpp
Go to the documentation of this file.
1 // Eng3D - General purpouse game engine
2 // Copyright (C) 2021, Eng3D contributors
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <https://www.gnu.org/licenses/>.
16 //
17 // ----------------------------------------------------------------------------
18 // Name:
19 // shader.cpp
20 //
21 // Abstract:
22 // Does some important stuff.
23 // ----------------------------------------------------------------------------
24 
25 #include <fstream>
26 #include <iostream>
27 #include <sstream>
28 #include <cassert>
29 
30 #ifdef E3D_BACKEND_OPENGL
31 # include <GL/glew.h>
32 # include <GL/gl.h>
33 #elif defined E3D_BACKEND_GLES
34 # include <GLES3/gl3.h>
35 # include <GLES3/gl31.h>
36 #endif
37 
38 #include "eng3d/shader.hpp"
39 #include "eng3d/glsl_trans.hpp"
40 #include "eng3d/utils.hpp"
41 #include "eng3d/log.hpp"
42 
43 #if defined E3D_BACKEND_OPENGL || defined E3D_BACKEND_GLES
46 Eng3D::OpenGL::Shader::Shader(const std::string& _buffer, GLuint type, bool use_transpiler, std::vector<Eng3D::GLSL::Define> defintions)
47  : buffer(_buffer)
48 {
49  if(use_transpiler) try {
50  Eng3D::GLSL::Context ctx(buffer);
51  ctx.defines = defintions;
52  ctx.lexer();
53  ctx.parser();
54  buffer = ctx.to_text();
55  line_numbers = ctx.line_numbers;
56  } catch(Eng3D::GLSL::Exception& e) {
57  Eng3D::Log::error("shder", e.it->data + " -> " + e.what());
58  }
59 
60  id = glCreateShader(type);
61  if(!id)
62  CXX_THROW(Eng3D::ShaderException, "Can't create shader");
63  const char* c_code = buffer.c_str();
64  glShaderSource(id, 1, &c_code, NULL);
65  compile(type);
66 }
67 
68 #include <sstream>
69 void Eng3D::OpenGL::Shader::compile(GLuint) {
70  glCompileShader(id);
71 
72  // Check for errors of the shader
73  GLint r = 0;
74  glGetShaderiv(id, GL_COMPILE_STATUS, &r);
75  if(!r) {
76  GLint infoLen = 0;
77  glGetShaderiv(id, GL_INFO_LOG_LENGTH, &infoLen);
78  std::string shader_error_info;
79  shader_error_info.resize(infoLen);
80  glGetShaderInfoLog(id, infoLen, NULL, &shader_error_info[0]);
81 
82  std::ostringstream output_error;
83  output_error << "Shader did not compile:\n";
84  std::istringstream error_lines(shader_error_info);
85  std::string error;
86  getline(error_lines, error);
87  while(!error_lines.eof()) {
88  std::istringstream sline(error);
89  // Nvidia's style of errors
90  int slot, col;
91  size_t row;
92  char ch;
93 
94  // nvidia styles errors the following way:
95  // slot:row(column)
96  // They also like to fuck me over, so they use
97  // slot(row) <-- fuck this
98  sline >> slot >> ch;
99  if(ch == ':') {
100  sline >> row >> ch;
101  if(ch == '(')
102  sline >> col;
103  } else if(ch == '(') {
104  sline >> row >> ch;
105  }
106 
107  size_t read_lines = 0;
108  std::stringstream code(buffer);
109  std::string error_code;
110  while(read_lines < row && !code.eof()) {
111  getline(code, error_code);
112  read_lines++;
113  }
114 
115  getline(sline, error);
116  if(row > 0 && row - 1 < line_numbers.size())
117  row = line_numbers[row - 1];
118 
119  output_error << "(" << row << ")" << ":" << error_code;
120  output_error << "\n^^^: " << error << "\n";
121  getline(error_lines, error);
122  }
123  Eng3D::Log::error("opengl", output_error.str());
124  CXX_THROW(Eng3D::ShaderException, output_error.str());
125  }
126  Eng3D::Log::debug("shader", "Status: Sucess");
127 }
128 
132  glDeleteShader(this->get_id());
133 }
134 
135 unsigned int Eng3D::OpenGL::Shader::get_id() const {
136  return this->id;
137 }
138 
139 //
140 // Vertex shader
141 //
142 Eng3D::OpenGL::VertexShader::VertexShader(const std::string& _buffer)
143  : Eng3D::OpenGL::Shader(_buffer, GL_VERTEX_SHADER)
144 {
145 
146 }
147 
148 //
149 // Fragment shader
150 //
151 Eng3D::OpenGL::FragmentShader::FragmentShader(const std::string& _buffer, bool use_transpiler, std::vector<Eng3D::GLSL::Define> defintions)
152  : Eng3D::OpenGL::Shader(_buffer, GL_FRAGMENT_SHADER, use_transpiler, defintions)
153 {
154 
155 }
156 
157 #if !defined E3D_BACKEND_GLES
158 //
159 // Geometry shader
160 //
161 Eng3D::OpenGL::GeometryShader::GeometryShader(const std::string& _buffer)
162  : Eng3D::OpenGL::Shader(_buffer, GL_GEOMETRY_SHADER)
163 {
164 
165 }
166 
167 //
168 // Tesseleation control shader
169 //
170 Eng3D::OpenGL::TessControlShader::TessControlShader(const std::string& _buffer)
171  : Eng3D::OpenGL::Shader(_buffer, GL_TESS_CONTROL_SHADER)
172 {
173 
174 }
175 
176 //
177 // Tesselation evaluation shader
178 //
179 Eng3D::OpenGL::TessEvalShader::TessEvalShader(const std::string& _buffer)
180  : Eng3D::OpenGL::Shader(_buffer, GL_TESS_EVALUATION_SHADER)
181 {
182 
183 }
184 #endif
185 
186 //
187 // Program shader
188 //
190  id = glCreateProgram();
191  if(!id)
192  CXX_THROW(Eng3D::ShaderException, "Can't create new shader program");
193  glBindAttribLocation(id, 0, "m_pos");
194  glBindAttribLocation(id, 1, "m_texcoord");
195 }
196 
198  glDeleteProgram(id);
199 }
200 
204  assert(id != 0); // Program has no Id
205  glLinkProgram(id);
206 
207  // Check for errors of the shader
208  GLint r;
209  glGetProgramiv(id, GL_LINK_STATUS, &r);
210  if(r != GL_TRUE) {
211  GLint infoLen = 0;
212  glGetProgramiv(id, GL_INFO_LOG_LENGTH, &infoLen);
213  std::string shader_error_info;
214  shader_error_info.resize(infoLen);
215  glGetShaderInfoLog(id, infoLen, NULL, &shader_error_info[0]);
216  Eng3D::Log::error("shader", Eng3D::translate_format("Shader program error %s", shader_error_info.c_str()));
217  }
218 }
219 
224  glAttachShader(id, shader.get_id());
225 }
226 
227 void Eng3D::OpenGL::Program::use() const {
228  glUseProgram(id);
229 }
230 
231 // Uniform overloads
232 // It allows the game engine to call these functions without worrying about type specifications
233 void Eng3D::OpenGL::Program::set_PVM(glm::mat4 projection, glm::mat4 view, glm::mat4 model) const {
234  set_uniform("projection", projection);
235  set_uniform("view", view);
236  set_uniform("model", model);
237 }
238 
239 void Eng3D::OpenGL::Program::set_uniform(const std::string& name, glm::mat4 uniform) const {
240  glProgramUniformMatrix4fv(id, glGetUniformLocation(id, name.c_str()), 1, GL_FALSE, glm::value_ptr(uniform));
241 }
242 
243 void Eng3D::OpenGL::Program::set_uniform(const std::string& name, float value1, float value2) const {
244  glProgramUniform2f(id, glGetUniformLocation(id, name.c_str()), value1, value2);
245 }
246 
247 void Eng3D::OpenGL::Program::set_uniform(const std::string& name, float value1, float value2, float value3) const {
248  glProgramUniform3f(id, glGetUniformLocation(id, name.c_str()), value1, value2, value3);
249 }
250 
251 void Eng3D::OpenGL::Program::set_uniform(const std::string& name, glm::vec2 uniform) const {
252  set_uniform(name, uniform.x, uniform.y);
253 }
254 
255 void Eng3D::OpenGL::Program::set_uniform(const std::string& name, glm::vec3 uniform) const {
256  set_uniform(name, uniform.x, uniform.y, uniform.z);
257 }
258 
259 void Eng3D::OpenGL::Program::set_uniform(const std::string& name, glm::vec4 uniform) const {
260  set_uniform(name, uniform.x, uniform.y, uniform.z, uniform.w);
261 }
262 
263 void Eng3D::OpenGL::Program::set_uniform(const std::string& name, float value1, float value2, float value3, float value4) const {
264  glProgramUniform4f(id, glGetUniformLocation(id, name.c_str()), value1, value2, value3, value4);
265 }
266 
267 void Eng3D::OpenGL::Program::set_uniform(const std::string& name, float value) const {
268  glProgramUniform1f(id, glGetUniformLocation(id, name.c_str()), value);
269 }
270 
271 void Eng3D::OpenGL::Program::set_uniform(const std::string& name, int value) const {
272  glProgramUniform1i(id, glGetUniformLocation(id, name.c_str()), value);
273 }
274 
276 void Eng3D::OpenGL::Program::set_texture(int value, const std::string& name, const Eng3D::Texture& texture) const {
277  glActiveTexture(GL_TEXTURE0 + value);
278  set_uniform(name, value);
279  glBindTexture(GL_TEXTURE_2D, texture.id);
280 }
281 
282 void Eng3D::OpenGL::Program::set_texture(int value, const std::string& name, const Eng3D::TextureArray& texture) const {
283  glActiveTexture(GL_TEXTURE0 + value);
284  set_uniform(name, value);
285  glBindTexture(GL_TEXTURE_2D_ARRAY, texture.id);
286 }
287 
288 unsigned int Eng3D::OpenGL::Program::get_id() const {
289  return this->id;
290 }
291 #endif
std::vector< Eng3D::GLSL::Token >::iterator it
Definition: glsl_trans.hpp:145
virtual const char * what() const noexcept
Definition: glsl_trans.hpp:141
FragmentShader(const std::string &_buffer, bool use_transpiler=true, std::vector< Eng3D::GLSL::Define > defintions={})
GeometryShader(const std::string &_buffer)
void set_texture(int value, const std::string &name, const Eng3D::Texture &texture) const
void attach_shader(const Eng3D::OpenGL::Shader &shader)
void set_uniform(const std::string &name, glm::mat4 uniform) const
unsigned int get_id() const
void set_PVM(glm::mat4 projection, glm::mat4 view, glm::mat4 model) const
OpenGL shader object.
Definition: shader.hpp:75
unsigned int get_id() const
Shader(const std::string &_buffer, unsigned int type, bool use_transpiler=true, std::vector< Eng3D::GLSL::Define > defintions={})
TessControlShader(const std::string &_buffer)
TessEvalShader(const std::string &_buffer)
VertexShader(const std::string &_buffer)
unsigned int id
Definition: texture.hpp:165
unsigned int id
Definition: texture.hpp:146
void error(const std::string_view category, const std::string_view msg)
Definition: log.cpp:68
void debug(const std::string_view category, const std::string_view msg)
Definition: log.cpp:58
std::string translate_format(const std::string_view format, Args &&... args)
String formatter, with translation.
Definition: string.hpp:128
#define CXX_THROW(class,...)
Definition: utils.hpp:98