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:
SPMeshBuffer()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     // ------------------------------------------------------------------------
draw(DrawCallType dct=DCT_NORMAL,int material_id=-1) const115     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             glDrawElementsInstanced(GL_TRIANGLES,
128                 std::get<1>(m_stk_material[material_id]),
129                 GL_UNSIGNED_SHORT,
130                 (void*)(std::get<0>(m_stk_material[material_id]) << 1),
131                 (unsigned)m_ins_dat[dct].size());
132         }
133 #endif
134     }
135     // ------------------------------------------------------------------------
136     virtual void uploadGLMesh();
137     // ------------------------------------------------------------------------
138     virtual void uploadInstanceData();
139     // ------------------------------------------------------------------------
combineMeshBuffer(SPMeshBuffer * spmb,bool different_material=true)140     bool combineMeshBuffer(SPMeshBuffer* spmb, bool different_material = true)
141     {
142         // We only use 16bit vertices
143         if (spmb->m_vertices.size() + m_vertices.size() > 65536)
144         {
145             return false;
146         }
147         const uint16_t old_vtx_count = (uint16_t)m_vertices.size();
148         m_vertices.insert(m_vertices.end(), spmb->m_vertices.begin(),
149             spmb->m_vertices.end());
150         for (uint16_t& idx : spmb->m_indices)
151         {
152             idx += old_vtx_count;
153         }
154         if (different_material)
155         {
156             m_stk_material.emplace_back(getIndexCount(), spmb->getIndexCount(),
157                 std::get<2>(spmb->m_stk_material[0]));
158         }
159         else
160         {
161             std::get<1>(m_stk_material[0]) += (unsigned)spmb->m_indices.size();
162         }
163         m_indices.insert(m_indices.end(), spmb->m_indices.begin(),
164             spmb->m_indices.end());
165         return true;
166     }
167     // ------------------------------------------------------------------------
168     void initDrawMaterial();
169     // ------------------------------------------------------------------------
enableSkinningData()170     void enableSkinningData()                             { m_skinned = true; }
171     // ------------------------------------------------------------------------
getSTKMaterial(unsigned first_index=0) const172     Material* getSTKMaterial(unsigned first_index = 0) const
173     {
174         for (unsigned i = 0; i < m_stk_material.size(); i++)
175         {
176             if (i == unsigned(m_stk_material.size() - 1) ||
177                 (first_index >= std::get<0>(m_stk_material[i]) &&
178                 first_index < std::get<0>(m_stk_material[i + 1])))
179             {
180                 return std::get<2>(m_stk_material[i]);
181             }
182         }
183         assert(false);
184         return NULL;
185     }
186     // ------------------------------------------------------------------------
187     void enableTextureMatrix(unsigned mat_id);
188     // ------------------------------------------------------------------------
189     std::array<std::shared_ptr<SPTexture>, 6>&
getSPTextures(unsigned first_index=0)190         getSPTextures(unsigned first_index = 0)
191     {
192         assert(m_stk_material.size() == m_textures.size());
193         for (unsigned i = 0; i < m_stk_material.size(); i++)
194         {
195             if (i == unsigned(m_stk_material.size() - 1) ||
196                 (first_index >= std::get<0>(m_stk_material[i]) &&
197                 first_index < std::get<0>(m_stk_material[i + 1])))
198             {
199                 return m_textures[i];
200             }
201         }
202         assert(false);
203         return m_textures[0];
204     }
205     // ------------------------------------------------------------------------
206     const std::array<std::shared_ptr<SPTexture>, 6>&
getSPTexturesByMaterialID(int material_id) const207         getSPTexturesByMaterialID(int material_id) const
208     {
209         assert((size_t)material_id < m_textures.size());
210         return m_textures[material_id];
211     }
212     // ------------------------------------------------------------------------
getAllSTKMaterials() const213     std::vector<Material*> getAllSTKMaterials() const
214     {
215         std::vector<Material*> ret;
216         for (unsigned i = 0; i < m_stk_material.size(); i++)
217         {
218             ret.push_back(std::get<2>(m_stk_material[i]));
219         }
220         return ret;
221     }
222     // ------------------------------------------------------------------------
getTextureCompare() const223     const std::unordered_map<std::string, unsigned>& getTextureCompare() const
224                                                           { return m_tex_cmp; }
225     // ------------------------------------------------------------------------
getMaterialID(const std::string & tex_cmp) const226     int getMaterialID(const std::string& tex_cmp) const
227     {
228         auto itr = m_tex_cmp.find(tex_cmp);
229         if (itr != m_tex_cmp.end())
230         {
231             return (int)itr->second;
232         }
233         return -1;
234     }
235     // ------------------------------------------------------------------------
addInstanceData(const SPInstancedData & id,DrawCallType dct)236     void addInstanceData(const SPInstancedData& id, DrawCallType dct)
237     {
238         if (m_uploaded_instance)
239         {
240             for (unsigned i = 0; i < DCT_FOR_VAO; i++)
241             {
242                 m_ins_dat[i].clear();
243                 m_uploaded_instance = false;
244             }
245         }
246         m_ins_dat[dct].push_back(id);
247     }
248     // ------------------------------------------------------------------------
249     void recreateVAO(unsigned i);
250     // ------------------------------------------------------------------------
getSPMVertex()251     video::S3DVertexSkinnedMesh* getSPMVertex()
252     {
253         return m_vertices.data();
254     }
255     // ------------------------------------------------------------------------
addSPMVertex(const video::S3DVertexSkinnedMesh & v)256     void addSPMVertex(const video::S3DVertexSkinnedMesh& v)
257     {
258         m_vertices.push_back(v);
259     }
260     // ------------------------------------------------------------------------
addIndex(uint16_t idx)261     void addIndex(uint16_t idx)
262     {
263         m_indices.push_back(idx);
264     }
265     // ------------------------------------------------------------------------
setSPMVertices(std::vector<video::S3DVertexSkinnedMesh> & vertices)266     void setSPMVertices(std::vector<video::S3DVertexSkinnedMesh>& vertices)
267     {
268         m_vertices = std::move(vertices);
269     }
270     // ------------------------------------------------------------------------
setIndices(std::vector<uint16_t> & indices)271     void setIndices(std::vector<uint16_t>& indices)
272     {
273         m_indices = std::move(indices);
274     }
275     // ------------------------------------------------------------------------
276     void setSTKMaterial(Material* m);
277     // ------------------------------------------------------------------------
278     void reloadTextureCompare();
279     // ------------------------------------------------------------------------
shrinkToFit()280     void shrinkToFit()
281     {
282         m_vertices.shrink_to_fit();
283         m_indices.shrink_to_fit();
284     }
285     // ------------------------------------------------------------------------
getShader(bool skinned=false) const286     SPShader* getShader(bool skinned = false) const
287                   { return skinned ? m_shaders[1].get() : m_shaders[0].get(); }
288     // ------------------------------------------------------------------------
getMaterial() const289     virtual const video::SMaterial& getMaterial() const
290     {
291         static video::SMaterial unused;
292         return unused;
293     }
294     // ------------------------------------------------------------------------
getMaterial()295     virtual video::SMaterial& getMaterial()
296     {
297         static video::SMaterial unused;
298         return unused;
299     }
300     // ------------------------------------------------------------------------
getVertices() const301     virtual const void* getVertices() const
302     {
303         return m_vertices.data();
304     }
305     // ------------------------------------------------------------------------
getVertices()306     virtual void* getVertices()
307     {
308         return m_vertices.data();
309     }
310     // ------------------------------------------------------------------------
getVertexCount() const311     virtual u32 getVertexCount() const
312     {
313         return (unsigned)m_vertices.size();
314     }
315     // ------------------------------------------------------------------------
getIndexType() const316     virtual video::E_INDEX_TYPE getIndexType() const
317     {
318         return video::EIT_16BIT;
319     }
320     // ------------------------------------------------------------------------
getIndices() const321     virtual const u16* getIndices() const
322     {
323         return m_indices.data();
324     }
325     // ------------------------------------------------------------------------
getIndices()326     virtual u16* getIndices()
327     {
328         return m_indices.data();
329     }
330     // ------------------------------------------------------------------------
getIndexCount() const331     virtual u32 getIndexCount() const
332     {
333         return (unsigned)m_indices.size();
334     }
335     // ------------------------------------------------------------------------
getBoundingBox() const336     virtual const core::aabbox3d<f32>& getBoundingBox() const
337     {
338         return m_bounding_box;
339     }
340     // ------------------------------------------------------------------------
setBoundingBox(const core::aabbox3df & box)341     virtual void setBoundingBox(const core::aabbox3df& box)
342     {
343         m_bounding_box = box;
344     }
345     // ------------------------------------------------------------------------
recalculateBoundingBox()346     virtual void recalculateBoundingBox()
347     {
348         if (m_vertices.empty())
349         {
350             m_bounding_box.reset(0.0f, 0.0f, 0.0f);
351         }
352         else
353         {
354             m_bounding_box.reset(m_vertices[0].m_position);
355             for (u32 i = 1; i < m_vertices.size(); i++)
356             {
357                 m_bounding_box.addInternalPoint(m_vertices[i].m_position);
358             }
359         }
360     }
361     // ------------------------------------------------------------------------
getVertexType() const362     virtual video::E_VERTEX_TYPE getVertexType() const
363     {
364         return video::EVT_SKINNED_MESH;
365     }
366     // ------------------------------------------------------------------------
getPosition(u32 i) const367     virtual const core::vector3df& getPosition(u32 i) const
368     {
369         return m_vertices[i].m_position;
370     }
371     // ------------------------------------------------------------------------
getPosition(u32 i)372     virtual core::vector3df& getPosition(u32 i)
373     {
374         return m_vertices[i].m_position;
375     }
376     // ------------------------------------------------------------------------
getNormal(u32 i) const377     virtual const core::vector3df& getNormal(u32 i) const
378     {
379         static core::vector3df unused;
380         return unused;
381     }
382     // ------------------------------------------------------------------------
getNormal(u32 i)383     virtual core::vector3df& getNormal(u32 i)
384     {
385         static core::vector3df unused;
386         return unused;
387     }
388     // ------------------------------------------------------------------------
getTCoords(u32 i) const389     virtual const core::vector2df& getTCoords(u32 i) const
390     {
391         static core::vector2df unused;
392         return unused;
393     }
394     // ------------------------------------------------------------------------
getTCoords(u32 i)395     virtual core::vector2df& getTCoords(u32 i)
396     {
397         static core::vector2df unused;
398         return unused;
399     }
400     // ------------------------------------------------------------------------
getPrimitiveType() const401     virtual scene::E_PRIMITIVE_TYPE getPrimitiveType() const
402     {
403         return EPT_TRIANGLES;
404     }
405     // ------------------------------------------------------------------------
append(const void * const vertices,u32 numm_vertices,const u16 * const indices,u32 numm_indices)406     virtual void append(const void* const vertices, u32 numm_vertices,
407                         const u16* const indices, u32 numm_indices) {}
408     // ------------------------------------------------------------------------
append(const IMeshBuffer * const other)409     virtual void append(const IMeshBuffer* const other) {}
410     // ------------------------------------------------------------------------
getHardwareMappingHint_Vertex() const411     virtual E_HARDWARE_MAPPING getHardwareMappingHint_Vertex() const
412     {
413         return EHM_NEVER;
414     }
415     // ------------------------------------------------------------------------
getHardwareMappingHint_Index() const416     virtual E_HARDWARE_MAPPING getHardwareMappingHint_Index() const
417     {
418         return EHM_NEVER;
419     }
420     // ------------------------------------------------------------------------
setHardwareMappingHint(E_HARDWARE_MAPPING,E_BUFFER_TYPE Buffer)421     virtual void setHardwareMappingHint(E_HARDWARE_MAPPING,
422                                         E_BUFFER_TYPE Buffer) {}
423     // ------------------------------------------------------------------------
setDirty(E_BUFFER_TYPE Buffer=EBT_VERTEX_AND_INDEX)424     virtual void setDirty(E_BUFFER_TYPE Buffer=EBT_VERTEX_AND_INDEX) {}
425     // ------------------------------------------------------------------------
getChangedID_Vertex() const426     virtual u32 getChangedID_Vertex() const { return 0; }
427     // ------------------------------------------------------------------------
getChangedID_Index() const428     virtual u32 getChangedID_Index() const { return 0; }
429 
430 };
431 
432 }
433 
434 #endif
435