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.hpp"
19 #include "graphics/sp/sp_animation.hpp"
20 #include "graphics/sp/sp_mesh_buffer.hpp"
21 #include "graphics/material.hpp"
22 #include "utils/mini_glm.hpp"
23
24 #include <algorithm>
25
26 namespace SP
27 {
28 // ----------------------------------------------------------------------------
SPMesh()29 SPMesh::SPMesh()
30 {
31 m_fps = 0.025f;
32 m_bind_frame = 0;
33 m_total_joints = 0;
34 m_joint_using = 0;
35 m_frame_count = 0;
36 } // SPMesh
37
38 // ----------------------------------------------------------------------------
~SPMesh()39 SPMesh::~SPMesh()
40 {
41 for (unsigned i=0; i < m_buffer.size(); i++)
42 {
43 if (m_buffer[i])
44 {
45 m_buffer[i]->drop();
46 }
47 }
48 } // ~SPMesh
49
50 // ----------------------------------------------------------------------------
getMeshBuffer(u32 nr) const51 IMeshBuffer* SPMesh::getMeshBuffer(u32 nr) const
52 {
53 if (nr < m_buffer.size())
54 {
55 return m_buffer[nr];
56 }
57 return NULL;
58 } // getMeshBuffer
59
60 // ----------------------------------------------------------------------------
getSPMeshBuffer(u32 nr) const61 SPMeshBuffer* SPMesh::getSPMeshBuffer(u32 nr) const
62 {
63 if (nr < m_buffer.size())
64 {
65 return m_buffer[nr];
66 }
67 return NULL;
68 } // getMeshBuffer
69
70 // ----------------------------------------------------------------------------
getMeshBuffer(const video::SMaterial & material) const71 IMeshBuffer* SPMesh::getMeshBuffer(const video::SMaterial &material) const
72 {
73 for (unsigned i = 0; i < m_buffer.size(); i++)
74 {
75 if (m_buffer[i]->getMaterial() == material)
76 {
77 return m_buffer[i];
78 }
79 }
80 return NULL;
81 } // getMeshBuffer
82
83 // ----------------------------------------------------------------------------
getJointName(u32 number) const84 const c8* SPMesh::getJointName(u32 number) const
85 {
86 if (number >= m_joint_using)
87 {
88 return "";
89 }
90 int i = 0;
91 int j = number;
92 while (j >= int(m_all_armatures[i].m_joint_used))
93 {
94 j -= int(m_all_armatures[i].m_joint_used);
95 i++;
96 }
97 return m_all_armatures.at(i).m_joint_names[j].c_str();
98
99 } // getJointName
100
101 // ----------------------------------------------------------------------------
getJointIDWithArm(const c8 * name,unsigned * arm_id) const102 s32 SPMesh::getJointIDWithArm(const c8* name, unsigned* arm_id) const
103 {
104 for (unsigned i = 0; i < m_all_armatures.size(); i++)
105 {
106 const Armature& arm = m_all_armatures[i];
107 auto found = std::find(arm.m_joint_names.begin(),
108 arm.m_joint_names.end(), name);
109 if (found != arm.m_joint_names.end())
110 {
111 if (arm_id != NULL)
112 {
113 *arm_id = i;
114 }
115 return (int)(found - arm.m_joint_names.begin());
116 }
117 }
118 return -1;
119 } // getJointIDWithArm
120
121 // ----------------------------------------------------------------------------
getSkinningMatrices(f32 frame,std::array<float,16> * dest)122 void SPMesh::getSkinningMatrices(f32 frame, std::array<float, 16>* dest)
123 {
124 unsigned accumulated_joints = 0;
125 for (unsigned i = 0; i < m_all_armatures.size(); i++)
126 {
127 m_all_armatures[i].getPose(frame, &dest[accumulated_joints]);
128 accumulated_joints += m_all_armatures[i].m_joint_used;
129 }
130
131 } // getSkinningMatrices
132
133 // ----------------------------------------------------------------------------
updateBoundingBox()134 void SPMesh::updateBoundingBox()
135 {
136 m_bounding_box.reset(0.0f, 0.0f, 0.0f);
137 for (unsigned i = 0; i < m_buffer.size(); i++)
138 {
139 m_buffer[i]->recalculateBoundingBox();
140 m_bounding_box.addInternalBox(m_buffer[i]->getBoundingBox());
141 }
142 } // updateBoundingBox
143
144 // ----------------------------------------------------------------------------
finalize()145 void SPMesh::finalize()
146 {
147 updateBoundingBox();
148 for (Armature& arm : getArmatures())
149 {
150 arm.getInterpolatedMatrices((float)m_bind_frame);
151 for (auto& p : arm.m_world_matrices)
152 {
153 p.second = false;
154 }
155 for (unsigned i = 0; i < arm.m_joint_names.size(); i++)
156 {
157 core::matrix4 m;
158 arm.getWorldMatrix(arm.m_interpolated_matrices, i).getInverse(m);
159 arm.m_joint_matrices[i] = m;
160 }
161 }
162 m_bounding_box.reset(0.0f, 0.0f, 0.0f);
163 // Sort with same shader name
164 std::sort(m_buffer.begin(), m_buffer.end(),
165 [](const SPMeshBuffer* a, const SPMeshBuffer* b)->bool
166 {
167 return a->getSTKMaterial()->getShaderName() <
168 b->getSTKMaterial()->getShaderName();
169 });
170
171 for (unsigned i = 0; i < m_buffer.size(); i++)
172 {
173 m_buffer[i]->recalculateBoundingBox();
174 m_bounding_box.addInternalBox(m_buffer[i]->getBoundingBox());
175 m_buffer[i]->initDrawMaterial();
176 if (!isStatic())
177 {
178 m_buffer[i]->enableSkinningData();
179 }
180 }
181
182 auto itr = m_buffer.begin();
183 while (itr != m_buffer.end())
184 {
185 auto itr_next = itr + 1;
186 if (itr_next != m_buffer.end() &&
187 (*itr)->getSTKMaterial()->getShaderName() ==
188 (*itr_next)->getSTKMaterial()->getShaderName())
189 {
190 if ((*itr)->combineMeshBuffer(*itr_next))
191 {
192 (*itr)->recalculateBoundingBox();
193 delete *itr_next;
194 m_buffer.erase(itr_next);
195 continue;
196 }
197 }
198 itr++;
199 }
200
201 for (unsigned i = 0; i < m_buffer.size(); i++)
202 {
203 m_buffer[i]->shrinkToFit();
204 }
205
206 } // finalize
207
208 }
209