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