SuperTuxKart
sp_mesh_buffer.hpp
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 #ifndef HEADER_SP_MESH_BUFFER_HPP
19 #define HEADER_SP_MESH_BUFFER_HPP
20 
21 #include "graphics/gl_headers.hpp"
22 #include "graphics/sp/sp_base.hpp"
23 #include "graphics/sp/sp_instanced_data.hpp"
24 #include "graphics/sp/sp_per_object_uniform.hpp"
25 #include "utils/types.hpp"
26 
27 #include <IMeshBuffer.h>
28 #include <S3DVertex.h>
29 
30 #include <array>
31 #include <cassert>
32 #include <string>
33 #include <tuple>
34 #include <unordered_map>
35 #include <vector>
36 
37 using namespace irr;
38 using namespace scene;
39 
40 class Material;
41 
42 namespace SP
43 {
44 class SPShader;
45 class SPTexture;
46 
47 class SPMeshBuffer : public IMeshBuffer, public SPPerObjectUniform
48 {
49 protected:
50  std::shared_ptr<SPShader> m_shaders[2];
51 
52  std::vector<std::tuple<size_t/*first_index_id*/,
53  unsigned/*indices_count*/, Material*> > m_stk_material;
54 
55  std::vector<std::array<std::shared_ptr<SPTexture>, 6> > m_textures;
56 
57  std::unordered_map<std::string, unsigned> m_tex_cmp;
58 
59  std::vector<video::S3DVertexSkinnedMesh> m_vertices;
60 
61  GLuint m_ibo, m_vbo;
62 
63  GLuint m_vao[DCT_FOR_VAO];
64 
65  unsigned m_pitch;
66 
67 private:
68  std::vector<uint16_t> m_indices;
69 
70  core::aabbox3d<f32> m_bounding_box;
71 
72  std::vector<SPInstancedData> m_ins_dat[DCT_FOR_VAO];
73 
74  void* m_ins_dat_mapped_ptr[DCT_FOR_VAO];
75 
76  unsigned m_gl_instance_size[DCT_FOR_VAO];
77 
78  GLuint m_ins_array[DCT_FOR_VAO];
79 
80  bool m_uploaded_gl;
81 
82  bool m_uploaded_instance;
83 
84  bool m_skinned;
85 
86  // ------------------------------------------------------------------------
87  bool initTexture();
88 
89 public:
90  SPMeshBuffer()
91  {
92 #ifdef _DEBUG
93  setDebugName("SMeshBuffer");
94 #endif
95  m_stk_material.resize(1, std::make_tuple(0u, 0u, nullptr));
96 
97  for (unsigned i = 0; i < DCT_FOR_VAO; i++)
98  {
99  m_ins_dat_mapped_ptr[i] = NULL;
100  m_gl_instance_size[i] = 0;
101  m_vao[i] = 0;
102  m_ins_array[i] = 0;
103  }
104 
105  m_pitch = 0;
106  m_ibo = 0;
107  m_vbo = 0;
108  m_uploaded_gl = false;
109  m_uploaded_instance = false;
110  m_skinned = false;
111  }
112  // ------------------------------------------------------------------------
113  ~SPMeshBuffer();
114  // ------------------------------------------------------------------------
115  virtual void draw(DrawCallType dct = DCT_NORMAL, int material_id = -1) const
116  {
117 #ifndef SERVER_ONLY
118  glBindVertexArray(m_vao[dct]);
119  if (material_id == -1)
120  {
121  // Draw whole mesh buffer, usually in shadow pass
122  glDrawElementsInstanced(GL_TRIANGLES, getIndexCount(),
123  GL_UNSIGNED_SHORT, 0, (unsigned)m_ins_dat[dct].size());
124  }
125  else
126  {
127  unsigned idx_count = std::get<1>(m_stk_material[material_id]);
128  if (idx_count == 0)
129  return;
130  glDrawElementsInstanced(GL_TRIANGLES,
131  idx_count,
132  GL_UNSIGNED_SHORT,
133  (void*)(std::get<0>(m_stk_material[material_id]) << 1),
134  (unsigned)m_ins_dat[dct].size());
135  }
136 #endif
137  }
138  // ------------------------------------------------------------------------
139  virtual void uploadGLMesh();
140  // ------------------------------------------------------------------------
141  virtual void uploadInstanceData();
142  // ------------------------------------------------------------------------
143  bool combineMeshBuffer(SPMeshBuffer* spmb, bool different_material = true)
144  {
145  // We only use 16bit vertices
146  if (spmb->m_vertices.size() + m_vertices.size() > 65536)
147  {
148  return false;
149  }
150  const uint16_t old_vtx_count = (uint16_t)m_vertices.size();
151  m_vertices.insert(m_vertices.end(), spmb->m_vertices.begin(),
152  spmb->m_vertices.end());
153  for (uint16_t& idx : spmb->m_indices)
154  {
155  idx += old_vtx_count;
156  }
157  if (different_material)
158  {
159  m_stk_material.emplace_back(getIndexCount(), spmb->getIndexCount(),
160  std::get<2>(spmb->m_stk_material[0]));
161  }
162  else
163  {
164  std::get<1>(m_stk_material[0]) += (unsigned)spmb->m_indices.size();
165  }
166  m_indices.insert(m_indices.end(), spmb->m_indices.begin(),
167  spmb->m_indices.end());
168  return true;
169  }
170  // ------------------------------------------------------------------------
171  void initDrawMaterial();
172  // ------------------------------------------------------------------------
173  void enableSkinningData() { m_skinned = true; }
174  // ------------------------------------------------------------------------
175  Material* getSTKMaterial(unsigned first_index = 0) const
176  {
177  for (unsigned i = 0; i < m_stk_material.size(); i++)
178  {
179  if (i == unsigned(m_stk_material.size() - 1) ||
180  (first_index >= std::get<0>(m_stk_material[i]) &&
181  first_index < std::get<0>(m_stk_material[i + 1])))
182  {
183  return std::get<2>(m_stk_material[i]);
184  }
185  }
186  assert(false);
187  return NULL;
188  }
189  // ------------------------------------------------------------------------
190  void enableTextureMatrix(unsigned mat_id);
191  // ------------------------------------------------------------------------
192  std::array<std::shared_ptr<SPTexture>, 6>&
193  getSPTextures(unsigned first_index = 0)
194  {
195  assert(m_stk_material.size() == m_textures.size());
196  for (unsigned i = 0; i < m_stk_material.size(); i++)
197  {
198  if (i == unsigned(m_stk_material.size() - 1) ||
199  (first_index >= std::get<0>(m_stk_material[i]) &&
200  first_index < std::get<0>(m_stk_material[i + 1])))
201  {
202  return m_textures[i];
203  }
204  }
205  assert(false);
206  return m_textures[0];
207  }
208  // ------------------------------------------------------------------------
209  const std::array<std::shared_ptr<SPTexture>, 6>&
210  getSPTexturesByMaterialID(int material_id) const
211  {
212  assert((size_t)material_id < m_textures.size());
213  return m_textures[material_id];
214  }
215  // ------------------------------------------------------------------------
216  std::vector<Material*> getAllSTKMaterials() const
217  {
218  std::vector<Material*> ret;
219  for (unsigned i = 0; i < m_stk_material.size(); i++)
220  {
221  ret.push_back(std::get<2>(m_stk_material[i]));
222  }
223  return ret;
224  }
225  // ------------------------------------------------------------------------
226  const std::unordered_map<std::string, unsigned>& getTextureCompare() const
227  { return m_tex_cmp; }
228  // ------------------------------------------------------------------------
229  int getMaterialID(const std::string& tex_cmp) const
230  {
231  auto itr = m_tex_cmp.find(tex_cmp);
232  if (itr != m_tex_cmp.end())
233  {
234  return (int)itr->second;
235  }
236  return -1;
237  }
238  // ------------------------------------------------------------------------
239  void addInstanceData(const SPInstancedData& id, DrawCallType dct)
240  {
241  if (m_uploaded_instance)
242  {
243  for (unsigned i = 0; i < DCT_FOR_VAO; i++)
244  {
245  m_ins_dat[i].clear();
246  m_uploaded_instance = false;
247  }
248  }
249  m_ins_dat[dct].push_back(id);
250  }
251  // ------------------------------------------------------------------------
252  void recreateVAO(unsigned i);
253  // ------------------------------------------------------------------------
254  video::S3DVertexSkinnedMesh* getSPMVertex()
255  {
256  return m_vertices.data();
257  }
258  // ------------------------------------------------------------------------
259  void addSPMVertex(const video::S3DVertexSkinnedMesh& v)
260  {
261  m_vertices.push_back(v);
262  }
263  // ------------------------------------------------------------------------
264  void addIndex(uint16_t idx)
265  {
266  m_indices.push_back(idx);
267  }
268  // ------------------------------------------------------------------------
269  void setSPMVertices(std::vector<video::S3DVertexSkinnedMesh>& vertices)
270  {
271  m_vertices = std::move(vertices);
272  }
273  // ------------------------------------------------------------------------
274  void setIndices(std::vector<uint16_t>& indices)
275  {
276  m_indices = std::move(indices);
277  }
278  // ------------------------------------------------------------------------
279  void setSTKMaterial(Material* m);
280  // ------------------------------------------------------------------------
281  void reloadTextureCompare();
282  // ------------------------------------------------------------------------
283  void shrinkToFit()
284  {
285  m_vertices.shrink_to_fit();
286  m_indices.shrink_to_fit();
287  }
288  // ------------------------------------------------------------------------
289  SPShader* getShader(bool skinned = false) const
290  { return skinned ? m_shaders[1].get() : m_shaders[0].get(); }
291  // ------------------------------------------------------------------------
292  virtual const video::SMaterial& getMaterial() const
293  {
294  static video::SMaterial unused;
295  return unused;
296  }
297  // ------------------------------------------------------------------------
298  virtual video::SMaterial& getMaterial()
299  {
300  static video::SMaterial unused;
301  return unused;
302  }
303  // ------------------------------------------------------------------------
304  virtual const void* getVertices() const
305  {
306  return m_vertices.data();
307  }
308  // ------------------------------------------------------------------------
309  virtual void* getVertices()
310  {
311  return m_vertices.data();
312  }
313  // ------------------------------------------------------------------------
314  std::vector<video::S3DVertexSkinnedMesh>& getVerticesRef()
315  {
316  return m_vertices;
317  }
318  // ------------------------------------------------------------------------
319  virtual u32 getVertexCount() const
320  {
321  return (unsigned)m_vertices.size();
322  }
323  // ------------------------------------------------------------------------
324  virtual video::E_INDEX_TYPE getIndexType() const
325  {
326  return video::EIT_16BIT;
327  }
328  // ------------------------------------------------------------------------
329  std::vector<u16>& getIndicesRef()
330  {
331  return m_indices;
332  }
333  // ------------------------------------------------------------------------
334  virtual const u16* getIndices() const
335  {
336  return m_indices.data();
337  }
338  // ------------------------------------------------------------------------
339  virtual u16* getIndices()
340  {
341  return m_indices.data();
342  }
343  // ------------------------------------------------------------------------
344  virtual u32 getIndexCount() const
345  {
346  return (unsigned)m_indices.size();
347  }
348  // ------------------------------------------------------------------------
349  virtual const core::aabbox3d<f32>& getBoundingBox() const
350  {
351  return m_bounding_box;
352  }
353  // ------------------------------------------------------------------------
354  virtual void setBoundingBox(const core::aabbox3df& box)
355  {
356  m_bounding_box = box;
357  }
358  // ------------------------------------------------------------------------
359  virtual void recalculateBoundingBox()
360  {
361  if (m_vertices.empty())
362  {
363  m_bounding_box.reset(0.0f, 0.0f, 0.0f);
364  }
365  else
366  {
367  m_bounding_box.reset(m_vertices[0].m_position);
368  for (u32 i = 1; i < m_vertices.size(); i++)
369  {
370  m_bounding_box.addInternalPoint(m_vertices[i].m_position);
371  }
372  }
373  }
374  // ------------------------------------------------------------------------
375  virtual video::E_VERTEX_TYPE getVertexType() const
376  {
377  return video::EVT_SKINNED_MESH;
378  }
379  // ------------------------------------------------------------------------
380  virtual const core::vector3df& getPosition(u32 i) const
381  {
382  return m_vertices[i].m_position;
383  }
384  // ------------------------------------------------------------------------
385  virtual core::vector3df& getPosition(u32 i)
386  {
387  return m_vertices[i].m_position;
388  }
389  // ------------------------------------------------------------------------
390  virtual const core::vector3df& getNormal(u32 i) const
391  {
392  static core::vector3df unused;
393  return unused;
394  }
395  // ------------------------------------------------------------------------
396  virtual core::vector3df& getNormal(u32 i)
397  {
398  static core::vector3df unused;
399  return unused;
400  }
401  // ------------------------------------------------------------------------
402  virtual const core::vector2df& getTCoords(u32 i) const
403  {
404  static core::vector2df unused;
405  return unused;
406  }
407  // ------------------------------------------------------------------------
408  virtual core::vector2df& getTCoords(u32 i)
409  {
410  static core::vector2df unused;
411  return unused;
412  }
413  // ------------------------------------------------------------------------
414  virtual scene::E_PRIMITIVE_TYPE getPrimitiveType() const
415  {
416  return EPT_TRIANGLES;
417  }
418  // ------------------------------------------------------------------------
419  virtual void append(const void* const vertices, u32 numm_vertices,
420  const u16* const indices, u32 numm_indices) {}
421  // ------------------------------------------------------------------------
422  virtual void append(const IMeshBuffer* const other) {}
423  // ------------------------------------------------------------------------
424  virtual E_HARDWARE_MAPPING getHardwareMappingHint_Vertex() const
425  {
426  return EHM_NEVER;
427  }
428  // ------------------------------------------------------------------------
429  virtual E_HARDWARE_MAPPING getHardwareMappingHint_Index() const
430  {
431  return EHM_NEVER;
432  }
433  // ------------------------------------------------------------------------
434  virtual void setHardwareMappingHint(E_HARDWARE_MAPPING,
435  E_BUFFER_TYPE Buffer) {}
436  // ------------------------------------------------------------------------
437  virtual void setDirty(E_BUFFER_TYPE Buffer=EBT_VERTEX_AND_INDEX) {}
438  // ------------------------------------------------------------------------
439  virtual u32 getChangedID_Vertex() const { return 0; }
440  // ------------------------------------------------------------------------
441  virtual u32 getChangedID_Index() const { return 0; }
442  // ------------------------------------------------------------------------
443  void disableForMaterial(u32 idx) { std::get<1>(m_stk_material[idx]) = 0; }
444 
445 };
446 
447 }
448 
449 #endif
Definition: material.hpp:48
Definition: sp_instanced_data.hpp:32
Definition: sp_mesh_buffer.hpp:48
Definition: sp_per_object_uniform.hpp:31
Definition: sp_shader.hpp:81
Declares the general types that are used by the network.