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