1 // This file belongs to the "MiniCore" game engine.
2 // Copyright (C) 2013 Jussi Lind <jussi.lind@iki.fi>
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 2
7 // of the License, or (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, write to the Free Software
16 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 // MA 02110-1301, USA.
18 //
19
20 #include "mcglobjectbase.hh"
21
22 #include "mccamera.hh"
23 #include "mcglscene.hh"
24 #include "mclogger.hh"
25
26 #include <cassert>
27 #include <exception>
28
29 GLuint MCGLObjectBase::m_boundVbo = 0;
30
MCGLObjectBase(std::string handle)31 MCGLObjectBase::MCGLObjectBase(std::string handle)
32 : m_handle(handle)
33 , m_program(MCGLScene::instance().defaultShaderProgram())
34 , m_shadowProgram(MCGLScene::instance().defaultShadowShaderProgram())
35 {
36 #ifdef __MC_QOPENGLFUNCTIONS__
37 initializeOpenGLFunctions();
38 #endif
39 }
40
setShaderProgram(MCGLShaderProgramPtr program)41 void MCGLObjectBase::setShaderProgram(MCGLShaderProgramPtr program)
42 {
43 m_program = program;
44 }
45
setShadowShaderProgram(MCGLShaderProgramPtr program)46 void MCGLObjectBase::setShadowShaderProgram(MCGLShaderProgramPtr program)
47 {
48 m_shadowProgram = program;
49 }
50
shaderProgram() const51 MCGLShaderProgramPtr MCGLObjectBase::shaderProgram() const
52 {
53 return m_program;
54 }
55
shadowShaderProgram() const56 MCGLShaderProgramPtr MCGLObjectBase::shadowShaderProgram() const
57 {
58 return m_shadowProgram;
59 }
60
61 // Notice that on desktop OpenGL 3.0+ VAOs are mandatory.
62 // Without VAOs this code will run only on GLES.
bindVAO()63 void MCGLObjectBase::bindVAO()
64 {
65 #ifdef __MC_QOPENGLFUNCTIONS__
66 if (m_hasVao)
67 {
68 m_vao.bind();
69 }
70 else
71 {
72 setAttributePointers();
73 }
74 #else
75 glBindVertexArray(m_vao);
76 #endif
77 }
78
releaseVAO()79 void MCGLObjectBase::releaseVAO()
80 {
81 #ifdef __MC_QOPENGLFUNCTIONS__
82 if (m_hasVao)
83 {
84 m_vao.release();
85 }
86 #else
87 glBindVertexArray(0);
88 #endif
89 }
90
createVAO()91 bool MCGLObjectBase::createVAO()
92 {
93 #ifdef __MC_QOPENGLFUNCTIONS__
94 m_hasVao = m_vao.create();
95 return m_hasVao;
96 #else
97 if (m_vao == 0)
98 {
99 glGenVertexArrays(1, &m_vao);
100 }
101 return m_vao;
102 #endif
103 }
104
bindVBO()105 void MCGLObjectBase::bindVBO()
106 {
107 glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
108 MCGLObjectBase::m_boundVbo = m_vbo;
109 }
110
releaseVBO()111 void MCGLObjectBase::releaseVBO()
112 {
113 MCGLObjectBase::m_boundVbo = 0;
114 glBindBuffer(GL_ARRAY_BUFFER, 0);
115 }
116
createVBO()117 void MCGLObjectBase::createVBO()
118 {
119 if (m_vbo == 0)
120 {
121 glGenBuffers(1, &m_vbo);
122 }
123 }
124
render()125 void MCGLObjectBase::render()
126 {
127 glDrawArrays(GL_TRIANGLES, 0, static_cast<int>(m_vertices.size()));
128 }
129
render(MCCamera * camera,MCVector3dFR pos,float angle)130 void MCGLObjectBase::render(MCCamera * camera, MCVector3dFR pos, float angle)
131 {
132 float x = pos.i();
133 float y = pos.j();
134 float z = pos.k();
135
136 if (camera)
137 {
138 camera->mapToCamera(x, y);
139 }
140
141 bind();
142
143 shaderProgram()->setScale(m_scale.i(), m_scale.j(), m_scale.k());
144 shaderProgram()->setColor(color());
145 shaderProgram()->setTransform(angle, MCVector3dF(x, y, z));
146
147 render();
148
149 release();
150 }
151
renderShadow(MCCamera * camera,MCVector3dFR pos,float angle)152 void MCGLObjectBase::renderShadow(MCCamera * camera, MCVector3dFR pos, float angle)
153 {
154 float x = pos.i();
155 float y = pos.j();
156
157 if (camera)
158 {
159 camera->mapToCamera(x, y);
160 }
161
162 bindShadow();
163
164 shadowShaderProgram()->setScale(m_scale.i(), m_scale.j(), m_scale.k());
165 shadowShaderProgram()->setTransform(angle, MCVector3dF(x, y, pos.k()));
166
167 render();
168
169 releaseShadow();
170 }
171
bind()172 void MCGLObjectBase::bind()
173 {
174 if (shaderProgram())
175 {
176 shaderProgram()->bind();
177 shaderProgram()->bindMaterial(m_material);
178
179 bindVBO();
180 bindVAO();
181 }
182 else
183 {
184 // Save the user from debugging as to why nothing is being drawn.
185 throw std::runtime_error("Trying to bind MCGLObject but shader program for it not set!");
186 }
187 }
188
bindShadow()189 void MCGLObjectBase::bindShadow()
190 {
191 if (shadowShaderProgram())
192 {
193 shadowShaderProgram()->bind();
194 shadowShaderProgram()->bindMaterial(m_material);
195
196 bindVBO();
197 bindVAO();
198 }
199 else
200 {
201 // Save the user from debugging as to why nothing is being drawn.
202 throw std::runtime_error("Trying to render shadow for surface, but shader program for it not set!");
203 }
204 }
205
release()206 void MCGLObjectBase::release()
207 {
208 releaseVAO();
209 }
210
releaseShadow()211 void MCGLObjectBase::releaseShadow()
212 {
213 releaseVAO();
214 }
215
setMaterial(MCGLMaterialPtr material)216 void MCGLObjectBase::setMaterial(MCGLMaterialPtr material)
217 {
218 m_material = material;
219 }
220
material() const221 MCGLMaterialPtr MCGLObjectBase::material() const
222 {
223 return m_material;
224 }
225
initBufferData(size_t totalDataSize,GLuint drawType)226 void MCGLObjectBase::initBufferData(size_t totalDataSize, GLuint drawType)
227 {
228 m_totalDataSize = totalDataSize;
229
230 createVAO();
231 createVBO();
232
233 bindVAO();
234 bindVBO();
235
236 glBufferData(GL_ARRAY_BUFFER, static_cast<int>(m_totalDataSize), nullptr, drawType);
237
238 m_bufferDataOffset = 0;
239 }
240
addVertex(const MCGLVertex & vertex)241 void MCGLObjectBase::addVertex(const MCGLVertex & vertex)
242 {
243 m_vertices.push_back(vertex);
244 }
245
setVertices(const VertexVector & vertices)246 void MCGLObjectBase::setVertices(const VertexVector & vertices)
247 {
248 m_vertices = vertices;
249 }
250
vertex(size_t index) const251 const MCGLVertex & MCGLObjectBase::vertex(size_t index) const
252 {
253 return m_vertices.at(index);
254 }
255
verticesAsGlArray() const256 const GLfloat * MCGLObjectBase::verticesAsGlArray() const
257 {
258 return reinterpret_cast<const GLfloat *>(&m_vertices[0]);
259 }
260
vertexCount() const261 size_t MCGLObjectBase::vertexCount() const
262 {
263 return m_vertices.size();
264 }
265
addNormal(const MCGLVertex & normal)266 void MCGLObjectBase::addNormal(const MCGLVertex & normal)
267 {
268 m_normals.push_back(normal);
269 }
270
setNormals(const VertexVector & normals)271 void MCGLObjectBase::setNormals(const VertexVector & normals)
272 {
273 m_normals = normals;
274 }
275
normal(size_t index) const276 const MCGLVertex & MCGLObjectBase::normal(size_t index) const
277 {
278 return m_normals.at(index);
279 }
280
normalsAsGlArray() const281 const GLfloat * MCGLObjectBase::normalsAsGlArray() const
282 {
283 return reinterpret_cast<const GLfloat *>(&m_normals[0]);
284 }
285
setColor(const MCGLColor & color)286 void MCGLObjectBase::setColor(const MCGLColor & color)
287 {
288 m_color = color;
289 }
290
color() const291 MCGLColor MCGLObjectBase::color() const
292 {
293 return m_color;
294 }
295
addColor(const MCGLColor & color)296 void MCGLObjectBase::addColor(const MCGLColor & color)
297 {
298 m_colors.push_back(color);
299 }
300
setColors(const ColorVector & colors)301 void MCGLObjectBase::setColors(const ColorVector & colors)
302 {
303 m_colors = colors;
304 }
305
color(size_t index) const306 const MCGLColor & MCGLObjectBase::color(size_t index) const
307 {
308 return m_colors.at(index);
309 }
310
colorsAsGlArray() const311 const GLfloat * MCGLObjectBase::colorsAsGlArray() const
312 {
313 return reinterpret_cast<const GLfloat *>(&m_colors[0]);
314 }
315
addTexCoord(const MCGLTexCoord & texCoord)316 void MCGLObjectBase::addTexCoord(const MCGLTexCoord & texCoord)
317 {
318 m_texCoords.push_back(texCoord);
319 }
320
setTexCoords(const TexCoordVector & texCoords)321 void MCGLObjectBase::setTexCoords(const TexCoordVector & texCoords)
322 {
323 m_texCoords = texCoords;
324 }
325
texCoord(size_t index) const326 const MCGLTexCoord & MCGLObjectBase::texCoord(size_t index) const
327 {
328 return m_texCoords.at(index);
329 }
330
texCoordsAsGlArray() const331 const GLfloat * MCGLObjectBase::texCoordsAsGlArray() const
332 {
333 return reinterpret_cast<const GLfloat *>(&m_texCoords[0]);
334 }
335
initUpdateBufferData()336 void MCGLObjectBase::initUpdateBufferData()
337 {
338 bindVAO();
339 bindVBO();
340
341 glBufferData(GL_ARRAY_BUFFER, static_cast<int>(m_totalDataSize), nullptr, GL_DYNAMIC_DRAW);
342
343 m_bufferDataOffset = 0;
344 }
345
addBufferSubData(MCGLShaderProgram::VertexAttribLocations dataType,size_t dataSize,const GLfloat * data)346 void MCGLObjectBase::addBufferSubData(
347 MCGLShaderProgram::VertexAttribLocations dataType, size_t dataSize, const GLfloat * data)
348 {
349 addBufferSubData(dataType, dataSize, dataSize, data);
350 }
351
addBufferSubData(MCGLShaderProgram::VertexAttribLocations dataType,size_t dataSize,size_t offsetJump,const GLfloat * data)352 void MCGLObjectBase::addBufferSubData(
353 MCGLShaderProgram::VertexAttribLocations dataType, size_t dataSize, size_t offsetJump, const GLfloat * data)
354 {
355 assert(dataSize <= offsetJump);
356
357 glBufferSubData(GL_ARRAY_BUFFER, static_cast<int>(m_bufferDataOffset), static_cast<int>(dataSize), data);
358
359 m_bufferDataOffset += offsetJump;
360
361 switch (dataType)
362 {
363 case MCGLShaderProgram::VAL_Vertex:
364 m_vertexDataSize = dataSize;
365 break;
366 case MCGLShaderProgram::VAL_Normal:
367 m_normalDataSize = dataSize;
368 break;
369 case MCGLShaderProgram::VAL_TexCoords:
370 m_texCoordDataSize = dataSize;
371 break;
372 case MCGLShaderProgram::VAL_Color:
373 m_colorDataSize = dataSize;
374 break;
375 }
376 }
377
enableAttributePointers()378 void MCGLObjectBase::enableAttributePointers()
379 {
380 glEnableVertexAttribArray(MCGLShaderProgram::VAL_Vertex);
381 glEnableVertexAttribArray(MCGLShaderProgram::VAL_Normal);
382 glEnableVertexAttribArray(MCGLShaderProgram::VAL_TexCoords);
383 glEnableVertexAttribArray(MCGLShaderProgram::VAL_Color);
384 }
385
setAttributePointers()386 void MCGLObjectBase::setAttributePointers()
387 {
388 enableAttributePointers();
389
390 glVertexAttribPointer(MCGLShaderProgram::VAL_Vertex, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
391
392 glVertexAttribPointer(MCGLShaderProgram::VAL_Normal, 3, GL_FLOAT, GL_FALSE, 0,
393 reinterpret_cast<GLvoid *>(m_vertexDataSize));
394
395 glVertexAttribPointer(MCGLShaderProgram::VAL_TexCoords, 2, GL_FLOAT, GL_FALSE, 0,
396 reinterpret_cast<GLvoid *>(m_vertexDataSize + m_normalDataSize));
397
398 glVertexAttribPointer(MCGLShaderProgram::VAL_Color, 4, GL_FLOAT, GL_FALSE, 0,
399 reinterpret_cast<GLvoid *>(m_vertexDataSize + m_normalDataSize + m_texCoordDataSize));
400 }
401
disableAttributePointers()402 void MCGLObjectBase::disableAttributePointers()
403 {
404 glDisableVertexAttribArray(MCGLShaderProgram::VAL_Vertex);
405 glDisableVertexAttribArray(MCGLShaderProgram::VAL_Normal);
406 glDisableVertexAttribArray(MCGLShaderProgram::VAL_TexCoords);
407 glDisableVertexAttribArray(MCGLShaderProgram::VAL_Color);
408 }
409
scale() const410 MCVector3dF MCGLObjectBase::scale() const
411 {
412 return m_scale;
413 }
414
handle() const415 std::string MCGLObjectBase::handle() const
416 {
417 return m_handle;
418 }
419
setHandle(const std::string & handle)420 void MCGLObjectBase::setHandle(const std::string & handle)
421 {
422 m_handle = handle;
423 }
424
width() const425 float MCGLObjectBase::width() const
426 {
427 return m_width * m_scale.i();
428 }
429
setWidth(float width)430 void MCGLObjectBase::setWidth(float width)
431 {
432 m_width = width;
433 }
434
height() const435 float MCGLObjectBase::height() const
436 {
437 return m_height * m_scale.j();
438 }
439
setHeight(float height)440 void MCGLObjectBase::setHeight(float height)
441 {
442 m_height = height;
443 }
444
setMaxZ(float maxZ)445 void MCGLObjectBase::setMaxZ(float maxZ)
446 {
447 m_maxZ = maxZ;
448 }
449
setMinZ(float minZ)450 void MCGLObjectBase::setMinZ(float minZ)
451 {
452 m_minZ = minZ;
453 }
454
setScale(const MCVector3dF & scale)455 void MCGLObjectBase::setScale(const MCVector3dF & scale)
456 {
457 m_scale = scale;
458 }
459
setSize(float width,float height)460 void MCGLObjectBase::setSize(float width, float height)
461 {
462 m_scale.setI(width / m_width);
463 m_scale.setJ(height / m_height);
464 }
465
minZ() const466 float MCGLObjectBase::minZ() const
467 {
468 return m_minZ * m_scale.k();
469 }
470
maxZ() const471 float MCGLObjectBase::maxZ() const
472 {
473 return m_maxZ * m_scale.k();
474 }
475
finishBufferData()476 void MCGLObjectBase::finishBufferData()
477 {
478 setAttributePointers();
479
480 releaseVBO();
481 releaseVAO();
482 }
483
totalDataSize() const484 size_t MCGLObjectBase::totalDataSize() const
485 {
486 return m_totalDataSize;
487 }
488
~MCGLObjectBase()489 MCGLObjectBase::~MCGLObjectBase()
490 {
491 if (m_vbo != 0)
492 {
493 glDeleteBuffers(1, &m_vbo);
494 m_vbo = 0;
495 }
496 #ifndef __MC_QOPENGLFUNCTIONS__
497 if (m_vao != 0)
498 {
499 glDeleteVertexArrays(1, &m_vao);
500 m_vao = 0;
501 }
502 #endif
503 }
504