1 // SuperTuxKart - a fun racing game with go-kart
2 // Copyright (C) 2018 SuperTuxKart-Team
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 3
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18 #include "graphics/sp/sp_mesh_buffer.hpp"
19 #include "graphics/sp/sp_texture.hpp"
20 #include "graphics/central_settings.hpp"
21 #include "graphics/graphics_restrictions.hpp"
22 #include "graphics/material.hpp"
23 #include "graphics/sp/sp_shader.hpp"
24 #include "graphics/sp/sp_shader_manager.hpp"
25 #include "graphics/sp/sp_texture_manager.hpp"
26 #include "race/race_manager.hpp"
27 #include "utils/mini_glm.hpp"
28 #include "utils/string_utils.hpp"
29
30 #include <set>
31
32 namespace SP
33 {
34 // ----------------------------------------------------------------------------
~SPMeshBuffer()35 SPMeshBuffer::~SPMeshBuffer()
36 {
37 #ifndef SERVER_ONLY
38 for (unsigned i = 0; i < DCT_FOR_VAO; i++)
39 {
40 if (m_vao[i] != 0)
41 {
42 glDeleteVertexArrays(1, &m_vao[i]);
43 }
44 if (m_ins_array[i] != 0)
45 {
46 if (CVS->isARBBufferStorageUsable())
47 {
48 glBindBuffer(GL_ARRAY_BUFFER, m_ins_array[i]);
49 glUnmapBuffer(GL_ARRAY_BUFFER);
50 glBindBuffer(GL_ARRAY_BUFFER, 0);
51 }
52 glDeleteBuffers(1, &m_ins_array[i]);
53 }
54 }
55 if (m_ibo != 0)
56 {
57 glDeleteBuffers(1, &m_ibo);
58 }
59 if (m_vbo != 0)
60 {
61 glDeleteBuffers(1, &m_vbo);
62 }
63 #endif
64 } // ~SPMeshBuffer
65
66 // ----------------------------------------------------------------------------
initDrawMaterial()67 void SPMeshBuffer::initDrawMaterial()
68 {
69 #ifndef SERVER_ONLY
70 Material* m = std::get<2>(m_stk_material[0]);
71 if (RaceManager::get()->getReverseTrack() && m->getMirrorAxisInReverse() != ' ')
72 {
73 for (unsigned i = 0; i < getVertexCount(); i++)
74 {
75 using namespace MiniGLM;
76 if (m->getMirrorAxisInReverse() == 'V')
77 {
78 m_vertices[i].m_all_uvs[1] =
79 toFloat16(1.0f - toFloat32(m_vertices[i].m_all_uvs[1]));
80 }
81 else
82 {
83 m_vertices[i].m_all_uvs[0] =
84 toFloat16(1.0f - toFloat32(m_vertices[i].m_all_uvs[0]));
85 }
86 }
87 } // reverse track and texture needs mirroring
88 #endif
89 } // initDrawMaterial
90
91 // ----------------------------------------------------------------------------
initTexture()92 bool SPMeshBuffer::initTexture()
93 {
94 #ifndef SERVER_ONLY
95 for (unsigned i = 0; i < m_stk_material.size(); i++)
96 {
97 for (unsigned j = 0; j < 6; j++)
98 {
99 if (!m_textures[i][j]->initialized())
100 {
101 return false;
102 }
103 }
104 }
105 #endif
106 return true;
107 } // initTexture
108
109 // ----------------------------------------------------------------------------
uploadGLMesh()110 void SPMeshBuffer::uploadGLMesh()
111 {
112 if (m_uploaded_gl)
113 {
114 return;
115 }
116 m_uploaded_gl = true;
117 #ifndef SERVER_ONLY
118 if (!m_shaders[0])
119 {
120 Log::warn("SPMeshBuffer", "%s shader is missing",
121 std::get<2>(m_stk_material[0])->getShaderName().c_str());
122 return;
123 }
124
125 m_textures.resize(m_stk_material.size());
126 for (unsigned i = 0; i < m_stk_material.size(); i++)
127 {
128 for (unsigned j = 0; j < 6; j++)
129 {
130 m_textures[i][j] = SPTextureManager::get()->getTexture
131 (m_shaders[0]->hasTextureLayer(j) ?
132 std::get<2>(m_stk_material[i])->getSamplerPath(j) : "",
133 j == 0 ? std::get<2>(m_stk_material[i]) : NULL,
134 m_shaders[0]->isSrgbForTextureLayer(j),
135 std::get<2>(m_stk_material[i])->getContainerId());
136 }
137 // Use the original spm uv texture 1 and 2 for compare in scene manager
138 m_tex_cmp[std::get<2>(m_stk_material[i])->getSamplerPath(0) +
139 std::get<2>(m_stk_material[i])->getSamplerPath(1)] = i;
140 }
141
142 bool use_2_uv = std::get<2>(m_stk_material[0])->use2UV();
143 bool use_tangents = m_shaders[0]->useTangents();
144 const unsigned pitch = 48 - (use_tangents ? 0 : 4) - (use_2_uv ? 0 : 4) -
145 (m_skinned ? 0 : 16);
146 m_pitch = pitch;
147
148 if (m_vbo != 0)
149 {
150 glDeleteBuffers(1, &m_vbo);
151 }
152 glGenBuffers(1, &m_vbo);
153 glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
154
155 unsigned v_size = (unsigned)m_vertices.size() * pitch;
156 glBufferData(GL_ARRAY_BUFFER, v_size, NULL, GL_DYNAMIC_DRAW);
157 size_t offset = 0;
158 char* ptr = (char*)glMapBufferRange(GL_ARRAY_BUFFER, 0, v_size,
159 GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT |
160 GL_MAP_INVALIDATE_BUFFER_BIT);
161 v_size = 0;
162 for (unsigned i = 0 ; i < m_vertices.size(); i++)
163 {
164 offset = 0;
165 memcpy(ptr + v_size + offset, &m_vertices[i].m_position.X, 12);
166 offset += 12;
167
168 memcpy(ptr + v_size + offset, &m_vertices[i].m_normal, 12);
169 offset += 4;
170
171 video::SColor vc = m_vertices[i].m_color;
172 if (CVS->isDeferredEnabled())
173 {
174 vc.setRed(srgb255ToLinear(vc.getRed()));
175 vc.setGreen(srgb255ToLinear(vc.getGreen()));
176 vc.setBlue(srgb255ToLinear(vc.getBlue()));
177 }
178 memcpy(ptr + v_size + offset, &vc, 4);
179 offset += 4;
180
181 memcpy(ptr + v_size + offset, &m_vertices[i].m_all_uvs[0], 4);
182 offset += 4;
183 if (use_2_uv)
184 {
185 memcpy(ptr + v_size + offset, &m_vertices[i].m_all_uvs[2], 4);
186 offset += 4;
187 }
188 if (use_tangents)
189 {
190 memcpy(ptr + v_size + offset, &m_vertices[i].m_tangent, 4);
191 offset += 4;
192 }
193 if (m_skinned)
194 {
195 memcpy(ptr + v_size + offset, &m_vertices[i].m_joint_idx[0], 16);
196 }
197 v_size += pitch;
198 }
199 glUnmapBuffer(GL_ARRAY_BUFFER);
200
201 SPTextureManager::get()->increaseGLCommandFunctionCount(1);
202 SPTextureManager::get()->addGLCommandFunction
203 (std::bind(&SPMeshBuffer::initTexture, this));
204
205 if (m_ibo != 0)
206 {
207 glDeleteBuffers(1, &m_ibo);
208 }
209 glGenBuffers(1, &m_ibo);
210 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo);
211
212 glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indices.size() * 2,
213 m_indices.data(), GL_STATIC_DRAW);
214 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
215
216 #endif
217 } // uploadGLMesh
218
219 // ----------------------------------------------------------------------------
recreateVAO(unsigned i)220 void SPMeshBuffer::recreateVAO(unsigned i)
221 {
222 #ifndef SERVER_ONLY
223 if (!m_shaders[0])
224 {
225 return;
226 }
227 bool use_2_uv = std::get<2>(m_stk_material[0])->use2UV();
228 bool use_tangents = m_shaders[0]->useTangents();
229 const unsigned pitch = m_pitch;
230
231 size_t offset = 0;
232
233 if (m_ins_array[i] == 0)
234 {
235 glGenBuffers(1, &m_ins_array[i]);
236 }
237 else
238 {
239 if (CVS->isARBBufferStorageUsable())
240 {
241 glBindBuffer(GL_ARRAY_BUFFER, m_ins_array[i]);
242 glUnmapBuffer(GL_ARRAY_BUFFER);
243 glBindBuffer(GL_ARRAY_BUFFER, 0);
244 }
245 glDeleteBuffers(1, &m_ins_array[i]);
246 glGenBuffers(1, &m_ins_array[i]);
247 }
248 glBindBuffer(GL_ARRAY_BUFFER, m_ins_array[i]);
249 #ifndef USE_GLES2
250 if (CVS->isARBBufferStorageUsable())
251 {
252 glBufferStorage(GL_ARRAY_BUFFER, m_gl_instance_size[i] * 44, NULL,
253 GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
254 m_ins_dat_mapped_ptr[i] = glMapBufferRange(GL_ARRAY_BUFFER, 0,
255 m_gl_instance_size[i] * 44,
256 GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
257 }
258 else
259 #endif
260 {
261 glBufferData(GL_ARRAY_BUFFER, m_gl_instance_size[i] * 44, NULL,
262 GL_DYNAMIC_DRAW);
263 }
264 glBindBuffer(GL_ARRAY_BUFFER, 0);
265
266 if (m_vao[i] != 0)
267 {
268 glDeleteVertexArrays(1, &m_vao[i]);
269 }
270 glGenVertexArrays(1, &m_vao[i]);
271 glBindVertexArray(m_vao[i]);
272
273 glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
274 // Position
275 glEnableVertexAttribArray(0);
276 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, pitch, (void*)offset);
277 offset += 12;
278
279 // Normal, if 10bit vector normalization is wrongly done by drivers, use
280 // original value and normalize ourselves in shader
281 glEnableVertexAttribArray(1);
282 glVertexAttribPointer(1, 4, GL_INT_2_10_10_10_REV,
283 GraphicsRestrictions::isDisabled
284 (GraphicsRestrictions::GR_CORRECT_10BIT_NORMALIZATION) ?
285 GL_FALSE : GL_TRUE, pitch, (void*)offset);
286 offset += 4;
287
288 // Vertex color
289 glEnableVertexAttribArray(2);
290 glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, pitch,
291 (void*)offset);
292 offset += 4;
293
294 // 1st texture coordinates
295 glEnableVertexAttribArray(3);
296 glVertexAttribPointer(3, 2, GL_HALF_FLOAT, GL_FALSE, pitch, (void*)offset);
297 offset += 4;
298 if (use_2_uv)
299 {
300 // 2nd texture coordinates
301 glEnableVertexAttribArray(4);
302 glVertexAttribPointer(4, 2, GL_HALF_FLOAT, GL_FALSE, pitch,
303 (void*)offset);
304 offset += 4;
305 }
306 else
307 {
308 glDisableVertexAttribArray(4);
309 }
310
311 if (use_tangents)
312 {
313 // Tangent and bi-tanget sign
314 glEnableVertexAttribArray(5);
315 glVertexAttribPointer(5, 4, GL_INT_2_10_10_10_REV,
316 GraphicsRestrictions::isDisabled
317 (GraphicsRestrictions::GR_CORRECT_10BIT_NORMALIZATION) ?
318 GL_FALSE : GL_TRUE, pitch, (void*)offset);
319 offset += 4;
320 }
321 else
322 {
323 glDisableVertexAttribArray(5);
324 }
325
326 if (m_skinned)
327 {
328 // 4 Joint indices
329 glEnableVertexAttribArray(6);
330 glVertexAttribIPointer(6, 4, GL_SHORT, pitch, (void*)offset);
331 offset += 8;
332 // 4 Joint weights
333 glEnableVertexAttribArray(7);
334 glVertexAttribPointer(7, 4, GL_HALF_FLOAT, GL_FALSE, pitch,
335 (void*)offset);
336 offset += 8;
337 }
338 else
339 {
340 glDisableVertexAttribArray(6);
341 glDisableVertexAttribArray(7);
342 }
343 glDisableVertexAttribArray(13);
344 glDisableVertexAttribArray(14);
345 glDisableVertexAttribArray(15);
346
347 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo);
348 glBindBuffer(GL_ARRAY_BUFFER, m_ins_array[i]);
349 // Origin
350 glEnableVertexAttribArray(8);
351 glVertexAttribPointer(8, 3, GL_FLOAT, GL_FALSE, 44, (void*)0);
352 glVertexAttribDivisorARB(8, 1);
353 // Rotation (quaternion in 4 32bit floats)
354 glEnableVertexAttribArray(9);
355 glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, 44, (void*)12);
356 glVertexAttribDivisorARB(9, 1);
357 // Scale (3 half floats and .w unused)
358 glEnableVertexAttribArray(10);
359 glVertexAttribPointer(10, 4, GL_HALF_FLOAT, GL_FALSE, 44, (void*)28);
360 glVertexAttribDivisorARB(10, 1);
361 // Texture translation
362 glEnableVertexAttribArray(11);
363 glVertexAttribPointer(11, 2, GL_SHORT, GL_TRUE, 44, (void*)36);
364 glVertexAttribDivisorARB(11, 1);
365 // Misc data (skinning offset and hue change)
366 glEnableVertexAttribArray(12);
367 glVertexAttribIPointer(12, 2, GL_SHORT, 44, (void*)40);
368 glVertexAttribDivisorARB(12, 1);
369
370 glBindVertexArray(0);
371 glBindBuffer(GL_ARRAY_BUFFER, 0);
372 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
373 #endif
374 } // uploadGLMesh
375
376 // ----------------------------------------------------------------------------
uploadInstanceData()377 void SPMeshBuffer::uploadInstanceData()
378 {
379 #ifndef SERVER_ONLY
380 for (unsigned i = 0; i < DCT_FOR_VAO; i++)
381 {
382 if (m_ins_dat[i].empty())
383 {
384 continue;
385 }
386
387 unsigned new_size =
388 m_gl_instance_size[i] == 0 ? 1 : m_gl_instance_size[i];
389 while (m_ins_dat[i].size() > new_size)
390 {
391 // Power of 2 allocation strategy, like std::vector in gcc
392 new_size <<= 1;
393 }
394 if (new_size != m_gl_instance_size[i])
395 {
396 m_gl_instance_size[i] = new_size;
397 recreateVAO(i);
398 }
399 if (CVS->isARBBufferStorageUsable())
400 {
401 memcpy(m_ins_dat_mapped_ptr[i], m_ins_dat[i].data(),
402 m_ins_dat[i].size() * 44);
403 }
404 else
405 {
406 glBindBuffer(GL_ARRAY_BUFFER, m_ins_array[i]);
407 void* ptr = glMapBufferRange(GL_ARRAY_BUFFER, 0,
408 m_ins_dat[i].size() * 44, GL_MAP_WRITE_BIT |
409 GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
410 memcpy(ptr, m_ins_dat[i].data(), m_ins_dat[i].size() * 44);
411 glUnmapBuffer(GL_ARRAY_BUFFER);
412 glBindBuffer(GL_ARRAY_BUFFER, 0);
413 }
414 }
415 #endif
416 m_uploaded_instance = true;
417 } // uploadInstanceData
418
419 // ----------------------------------------------------------------------------
enableTextureMatrix(unsigned mat_id)420 void SPMeshBuffer::enableTextureMatrix(unsigned mat_id)
421 {
422 #ifndef SERVER_ONLY
423 assert(mat_id < m_stk_material.size());
424 // Make the 31 bit in normal to be 1
425 uploadGLMesh();
426 if (m_vbo == 0 || m_ibo == 0)
427 return;
428 auto& ret = m_stk_material[mat_id];
429 glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
430 std::set<uint16_t> used_vertices;
431 for (unsigned int j = 0; j < std::get<1>(ret); j += 3)
432 {
433 for (unsigned int k = 0; k < 3; k++)
434 {
435 const uint16_t vertex_id = m_indices[std::get<0>(ret) + j + k];
436 auto ret = used_vertices.find(vertex_id);
437 if (ret == used_vertices.end())
438 {
439 if ((m_vertices[vertex_id].m_normal & (1 << 30)) != 0)
440 {
441 // Already enabled
442 glBindBuffer(GL_ARRAY_BUFFER, 0);
443 return;
444 }
445 used_vertices.insert(vertex_id);
446 m_vertices[vertex_id].m_normal |= 1 << 30;
447 glBufferSubData(GL_ARRAY_BUFFER,
448 (vertex_id * m_pitch) + 12 /*3 position*/, 4,
449 &m_vertices[vertex_id].m_normal);
450 }
451 }
452 }
453 glBindBuffer(GL_ARRAY_BUFFER, 0);
454 #endif
455 } // enableTextureMatrix
456
457 // ----------------------------------------------------------------------------
reloadTextureCompare()458 void SPMeshBuffer::reloadTextureCompare()
459 {
460 assert(!m_textures.empty());
461 m_tex_cmp.clear();
462 for (unsigned i = 0; i < m_stk_material.size(); i++)
463 {
464 const std::string name =
465 m_textures[i][0]->getPath() + m_textures[i][1]->getPath();
466 m_tex_cmp[name] = i;
467 }
468 } // reloadTextureCompare
469
470 // ----------------------------------------------------------------------------
setSTKMaterial(Material * m)471 void SPMeshBuffer::setSTKMaterial(Material* m)
472 {
473 m_stk_material[0] = std::make_tuple(0u, getIndexCount(), m);
474 const std::string shader_name =
475 std::get<2>(m_stk_material[0])->getShaderName();
476 const std::string skinned_shader_name =
477 std::get<2>(m_stk_material[0])->getShaderName() + "_skinned";
478
479 m_shaders[0] = SPShaderManager::get()->getSPShader(shader_name);
480 if (!m_shaders[0])
481 {
482 Log::warn("SPMeshBuffer", "%s shader is missing, fallback to solid",
483 shader_name.c_str());
484 m_shaders[0] = SPShaderManager::get()->getSPShader("solid");
485 }
486
487 m_shaders[1] = SPShaderManager::get()->getSPShader(skinned_shader_name);
488 if (!m_shaders[1])
489 m_shaders[1] = SPShaderManager::get()->getSPShader("solid_skinned");
490 } // setSTKMaterial
491
492 }
493