rev |
line source |
nuclear@0
|
1 /*
|
nuclear@0
|
2 Open Asset Import Library (assimp)
|
nuclear@0
|
3 ----------------------------------------------------------------------
|
nuclear@0
|
4
|
nuclear@0
|
5 Copyright (c) 2006-2012, assimp team
|
nuclear@0
|
6 All rights reserved.
|
nuclear@0
|
7
|
nuclear@0
|
8 Redistribution and use of this software in source and binary forms,
|
nuclear@0
|
9 with or without modification, are permitted provided that the
|
nuclear@0
|
10 following conditions are met:
|
nuclear@0
|
11
|
nuclear@0
|
12 * Redistributions of source code must retain the above
|
nuclear@0
|
13 copyright notice, this list of conditions and the
|
nuclear@0
|
14 following disclaimer.
|
nuclear@0
|
15
|
nuclear@0
|
16 * Redistributions in binary form must reproduce the above
|
nuclear@0
|
17 copyright notice, this list of conditions and the
|
nuclear@0
|
18 following disclaimer in the documentation and/or other
|
nuclear@0
|
19 materials provided with the distribution.
|
nuclear@0
|
20
|
nuclear@0
|
21 * Neither the name of the assimp team, nor the names of its
|
nuclear@0
|
22 contributors may be used to endorse or promote products
|
nuclear@0
|
23 derived from this software without specific prior
|
nuclear@0
|
24 written permission of the assimp team.
|
nuclear@0
|
25
|
nuclear@0
|
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
nuclear@0
|
27 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
nuclear@0
|
28 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
nuclear@0
|
29 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
nuclear@0
|
30 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
nuclear@0
|
31 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
nuclear@0
|
32 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
nuclear@0
|
33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
nuclear@0
|
34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
nuclear@0
|
35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
nuclear@0
|
36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
nuclear@0
|
37
|
nuclear@0
|
38 ----------------------------------------------------------------------
|
nuclear@0
|
39 */
|
nuclear@0
|
40
|
nuclear@0
|
41
|
nuclear@0
|
42 /** @file Implementation of the SplitLargeMeshes postprocessing step
|
nuclear@0
|
43 */
|
nuclear@0
|
44
|
nuclear@0
|
45 #include "AssimpPCH.h"
|
nuclear@0
|
46
|
nuclear@0
|
47 // internal headers of the post-processing framework
|
nuclear@0
|
48 #include "SplitLargeMeshes.h"
|
nuclear@0
|
49 #include "ProcessHelper.h"
|
nuclear@0
|
50
|
nuclear@0
|
51 using namespace Assimp;
|
nuclear@0
|
52
|
nuclear@0
|
53
|
nuclear@0
|
54 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
55 SplitLargeMeshesProcess_Triangle::SplitLargeMeshesProcess_Triangle()
|
nuclear@0
|
56 {
|
nuclear@0
|
57 LIMIT = AI_SLM_DEFAULT_MAX_TRIANGLES;
|
nuclear@0
|
58 }
|
nuclear@0
|
59
|
nuclear@0
|
60 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
61 SplitLargeMeshesProcess_Triangle::~SplitLargeMeshesProcess_Triangle()
|
nuclear@0
|
62 {
|
nuclear@0
|
63 // nothing to do here
|
nuclear@0
|
64 }
|
nuclear@0
|
65
|
nuclear@0
|
66 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
67 // Returns whether the processing step is present in the given flag field.
|
nuclear@0
|
68 bool SplitLargeMeshesProcess_Triangle::IsActive( unsigned int pFlags) const
|
nuclear@0
|
69 {
|
nuclear@0
|
70 return (pFlags & aiProcess_SplitLargeMeshes) != 0;
|
nuclear@0
|
71 }
|
nuclear@0
|
72
|
nuclear@0
|
73 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
74 // Executes the post processing step on the given imported data.
|
nuclear@0
|
75 void SplitLargeMeshesProcess_Triangle::Execute( aiScene* pScene)
|
nuclear@0
|
76 {
|
nuclear@0
|
77 if (0xffffffff == this->LIMIT)return;
|
nuclear@0
|
78
|
nuclear@0
|
79 DefaultLogger::get()->debug("SplitLargeMeshesProcess_Triangle begin");
|
nuclear@0
|
80 std::vector<std::pair<aiMesh*, unsigned int> > avList;
|
nuclear@0
|
81
|
nuclear@0
|
82 for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
|
nuclear@0
|
83 this->SplitMesh(a, pScene->mMeshes[a],avList);
|
nuclear@0
|
84
|
nuclear@0
|
85 if (avList.size() != pScene->mNumMeshes)
|
nuclear@0
|
86 {
|
nuclear@0
|
87 // it seems something has been split. rebuild the mesh list
|
nuclear@0
|
88 delete[] pScene->mMeshes;
|
nuclear@0
|
89 pScene->mNumMeshes = (unsigned int)avList.size();
|
nuclear@0
|
90 pScene->mMeshes = new aiMesh*[avList.size()];
|
nuclear@0
|
91
|
nuclear@0
|
92 for (unsigned int i = 0; i < avList.size();++i)
|
nuclear@0
|
93 pScene->mMeshes[i] = avList[i].first;
|
nuclear@0
|
94
|
nuclear@0
|
95 // now we need to update all nodes
|
nuclear@0
|
96 this->UpdateNode(pScene->mRootNode,avList);
|
nuclear@0
|
97 DefaultLogger::get()->info("SplitLargeMeshesProcess_Triangle finished. Meshes have been split");
|
nuclear@0
|
98 }
|
nuclear@0
|
99 else DefaultLogger::get()->debug("SplitLargeMeshesProcess_Triangle finished. There was nothing to do");
|
nuclear@0
|
100 return;
|
nuclear@0
|
101 }
|
nuclear@0
|
102
|
nuclear@0
|
103 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
104 // Setup properties
|
nuclear@0
|
105 void SplitLargeMeshesProcess_Triangle::SetupProperties( const Importer* pImp)
|
nuclear@0
|
106 {
|
nuclear@0
|
107 // get the current value of the split property
|
nuclear@0
|
108 this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES);
|
nuclear@0
|
109 }
|
nuclear@0
|
110
|
nuclear@0
|
111 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
112 // Update a node after some meshes have been split
|
nuclear@0
|
113 void SplitLargeMeshesProcess_Triangle::UpdateNode(aiNode* pcNode,
|
nuclear@0
|
114 const std::vector<std::pair<aiMesh*, unsigned int> >& avList)
|
nuclear@0
|
115 {
|
nuclear@0
|
116 // for every index in out list build a new entry
|
nuclear@0
|
117 std::vector<unsigned int> aiEntries;
|
nuclear@0
|
118 aiEntries.reserve(pcNode->mNumMeshes + 1);
|
nuclear@0
|
119 for (unsigned int i = 0; i < pcNode->mNumMeshes;++i)
|
nuclear@0
|
120 {
|
nuclear@0
|
121 for (unsigned int a = 0; a < avList.size();++a)
|
nuclear@0
|
122 {
|
nuclear@0
|
123 if (avList[a].second == pcNode->mMeshes[i])
|
nuclear@0
|
124 {
|
nuclear@0
|
125 aiEntries.push_back(a);
|
nuclear@0
|
126 }
|
nuclear@0
|
127 }
|
nuclear@0
|
128 }
|
nuclear@0
|
129
|
nuclear@0
|
130 // now build the new list
|
nuclear@0
|
131 delete pcNode->mMeshes;
|
nuclear@0
|
132 pcNode->mNumMeshes = (unsigned int)aiEntries.size();
|
nuclear@0
|
133 pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
|
nuclear@0
|
134
|
nuclear@0
|
135 for (unsigned int b = 0; b < pcNode->mNumMeshes;++b)
|
nuclear@0
|
136 pcNode->mMeshes[b] = aiEntries[b];
|
nuclear@0
|
137
|
nuclear@0
|
138 // recusively update all other nodes
|
nuclear@0
|
139 for (unsigned int i = 0; i < pcNode->mNumChildren;++i)
|
nuclear@0
|
140 {
|
nuclear@0
|
141 UpdateNode ( pcNode->mChildren[i], avList );
|
nuclear@0
|
142 }
|
nuclear@0
|
143 return;
|
nuclear@0
|
144 }
|
nuclear@0
|
145
|
nuclear@0
|
146 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
147 // Executes the post processing step on the given imported data.
|
nuclear@0
|
148 void SplitLargeMeshesProcess_Triangle::SplitMesh(
|
nuclear@0
|
149 unsigned int a,
|
nuclear@0
|
150 aiMesh* pMesh,
|
nuclear@0
|
151 std::vector<std::pair<aiMesh*, unsigned int> >& avList)
|
nuclear@0
|
152 {
|
nuclear@0
|
153 if (pMesh->mNumFaces > SplitLargeMeshesProcess_Triangle::LIMIT)
|
nuclear@0
|
154 {
|
nuclear@0
|
155 DefaultLogger::get()->info("Mesh exceeds the triangle limit. It will be split ...");
|
nuclear@0
|
156
|
nuclear@0
|
157 // we need to split this mesh into sub meshes
|
nuclear@0
|
158 // determine the size of a submesh
|
nuclear@0
|
159 const unsigned int iSubMeshes = (pMesh->mNumFaces / LIMIT) + 1;
|
nuclear@0
|
160
|
nuclear@0
|
161 const unsigned int iOutFaceNum = pMesh->mNumFaces / iSubMeshes;
|
nuclear@0
|
162 const unsigned int iOutVertexNum = iOutFaceNum * 3;
|
nuclear@0
|
163
|
nuclear@0
|
164 // now generate all submeshes
|
nuclear@0
|
165 for (unsigned int i = 0; i < iSubMeshes;++i)
|
nuclear@0
|
166 {
|
nuclear@0
|
167 aiMesh* pcMesh = new aiMesh;
|
nuclear@0
|
168 pcMesh->mNumFaces = iOutFaceNum;
|
nuclear@0
|
169 pcMesh->mMaterialIndex = pMesh->mMaterialIndex;
|
nuclear@0
|
170
|
nuclear@0
|
171 // the name carries the adjacency information between the meshes
|
nuclear@0
|
172 pcMesh->mName = pMesh->mName;
|
nuclear@0
|
173
|
nuclear@0
|
174 if (i == iSubMeshes-1)
|
nuclear@0
|
175 {
|
nuclear@0
|
176 pcMesh->mNumFaces = iOutFaceNum + (
|
nuclear@0
|
177 pMesh->mNumFaces - iOutFaceNum * iSubMeshes);
|
nuclear@0
|
178 }
|
nuclear@0
|
179 // copy the list of faces
|
nuclear@0
|
180 pcMesh->mFaces = new aiFace[pcMesh->mNumFaces];
|
nuclear@0
|
181
|
nuclear@0
|
182 const unsigned int iBase = iOutFaceNum * i;
|
nuclear@0
|
183
|
nuclear@0
|
184 // get the total number of indices
|
nuclear@0
|
185 unsigned int iCnt = 0;
|
nuclear@0
|
186 for (unsigned int p = iBase; p < pcMesh->mNumFaces + iBase;++p)
|
nuclear@0
|
187 {
|
nuclear@0
|
188 iCnt += pMesh->mFaces[p].mNumIndices;
|
nuclear@0
|
189 }
|
nuclear@0
|
190 pcMesh->mNumVertices = iCnt;
|
nuclear@0
|
191
|
nuclear@0
|
192 // allocate storage
|
nuclear@0
|
193 if (pMesh->mVertices != NULL)
|
nuclear@0
|
194 pcMesh->mVertices = new aiVector3D[iCnt];
|
nuclear@0
|
195
|
nuclear@0
|
196 if (pMesh->HasNormals())
|
nuclear@0
|
197 pcMesh->mNormals = new aiVector3D[iCnt];
|
nuclear@0
|
198
|
nuclear@0
|
199 if (pMesh->HasTangentsAndBitangents())
|
nuclear@0
|
200 {
|
nuclear@0
|
201 pcMesh->mTangents = new aiVector3D[iCnt];
|
nuclear@0
|
202 pcMesh->mBitangents = new aiVector3D[iCnt];
|
nuclear@0
|
203 }
|
nuclear@0
|
204
|
nuclear@0
|
205 // texture coordinates
|
nuclear@0
|
206 for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)
|
nuclear@0
|
207 {
|
nuclear@0
|
208 pcMesh->mNumUVComponents[c] = pMesh->mNumUVComponents[c];
|
nuclear@0
|
209 if (pMesh->HasTextureCoords( c))
|
nuclear@0
|
210 {
|
nuclear@0
|
211 pcMesh->mTextureCoords[c] = new aiVector3D[iCnt];
|
nuclear@0
|
212 }
|
nuclear@0
|
213 }
|
nuclear@0
|
214
|
nuclear@0
|
215 // vertex colors
|
nuclear@0
|
216 for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS;++c)
|
nuclear@0
|
217 {
|
nuclear@0
|
218 if (pMesh->HasVertexColors( c))
|
nuclear@0
|
219 {
|
nuclear@0
|
220 pcMesh->mColors[c] = new aiColor4D[iCnt];
|
nuclear@0
|
221 }
|
nuclear@0
|
222 }
|
nuclear@0
|
223
|
nuclear@0
|
224 if (pMesh->HasBones())
|
nuclear@0
|
225 {
|
nuclear@0
|
226 // assume the number of bones won't change in most cases
|
nuclear@0
|
227 pcMesh->mBones = new aiBone*[pMesh->mNumBones];
|
nuclear@0
|
228
|
nuclear@0
|
229 // iterate through all bones of the mesh and find those which
|
nuclear@0
|
230 // need to be copied to the split mesh
|
nuclear@0
|
231 std::vector<aiVertexWeight> avTempWeights;
|
nuclear@0
|
232 for (unsigned int p = 0; p < pcMesh->mNumBones;++p)
|
nuclear@0
|
233 {
|
nuclear@0
|
234 aiBone* const bone = pcMesh->mBones[p];
|
nuclear@0
|
235 avTempWeights.clear();
|
nuclear@0
|
236 avTempWeights.reserve(bone->mNumWeights / iSubMeshes);
|
nuclear@0
|
237
|
nuclear@0
|
238 for (unsigned int q = 0; q < bone->mNumWeights;++q)
|
nuclear@0
|
239 {
|
nuclear@0
|
240 aiVertexWeight& weight = bone->mWeights[q];
|
nuclear@0
|
241 if(weight.mVertexId >= iBase && weight.mVertexId < iBase + iOutVertexNum)
|
nuclear@0
|
242 {
|
nuclear@0
|
243 avTempWeights.push_back(weight);
|
nuclear@0
|
244 weight = avTempWeights.back();
|
nuclear@0
|
245 weight.mVertexId -= iBase;
|
nuclear@0
|
246 }
|
nuclear@0
|
247 }
|
nuclear@0
|
248
|
nuclear@0
|
249 if (!avTempWeights.empty())
|
nuclear@0
|
250 {
|
nuclear@0
|
251 // we'll need this bone. Copy it ...
|
nuclear@0
|
252 aiBone* pc = new aiBone();
|
nuclear@0
|
253 pcMesh->mBones[pcMesh->mNumBones++] = pc;
|
nuclear@0
|
254 pc->mName = aiString(bone->mName);
|
nuclear@0
|
255 pc->mNumWeights = (unsigned int)avTempWeights.size();
|
nuclear@0
|
256 pc->mOffsetMatrix = bone->mOffsetMatrix;
|
nuclear@0
|
257
|
nuclear@0
|
258 // no need to reallocate the array for the last submesh.
|
nuclear@0
|
259 // Here we can reuse the (large) source array, although
|
nuclear@0
|
260 // we'll waste some memory
|
nuclear@0
|
261 if (iSubMeshes-1 == i)
|
nuclear@0
|
262 {
|
nuclear@0
|
263 pc->mWeights = bone->mWeights;
|
nuclear@0
|
264 bone->mWeights = NULL;
|
nuclear@0
|
265 }
|
nuclear@0
|
266 else pc->mWeights = new aiVertexWeight[pc->mNumWeights];
|
nuclear@0
|
267
|
nuclear@0
|
268 // copy the weights
|
nuclear@0
|
269 ::memcpy(pc->mWeights,&avTempWeights[0],sizeof(aiVertexWeight)*pc->mNumWeights);
|
nuclear@0
|
270 }
|
nuclear@0
|
271 }
|
nuclear@0
|
272 }
|
nuclear@0
|
273
|
nuclear@0
|
274 // (we will also need to copy the array of indices)
|
nuclear@0
|
275 unsigned int iCurrent = 0;
|
nuclear@0
|
276 for (unsigned int p = 0; p < pcMesh->mNumFaces;++p)
|
nuclear@0
|
277 {
|
nuclear@0
|
278 pcMesh->mFaces[p].mNumIndices = 3;
|
nuclear@0
|
279 // allocate a new array
|
nuclear@0
|
280 const unsigned int iTemp = p + iBase;
|
nuclear@0
|
281 const unsigned int iNumIndices = pMesh->mFaces[iTemp].mNumIndices;
|
nuclear@0
|
282
|
nuclear@0
|
283 // setup face type and number of indices
|
nuclear@0
|
284 pcMesh->mFaces[p].mNumIndices = iNumIndices;
|
nuclear@0
|
285 unsigned int* pi = pMesh->mFaces[iTemp].mIndices;
|
nuclear@0
|
286 unsigned int* piOut = pcMesh->mFaces[p].mIndices = new unsigned int[iNumIndices];
|
nuclear@0
|
287
|
nuclear@0
|
288 // need to update the output primitive types
|
nuclear@0
|
289 switch (iNumIndices)
|
nuclear@0
|
290 {
|
nuclear@0
|
291 case 1:
|
nuclear@0
|
292 pcMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
|
nuclear@0
|
293 break;
|
nuclear@0
|
294 case 2:
|
nuclear@0
|
295 pcMesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
|
nuclear@0
|
296 break;
|
nuclear@0
|
297 case 3:
|
nuclear@0
|
298 pcMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
|
nuclear@0
|
299 break;
|
nuclear@0
|
300 default:
|
nuclear@0
|
301 pcMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
|
nuclear@0
|
302 }
|
nuclear@0
|
303
|
nuclear@0
|
304 // and copy the contents of the old array, offset by current base
|
nuclear@0
|
305 for (unsigned int v = 0; v < iNumIndices;++v)
|
nuclear@0
|
306 {
|
nuclear@0
|
307 unsigned int iIndex = pi[v];
|
nuclear@0
|
308 unsigned int iIndexOut = iCurrent++;
|
nuclear@0
|
309 piOut[v] = iIndexOut;
|
nuclear@0
|
310
|
nuclear@0
|
311 // copy positions
|
nuclear@0
|
312 if (pMesh->mVertices != NULL)
|
nuclear@0
|
313 pcMesh->mVertices[iIndexOut] = pMesh->mVertices[iIndex];
|
nuclear@0
|
314
|
nuclear@0
|
315 // copy normals
|
nuclear@0
|
316 if (pMesh->HasNormals())
|
nuclear@0
|
317 pcMesh->mNormals[iIndexOut] = pMesh->mNormals[iIndex];
|
nuclear@0
|
318
|
nuclear@0
|
319 // copy tangents/bitangents
|
nuclear@0
|
320 if (pMesh->HasTangentsAndBitangents())
|
nuclear@0
|
321 {
|
nuclear@0
|
322 pcMesh->mTangents[iIndexOut] = pMesh->mTangents[iIndex];
|
nuclear@0
|
323 pcMesh->mBitangents[iIndexOut] = pMesh->mBitangents[iIndex];
|
nuclear@0
|
324 }
|
nuclear@0
|
325
|
nuclear@0
|
326 // texture coordinates
|
nuclear@0
|
327 for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)
|
nuclear@0
|
328 {
|
nuclear@0
|
329 if (pMesh->HasTextureCoords( c))
|
nuclear@0
|
330 pcMesh->mTextureCoords[c][iIndexOut] = pMesh->mTextureCoords[c][iIndex];
|
nuclear@0
|
331 }
|
nuclear@0
|
332 // vertex colors
|
nuclear@0
|
333 for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS;++c)
|
nuclear@0
|
334 {
|
nuclear@0
|
335 if (pMesh->HasVertexColors( c))
|
nuclear@0
|
336 pcMesh->mColors[c][iIndexOut] = pMesh->mColors[c][iIndex];
|
nuclear@0
|
337 }
|
nuclear@0
|
338 }
|
nuclear@0
|
339 }
|
nuclear@0
|
340
|
nuclear@0
|
341 // add the newly created mesh to the list
|
nuclear@0
|
342 avList.push_back(std::pair<aiMesh*, unsigned int>(pcMesh,a));
|
nuclear@0
|
343 }
|
nuclear@0
|
344
|
nuclear@0
|
345 // now delete the old mesh data
|
nuclear@0
|
346 delete pMesh;
|
nuclear@0
|
347 }
|
nuclear@0
|
348 else avList.push_back(std::pair<aiMesh*, unsigned int>(pMesh,a));
|
nuclear@0
|
349 return;
|
nuclear@0
|
350 }
|
nuclear@0
|
351
|
nuclear@0
|
352 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
353 SplitLargeMeshesProcess_Vertex::SplitLargeMeshesProcess_Vertex()
|
nuclear@0
|
354 {
|
nuclear@0
|
355 LIMIT = AI_SLM_DEFAULT_MAX_VERTICES;
|
nuclear@0
|
356 }
|
nuclear@0
|
357
|
nuclear@0
|
358 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
359 SplitLargeMeshesProcess_Vertex::~SplitLargeMeshesProcess_Vertex()
|
nuclear@0
|
360 {
|
nuclear@0
|
361 // nothing to do here
|
nuclear@0
|
362 }
|
nuclear@0
|
363
|
nuclear@0
|
364 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
365 // Returns whether the processing step is present in the given flag field.
|
nuclear@0
|
366 bool SplitLargeMeshesProcess_Vertex::IsActive( unsigned int pFlags) const
|
nuclear@0
|
367 {
|
nuclear@0
|
368 return (pFlags & aiProcess_SplitLargeMeshes) != 0;
|
nuclear@0
|
369 }
|
nuclear@0
|
370
|
nuclear@0
|
371 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
372 // Executes the post processing step on the given imported data.
|
nuclear@0
|
373 void SplitLargeMeshesProcess_Vertex::Execute( aiScene* pScene)
|
nuclear@0
|
374 {
|
nuclear@0
|
375 std::vector<std::pair<aiMesh*, unsigned int> > avList;
|
nuclear@0
|
376
|
nuclear@0
|
377 if (0xffffffff == this->LIMIT)return;
|
nuclear@0
|
378
|
nuclear@0
|
379 DefaultLogger::get()->debug("SplitLargeMeshesProcess_Vertex begin");
|
nuclear@0
|
380 for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
|
nuclear@0
|
381 this->SplitMesh(a, pScene->mMeshes[a],avList);
|
nuclear@0
|
382
|
nuclear@0
|
383 if (avList.size() != pScene->mNumMeshes)
|
nuclear@0
|
384 {
|
nuclear@0
|
385 // it seems something has been split. rebuild the mesh list
|
nuclear@0
|
386 delete[] pScene->mMeshes;
|
nuclear@0
|
387 pScene->mNumMeshes = (unsigned int)avList.size();
|
nuclear@0
|
388 pScene->mMeshes = new aiMesh*[avList.size()];
|
nuclear@0
|
389
|
nuclear@0
|
390 for (unsigned int i = 0; i < avList.size();++i)
|
nuclear@0
|
391 pScene->mMeshes[i] = avList[i].first;
|
nuclear@0
|
392
|
nuclear@0
|
393 // now we need to update all nodes
|
nuclear@0
|
394 SplitLargeMeshesProcess_Triangle::UpdateNode(pScene->mRootNode,avList);
|
nuclear@0
|
395 DefaultLogger::get()->info("SplitLargeMeshesProcess_Vertex finished. Meshes have been split");
|
nuclear@0
|
396 }
|
nuclear@0
|
397 else DefaultLogger::get()->debug("SplitLargeMeshesProcess_Vertex finished. There was nothing to do");
|
nuclear@0
|
398 return;
|
nuclear@0
|
399 }
|
nuclear@0
|
400
|
nuclear@0
|
401 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
402 // Setup properties
|
nuclear@0
|
403 void SplitLargeMeshesProcess_Vertex::SetupProperties( const Importer* pImp)
|
nuclear@0
|
404 {
|
nuclear@0
|
405 this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES);
|
nuclear@0
|
406 }
|
nuclear@0
|
407
|
nuclear@0
|
408 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
409 // Executes the post processing step on the given imported data.
|
nuclear@0
|
410 void SplitLargeMeshesProcess_Vertex::SplitMesh(
|
nuclear@0
|
411 unsigned int a,
|
nuclear@0
|
412 aiMesh* pMesh,
|
nuclear@0
|
413 std::vector<std::pair<aiMesh*, unsigned int> >& avList)
|
nuclear@0
|
414 {
|
nuclear@0
|
415 if (pMesh->mNumVertices > SplitLargeMeshesProcess_Vertex::LIMIT)
|
nuclear@0
|
416 {
|
nuclear@0
|
417 typedef std::vector< std::pair<unsigned int,float> > VertexWeightTable;
|
nuclear@0
|
418
|
nuclear@0
|
419 // build a per-vertex weight list if necessary
|
nuclear@0
|
420 VertexWeightTable* avPerVertexWeights = ComputeVertexBoneWeightTable(pMesh);
|
nuclear@0
|
421
|
nuclear@0
|
422 // we need to split this mesh into sub meshes
|
nuclear@0
|
423 // determine the estimated size of a submesh
|
nuclear@0
|
424 // (this could be too large. Max waste is a single digit percentage)
|
nuclear@0
|
425 const unsigned int iSubMeshes = (pMesh->mNumVertices / SplitLargeMeshesProcess_Vertex::LIMIT) + 1;
|
nuclear@0
|
426 //const unsigned int iOutVertexNum2 = pMesh->mNumVertices /iSubMeshes;
|
nuclear@0
|
427
|
nuclear@0
|
428 // create a std::vector<unsigned int> to indicate which vertices
|
nuclear@0
|
429 // have already been copied
|
nuclear@0
|
430 std::vector<unsigned int> avWasCopied;
|
nuclear@0
|
431 avWasCopied.resize(pMesh->mNumVertices,0xFFFFFFFF);
|
nuclear@0
|
432
|
nuclear@0
|
433 // try to find a good estimate for the number of output faces
|
nuclear@0
|
434 // per mesh. Add 12.5% as buffer
|
nuclear@0
|
435 unsigned int iEstimatedSize = pMesh->mNumFaces / iSubMeshes;
|
nuclear@0
|
436 iEstimatedSize += iEstimatedSize >> 3;
|
nuclear@0
|
437
|
nuclear@0
|
438 // now generate all submeshes
|
nuclear@0
|
439 unsigned int iBase = 0;
|
nuclear@0
|
440 while (true)
|
nuclear@0
|
441 {
|
nuclear@0
|
442 const unsigned int iOutVertexNum = SplitLargeMeshesProcess_Vertex::LIMIT;
|
nuclear@0
|
443
|
nuclear@0
|
444 aiMesh* pcMesh = new aiMesh;
|
nuclear@0
|
445 pcMesh->mNumVertices = 0;
|
nuclear@0
|
446 pcMesh->mMaterialIndex = pMesh->mMaterialIndex;
|
nuclear@0
|
447
|
nuclear@0
|
448 // the name carries the adjacency information between the meshes
|
nuclear@0
|
449 pcMesh->mName = pMesh->mName;
|
nuclear@0
|
450
|
nuclear@0
|
451 typedef std::vector<aiVertexWeight> BoneWeightList;
|
nuclear@0
|
452 if (pMesh->HasBones())
|
nuclear@0
|
453 {
|
nuclear@0
|
454 pcMesh->mBones = new aiBone*[pMesh->mNumBones];
|
nuclear@0
|
455 ::memset(pcMesh->mBones,0,sizeof(void*)*pMesh->mNumBones);
|
nuclear@0
|
456 }
|
nuclear@0
|
457
|
nuclear@0
|
458 // clear the temporary helper array
|
nuclear@0
|
459 if (iBase)
|
nuclear@0
|
460 {
|
nuclear@0
|
461 // we can't use memset here we unsigned int needn' be 32 bits
|
nuclear@0
|
462 for (std::vector<unsigned int>::iterator
|
nuclear@0
|
463 iter = avWasCopied.begin(),end = avWasCopied.end();
|
nuclear@0
|
464 iter != end;++iter)
|
nuclear@0
|
465 {
|
nuclear@0
|
466 (*iter) = 0xffffffff;
|
nuclear@0
|
467 }
|
nuclear@0
|
468 }
|
nuclear@0
|
469
|
nuclear@0
|
470 // output vectors
|
nuclear@0
|
471 std::vector<aiFace> vFaces;
|
nuclear@0
|
472
|
nuclear@0
|
473 // reserve enough storage for most cases
|
nuclear@0
|
474 if (pMesh->HasPositions())
|
nuclear@0
|
475 {
|
nuclear@0
|
476 pcMesh->mVertices = new aiVector3D[iOutVertexNum];
|
nuclear@0
|
477 }
|
nuclear@0
|
478 if (pMesh->HasNormals())
|
nuclear@0
|
479 {
|
nuclear@0
|
480 pcMesh->mNormals = new aiVector3D[iOutVertexNum];
|
nuclear@0
|
481 }
|
nuclear@0
|
482 if (pMesh->HasTangentsAndBitangents())
|
nuclear@0
|
483 {
|
nuclear@0
|
484 pcMesh->mTangents = new aiVector3D[iOutVertexNum];
|
nuclear@0
|
485 pcMesh->mBitangents = new aiVector3D[iOutVertexNum];
|
nuclear@0
|
486 }
|
nuclear@0
|
487 for (unsigned int c = 0; pMesh->HasVertexColors(c);++c)
|
nuclear@0
|
488 {
|
nuclear@0
|
489 pcMesh->mColors[c] = new aiColor4D[iOutVertexNum];
|
nuclear@0
|
490 }
|
nuclear@0
|
491 for (unsigned int c = 0; pMesh->HasTextureCoords(c);++c)
|
nuclear@0
|
492 {
|
nuclear@0
|
493 pcMesh->mNumUVComponents[c] = pMesh->mNumUVComponents[c];
|
nuclear@0
|
494 pcMesh->mTextureCoords[c] = new aiVector3D[iOutVertexNum];
|
nuclear@0
|
495 }
|
nuclear@0
|
496 vFaces.reserve(iEstimatedSize);
|
nuclear@0
|
497
|
nuclear@0
|
498 // (we will also need to copy the array of indices)
|
nuclear@0
|
499 while (iBase < pMesh->mNumFaces)
|
nuclear@0
|
500 {
|
nuclear@0
|
501 // allocate a new array
|
nuclear@0
|
502 const unsigned int iNumIndices = pMesh->mFaces[iBase].mNumIndices;
|
nuclear@0
|
503
|
nuclear@0
|
504 // doesn't catch degenerates but is quite fast
|
nuclear@0
|
505 unsigned int iNeed = 0;
|
nuclear@0
|
506 for (unsigned int v = 0; v < iNumIndices;++v)
|
nuclear@0
|
507 {
|
nuclear@0
|
508 unsigned int iIndex = pMesh->mFaces[iBase].mIndices[v];
|
nuclear@0
|
509
|
nuclear@0
|
510 // check whether we do already have this vertex
|
nuclear@0
|
511 if (0xFFFFFFFF == avWasCopied[iIndex])
|
nuclear@0
|
512 {
|
nuclear@0
|
513 iNeed++;
|
nuclear@0
|
514 }
|
nuclear@0
|
515 }
|
nuclear@0
|
516 if (pcMesh->mNumVertices + iNeed > iOutVertexNum)
|
nuclear@0
|
517 {
|
nuclear@0
|
518 // don't use this face
|
nuclear@0
|
519 break;
|
nuclear@0
|
520 }
|
nuclear@0
|
521
|
nuclear@0
|
522 vFaces.push_back(aiFace());
|
nuclear@0
|
523 aiFace& rFace = vFaces.back();
|
nuclear@0
|
524
|
nuclear@0
|
525 // setup face type and number of indices
|
nuclear@0
|
526 rFace.mNumIndices = iNumIndices;
|
nuclear@0
|
527 rFace.mIndices = new unsigned int[iNumIndices];
|
nuclear@0
|
528
|
nuclear@0
|
529 // need to update the output primitive types
|
nuclear@0
|
530 switch (rFace.mNumIndices)
|
nuclear@0
|
531 {
|
nuclear@0
|
532 case 1:
|
nuclear@0
|
533 pcMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
|
nuclear@0
|
534 break;
|
nuclear@0
|
535 case 2:
|
nuclear@0
|
536 pcMesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
|
nuclear@0
|
537 break;
|
nuclear@0
|
538 case 3:
|
nuclear@0
|
539 pcMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
|
nuclear@0
|
540 break;
|
nuclear@0
|
541 default:
|
nuclear@0
|
542 pcMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
|
nuclear@0
|
543 }
|
nuclear@0
|
544
|
nuclear@0
|
545 // and copy the contents of the old array, offset by current base
|
nuclear@0
|
546 for (unsigned int v = 0; v < iNumIndices;++v)
|
nuclear@0
|
547 {
|
nuclear@0
|
548 unsigned int iIndex = pMesh->mFaces[iBase].mIndices[v];
|
nuclear@0
|
549
|
nuclear@0
|
550 // check whether we do already have this vertex
|
nuclear@0
|
551 if (0xFFFFFFFF != avWasCopied[iIndex])
|
nuclear@0
|
552 {
|
nuclear@0
|
553 rFace.mIndices[v] = avWasCopied[iIndex];
|
nuclear@0
|
554 continue;
|
nuclear@0
|
555 }
|
nuclear@0
|
556
|
nuclear@0
|
557 // copy positions
|
nuclear@0
|
558 pcMesh->mVertices[pcMesh->mNumVertices] = (pMesh->mVertices[iIndex]);
|
nuclear@0
|
559
|
nuclear@0
|
560 // copy normals
|
nuclear@0
|
561 if (pMesh->HasNormals())
|
nuclear@0
|
562 {
|
nuclear@0
|
563 pcMesh->mNormals[pcMesh->mNumVertices] = (pMesh->mNormals[iIndex]);
|
nuclear@0
|
564 }
|
nuclear@0
|
565
|
nuclear@0
|
566 // copy tangents/bitangents
|
nuclear@0
|
567 if (pMesh->HasTangentsAndBitangents())
|
nuclear@0
|
568 {
|
nuclear@0
|
569 pcMesh->mTangents[pcMesh->mNumVertices] = (pMesh->mTangents[iIndex]);
|
nuclear@0
|
570 pcMesh->mBitangents[pcMesh->mNumVertices] = (pMesh->mBitangents[iIndex]);
|
nuclear@0
|
571 }
|
nuclear@0
|
572
|
nuclear@0
|
573 // texture coordinates
|
nuclear@0
|
574 for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)
|
nuclear@0
|
575 {
|
nuclear@0
|
576 if (pMesh->HasTextureCoords( c))
|
nuclear@0
|
577 {
|
nuclear@0
|
578 pcMesh->mTextureCoords[c][pcMesh->mNumVertices] = pMesh->mTextureCoords[c][iIndex];
|
nuclear@0
|
579 }
|
nuclear@0
|
580 }
|
nuclear@0
|
581 // vertex colors
|
nuclear@0
|
582 for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS;++c)
|
nuclear@0
|
583 {
|
nuclear@0
|
584 if (pMesh->HasVertexColors( c))
|
nuclear@0
|
585 {
|
nuclear@0
|
586 pcMesh->mColors[c][pcMesh->mNumVertices] = pMesh->mColors[c][iIndex];
|
nuclear@0
|
587 }
|
nuclear@0
|
588 }
|
nuclear@0
|
589 // check whether we have bone weights assigned to this vertex
|
nuclear@0
|
590 rFace.mIndices[v] = pcMesh->mNumVertices;
|
nuclear@0
|
591 if (avPerVertexWeights)
|
nuclear@0
|
592 {
|
nuclear@0
|
593 VertexWeightTable& table = avPerVertexWeights[ pcMesh->mNumVertices ];
|
nuclear@0
|
594 if( !table.empty() )
|
nuclear@0
|
595 {
|
nuclear@0
|
596 for (VertexWeightTable::const_iterator
|
nuclear@0
|
597 iter = table.begin();
|
nuclear@0
|
598 iter != table.end();++iter)
|
nuclear@0
|
599 {
|
nuclear@0
|
600 // allocate the bone weight array if necessary
|
nuclear@0
|
601 BoneWeightList* pcWeightList = (BoneWeightList*)pcMesh->mBones[(*iter).first];
|
nuclear@0
|
602 if (!pcWeightList)
|
nuclear@0
|
603 {
|
nuclear@0
|
604 pcMesh->mBones[(*iter).first] = (aiBone*)(pcWeightList = new BoneWeightList());
|
nuclear@0
|
605 }
|
nuclear@0
|
606 pcWeightList->push_back(aiVertexWeight(pcMesh->mNumVertices,(*iter).second));
|
nuclear@0
|
607 }
|
nuclear@0
|
608 }
|
nuclear@0
|
609 }
|
nuclear@0
|
610
|
nuclear@0
|
611 avWasCopied[iIndex] = pcMesh->mNumVertices;
|
nuclear@0
|
612 pcMesh->mNumVertices++;
|
nuclear@0
|
613 }
|
nuclear@0
|
614 iBase++;
|
nuclear@0
|
615 if(pcMesh->mNumVertices == iOutVertexNum)
|
nuclear@0
|
616 {
|
nuclear@0
|
617 // break here. The face is only added if it was complete
|
nuclear@0
|
618 break;
|
nuclear@0
|
619 }
|
nuclear@0
|
620 }
|
nuclear@0
|
621
|
nuclear@0
|
622 // check which bones we'll need to create for this submesh
|
nuclear@0
|
623 if (pMesh->HasBones())
|
nuclear@0
|
624 {
|
nuclear@0
|
625 aiBone** ppCurrent = pcMesh->mBones;
|
nuclear@0
|
626 for (unsigned int k = 0; k < pMesh->mNumBones;++k)
|
nuclear@0
|
627 {
|
nuclear@0
|
628 // check whether the bone is existing
|
nuclear@0
|
629 BoneWeightList* pcWeightList;
|
nuclear@0
|
630 if ((pcWeightList = (BoneWeightList*)pcMesh->mBones[k]))
|
nuclear@0
|
631 {
|
nuclear@0
|
632 aiBone* pcOldBone = pMesh->mBones[k];
|
nuclear@0
|
633 aiBone* pcOut;
|
nuclear@0
|
634 *ppCurrent++ = pcOut = new aiBone();
|
nuclear@0
|
635 pcOut->mName = aiString(pcOldBone->mName);
|
nuclear@0
|
636 pcOut->mOffsetMatrix = pcOldBone->mOffsetMatrix;
|
nuclear@0
|
637 pcOut->mNumWeights = (unsigned int)pcWeightList->size();
|
nuclear@0
|
638 pcOut->mWeights = new aiVertexWeight[pcOut->mNumWeights];
|
nuclear@0
|
639
|
nuclear@0
|
640 // copy the vertex weights
|
nuclear@0
|
641 ::memcpy(pcOut->mWeights,&pcWeightList->operator[](0),
|
nuclear@0
|
642 pcOut->mNumWeights * sizeof(aiVertexWeight));
|
nuclear@0
|
643
|
nuclear@0
|
644 // delete the temporary bone weight list
|
nuclear@0
|
645 delete pcWeightList;
|
nuclear@0
|
646 pcMesh->mNumBones++;
|
nuclear@0
|
647 }
|
nuclear@0
|
648 }
|
nuclear@0
|
649 }
|
nuclear@0
|
650
|
nuclear@0
|
651 // copy the face list to the mesh
|
nuclear@0
|
652 pcMesh->mFaces = new aiFace[vFaces.size()];
|
nuclear@0
|
653 pcMesh->mNumFaces = (unsigned int)vFaces.size();
|
nuclear@0
|
654
|
nuclear@0
|
655 for (unsigned int p = 0; p < pcMesh->mNumFaces;++p)
|
nuclear@0
|
656 pcMesh->mFaces[p] = vFaces[p];
|
nuclear@0
|
657
|
nuclear@0
|
658 // add the newly created mesh to the list
|
nuclear@0
|
659 avList.push_back(std::pair<aiMesh*, unsigned int>(pcMesh,a));
|
nuclear@0
|
660
|
nuclear@0
|
661 if (iBase == pMesh->mNumFaces)
|
nuclear@0
|
662 {
|
nuclear@0
|
663 // have all faces ... finish the outer loop, too
|
nuclear@0
|
664 break;
|
nuclear@0
|
665 }
|
nuclear@0
|
666 }
|
nuclear@0
|
667
|
nuclear@0
|
668 // delete the per-vertex weight list again
|
nuclear@0
|
669 delete[] avPerVertexWeights;
|
nuclear@0
|
670
|
nuclear@0
|
671 // now delete the old mesh data
|
nuclear@0
|
672 delete pMesh;
|
nuclear@0
|
673 return;
|
nuclear@0
|
674 }
|
nuclear@0
|
675 avList.push_back(std::pair<aiMesh*, unsigned int>(pMesh,a));
|
nuclear@0
|
676 return;
|
nuclear@0
|
677 }
|