rev |
line source |
nuclear@0
|
1 /*
|
nuclear@0
|
2 ---------------------------------------------------------------------------
|
nuclear@0
|
3 Open Asset Import Library (assimp)
|
nuclear@0
|
4 ---------------------------------------------------------------------------
|
nuclear@0
|
5
|
nuclear@0
|
6 Copyright (c) 2006-2012, assimp team
|
nuclear@0
|
7
|
nuclear@0
|
8 All rights reserved.
|
nuclear@0
|
9
|
nuclear@0
|
10 Redistribution and use of this software in source and binary forms,
|
nuclear@0
|
11 with or without modification, are permitted provided that the following
|
nuclear@0
|
12 conditions are met:
|
nuclear@0
|
13
|
nuclear@0
|
14 * Redistributions of source code must retain the above
|
nuclear@0
|
15 copyright notice, this list of conditions and the
|
nuclear@0
|
16 following disclaimer.
|
nuclear@0
|
17
|
nuclear@0
|
18 * Redistributions in binary form must reproduce the above
|
nuclear@0
|
19 copyright notice, this list of conditions and the
|
nuclear@0
|
20 following disclaimer in the documentation and/or other
|
nuclear@0
|
21 materials provided with the distribution.
|
nuclear@0
|
22
|
nuclear@0
|
23 * Neither the name of the assimp team, nor the names of its
|
nuclear@0
|
24 contributors may be used to endorse or promote products
|
nuclear@0
|
25 derived from this software without specific prior
|
nuclear@0
|
26 written permission of the assimp team.
|
nuclear@0
|
27
|
nuclear@0
|
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
nuclear@0
|
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
nuclear@0
|
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
nuclear@0
|
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
nuclear@0
|
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
nuclear@0
|
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
nuclear@0
|
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
nuclear@0
|
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
nuclear@0
|
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
nuclear@0
|
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
nuclear@0
|
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
nuclear@0
|
39 ---------------------------------------------------------------------------
|
nuclear@0
|
40 */
|
nuclear@0
|
41
|
nuclear@0
|
42 /** @file Implementation of the post processing step to join identical vertices
|
nuclear@0
|
43 * for all imported meshes
|
nuclear@0
|
44 */
|
nuclear@0
|
45
|
nuclear@0
|
46 #include "AssimpPCH.h"
|
nuclear@0
|
47 #ifndef ASSIMP_BUILD_NO_JOINVERTICES_PROCESS
|
nuclear@0
|
48
|
nuclear@0
|
49 #include "JoinVerticesProcess.h"
|
nuclear@0
|
50 #include "ProcessHelper.h"
|
nuclear@0
|
51 #include "Vertex.h"
|
nuclear@0
|
52 #include "TinyFormatter.h"
|
nuclear@0
|
53
|
nuclear@0
|
54 using namespace Assimp;
|
nuclear@0
|
55 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
56 // Constructor to be privately used by Importer
|
nuclear@0
|
57 JoinVerticesProcess::JoinVerticesProcess()
|
nuclear@0
|
58 {
|
nuclear@0
|
59 // nothing to do here
|
nuclear@0
|
60 }
|
nuclear@0
|
61
|
nuclear@0
|
62 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
63 // Destructor, private as well
|
nuclear@0
|
64 JoinVerticesProcess::~JoinVerticesProcess()
|
nuclear@0
|
65 {
|
nuclear@0
|
66 // nothing to do here
|
nuclear@0
|
67 }
|
nuclear@0
|
68
|
nuclear@0
|
69 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
70 // Returns whether the processing step is present in the given flag field.
|
nuclear@0
|
71 bool JoinVerticesProcess::IsActive( unsigned int pFlags) const
|
nuclear@0
|
72 {
|
nuclear@0
|
73 return (pFlags & aiProcess_JoinIdenticalVertices) != 0;
|
nuclear@0
|
74 }
|
nuclear@0
|
75 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
76 // Executes the post processing step on the given imported data.
|
nuclear@0
|
77 void JoinVerticesProcess::Execute( aiScene* pScene)
|
nuclear@0
|
78 {
|
nuclear@0
|
79 DefaultLogger::get()->debug("JoinVerticesProcess begin");
|
nuclear@0
|
80
|
nuclear@0
|
81 // get the total number of vertices BEFORE the step is executed
|
nuclear@0
|
82 int iNumOldVertices = 0;
|
nuclear@0
|
83 if (!DefaultLogger::isNullLogger()) {
|
nuclear@0
|
84 for( unsigned int a = 0; a < pScene->mNumMeshes; a++) {
|
nuclear@0
|
85 iNumOldVertices += pScene->mMeshes[a]->mNumVertices;
|
nuclear@0
|
86 }
|
nuclear@0
|
87 }
|
nuclear@0
|
88
|
nuclear@0
|
89 // execute the step
|
nuclear@0
|
90 int iNumVertices = 0;
|
nuclear@0
|
91 for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
|
nuclear@0
|
92 iNumVertices += ProcessMesh( pScene->mMeshes[a],a);
|
nuclear@0
|
93
|
nuclear@0
|
94 // if logging is active, print detailed statistics
|
nuclear@0
|
95 if (!DefaultLogger::isNullLogger())
|
nuclear@0
|
96 {
|
nuclear@0
|
97 if (iNumOldVertices == iNumVertices)
|
nuclear@0
|
98 {
|
nuclear@0
|
99 DefaultLogger::get()->debug("JoinVerticesProcess finished ");
|
nuclear@0
|
100 } else
|
nuclear@0
|
101 {
|
nuclear@0
|
102 char szBuff[128]; // should be sufficiently large in every case
|
nuclear@0
|
103 sprintf(szBuff,"JoinVerticesProcess finished | Verts in: %i out: %i | ~%.1f%%",
|
nuclear@0
|
104 iNumOldVertices,
|
nuclear@0
|
105 iNumVertices,
|
nuclear@0
|
106 ((iNumOldVertices - iNumVertices) / (float)iNumOldVertices) * 100.f);
|
nuclear@0
|
107 DefaultLogger::get()->info(szBuff);
|
nuclear@0
|
108 }
|
nuclear@0
|
109 }
|
nuclear@0
|
110
|
nuclear@0
|
111 pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
|
nuclear@0
|
112 }
|
nuclear@0
|
113
|
nuclear@0
|
114 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
115 // Unites identical vertices in the given mesh
|
nuclear@0
|
116 int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
nuclear@0
|
117 {
|
nuclear@0
|
118 BOOST_STATIC_ASSERT( AI_MAX_NUMBER_OF_COLOR_SETS == 8);
|
nuclear@0
|
119 BOOST_STATIC_ASSERT( AI_MAX_NUMBER_OF_TEXTURECOORDS == 8);
|
nuclear@0
|
120
|
nuclear@0
|
121 // Return early if we don't have any positions
|
nuclear@0
|
122 if (!pMesh->HasPositions() || !pMesh->HasFaces()) {
|
nuclear@0
|
123 return 0;
|
nuclear@0
|
124 }
|
nuclear@0
|
125
|
nuclear@0
|
126 // We'll never have more vertices afterwards.
|
nuclear@0
|
127 std::vector<Vertex> uniqueVertices;
|
nuclear@0
|
128 uniqueVertices.reserve( pMesh->mNumVertices);
|
nuclear@0
|
129
|
nuclear@0
|
130 // For each vertex the index of the vertex it was replaced by.
|
nuclear@0
|
131 // Since the maximal number of vertices is 2^31-1, the most significand bit can be used to mark
|
nuclear@0
|
132 // whether a new vertex was created for the index (true) or if it was replaced by an existing
|
nuclear@0
|
133 // unique vertex (false). This saves an additional std::vector<bool> and greatly enhances
|
nuclear@0
|
134 // branching performance.
|
nuclear@0
|
135 BOOST_STATIC_ASSERT(AI_MAX_VERTICES == 0x7fffffff);
|
nuclear@0
|
136 std::vector<unsigned int> replaceIndex( pMesh->mNumVertices, 0xffffffff);
|
nuclear@0
|
137
|
nuclear@0
|
138 // A little helper to find locally close vertices faster.
|
nuclear@0
|
139 // Try to reuse the lookup table from the last step.
|
nuclear@0
|
140 const static float epsilon = 1e-5f;
|
nuclear@0
|
141 // float posEpsilonSqr;
|
nuclear@0
|
142 SpatialSort* vertexFinder = NULL;
|
nuclear@0
|
143 SpatialSort _vertexFinder;
|
nuclear@0
|
144
|
nuclear@0
|
145 typedef std::pair<SpatialSort,float> SpatPair;
|
nuclear@0
|
146 if (shared) {
|
nuclear@0
|
147 std::vector<SpatPair >* avf;
|
nuclear@0
|
148 shared->GetProperty(AI_SPP_SPATIAL_SORT,avf);
|
nuclear@0
|
149 if (avf) {
|
nuclear@0
|
150 SpatPair& blubb = (*avf)[meshIndex];
|
nuclear@0
|
151 vertexFinder = &blubb.first;
|
nuclear@0
|
152 // posEpsilonSqr = blubb.second;
|
nuclear@0
|
153 }
|
nuclear@0
|
154 }
|
nuclear@0
|
155 if (!vertexFinder) {
|
nuclear@0
|
156 // bad, need to compute it.
|
nuclear@0
|
157 _vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D));
|
nuclear@0
|
158 vertexFinder = &_vertexFinder;
|
nuclear@0
|
159 // posEpsilonSqr = ComputePositionEpsilon(pMesh);
|
nuclear@0
|
160 }
|
nuclear@0
|
161
|
nuclear@0
|
162 // Squared because we check against squared length of the vector difference
|
nuclear@0
|
163 static const float squareEpsilon = epsilon * epsilon;
|
nuclear@0
|
164
|
nuclear@0
|
165 // Again, better waste some bytes than a realloc ...
|
nuclear@0
|
166 std::vector<unsigned int> verticesFound;
|
nuclear@0
|
167 verticesFound.reserve(10);
|
nuclear@0
|
168
|
nuclear@0
|
169 // Run an optimized code path if we don't have multiple UVs or vertex colors.
|
nuclear@0
|
170 // This should yield false in more than 99% of all imports ...
|
nuclear@0
|
171 const bool complex = ( pMesh->GetNumColorChannels() > 0 || pMesh->GetNumUVChannels() > 1);
|
nuclear@0
|
172
|
nuclear@0
|
173 // Now check each vertex if it brings something new to the table
|
nuclear@0
|
174 for( unsigned int a = 0; a < pMesh->mNumVertices; a++) {
|
nuclear@0
|
175 // collect the vertex data
|
nuclear@0
|
176 Vertex v(pMesh,a);
|
nuclear@0
|
177
|
nuclear@0
|
178 // collect all vertices that are close enough to the given position
|
nuclear@0
|
179 vertexFinder->FindIdenticalPositions( v.position, verticesFound);
|
nuclear@0
|
180 unsigned int matchIndex = 0xffffffff;
|
nuclear@0
|
181
|
nuclear@0
|
182 // check all unique vertices close to the position if this vertex is already present among them
|
nuclear@0
|
183 for( unsigned int b = 0; b < verticesFound.size(); b++) {
|
nuclear@0
|
184
|
nuclear@0
|
185 const unsigned int vidx = verticesFound[b];
|
nuclear@0
|
186 const unsigned int uidx = replaceIndex[ vidx];
|
nuclear@0
|
187 if( uidx & 0x80000000)
|
nuclear@0
|
188 continue;
|
nuclear@0
|
189
|
nuclear@0
|
190 const Vertex& uv = uniqueVertices[ uidx];
|
nuclear@0
|
191 // Position mismatch is impossible - the vertex finder already discarded all non-matching positions
|
nuclear@0
|
192
|
nuclear@0
|
193 // We just test the other attributes even if they're not present in the mesh.
|
nuclear@0
|
194 // In this case they're initialized to 0 so the comparision succeeds.
|
nuclear@0
|
195 // By this method the non-present attributes are effectively ignored in the comparision.
|
nuclear@0
|
196 if( (uv.normal - v.normal).SquareLength() > squareEpsilon)
|
nuclear@0
|
197 continue;
|
nuclear@0
|
198 if( (uv.texcoords[0] - v.texcoords[0]).SquareLength() > squareEpsilon)
|
nuclear@0
|
199 continue;
|
nuclear@0
|
200 if( (uv.tangent - v.tangent).SquareLength() > squareEpsilon)
|
nuclear@0
|
201 continue;
|
nuclear@0
|
202 if( (uv.bitangent - v.bitangent).SquareLength() > squareEpsilon)
|
nuclear@0
|
203 continue;
|
nuclear@0
|
204
|
nuclear@0
|
205 // Usually we won't have vertex colors or multiple UVs, so we can skip from here
|
nuclear@0
|
206 // Actually this increases runtime performance slightly, at least if branch
|
nuclear@0
|
207 // prediction is on our side.
|
nuclear@0
|
208 if (complex){
|
nuclear@0
|
209 // manually unrolled because continue wouldn't work as desired in an inner loop,
|
nuclear@0
|
210 // also because some compilers seem to fail the task. Colors and UV coords
|
nuclear@0
|
211 // are interleaved since the higher entries are most likely to be
|
nuclear@0
|
212 // zero and thus useless. By interleaving the arrays, vertices are,
|
nuclear@0
|
213 // on average, rejected earlier.
|
nuclear@0
|
214
|
nuclear@0
|
215 if( (uv.texcoords[1] - v.texcoords[1]).SquareLength() > squareEpsilon)
|
nuclear@0
|
216 continue;
|
nuclear@0
|
217 if( GetColorDifference( uv.colors[0], v.colors[0]) > squareEpsilon)
|
nuclear@0
|
218 continue;
|
nuclear@0
|
219
|
nuclear@0
|
220 if( (uv.texcoords[2] - v.texcoords[2]).SquareLength() > squareEpsilon)
|
nuclear@0
|
221 continue;
|
nuclear@0
|
222 if( GetColorDifference( uv.colors[1], v.colors[1]) > squareEpsilon)
|
nuclear@0
|
223 continue;
|
nuclear@0
|
224
|
nuclear@0
|
225 if( (uv.texcoords[3] - v.texcoords[3]).SquareLength() > squareEpsilon)
|
nuclear@0
|
226 continue;
|
nuclear@0
|
227 if( GetColorDifference( uv.colors[2], v.colors[2]) > squareEpsilon)
|
nuclear@0
|
228 continue;
|
nuclear@0
|
229
|
nuclear@0
|
230 if( (uv.texcoords[4] - v.texcoords[4]).SquareLength() > squareEpsilon)
|
nuclear@0
|
231 continue;
|
nuclear@0
|
232 if( GetColorDifference( uv.colors[3], v.colors[3]) > squareEpsilon)
|
nuclear@0
|
233 continue;
|
nuclear@0
|
234
|
nuclear@0
|
235 if( (uv.texcoords[5] - v.texcoords[5]).SquareLength() > squareEpsilon)
|
nuclear@0
|
236 continue;
|
nuclear@0
|
237 if( GetColorDifference( uv.colors[4], v.colors[4]) > squareEpsilon)
|
nuclear@0
|
238 continue;
|
nuclear@0
|
239
|
nuclear@0
|
240 if( (uv.texcoords[6] - v.texcoords[6]).SquareLength() > squareEpsilon)
|
nuclear@0
|
241 continue;
|
nuclear@0
|
242 if( GetColorDifference( uv.colors[5], v.colors[5]) > squareEpsilon)
|
nuclear@0
|
243 continue;
|
nuclear@0
|
244
|
nuclear@0
|
245 if( (uv.texcoords[7] - v.texcoords[7]).SquareLength() > squareEpsilon)
|
nuclear@0
|
246 continue;
|
nuclear@0
|
247 if( GetColorDifference( uv.colors[6], v.colors[6]) > squareEpsilon)
|
nuclear@0
|
248 continue;
|
nuclear@0
|
249
|
nuclear@0
|
250 if( GetColorDifference( uv.colors[7], v.colors[7]) > squareEpsilon)
|
nuclear@0
|
251 continue;
|
nuclear@0
|
252 }
|
nuclear@0
|
253
|
nuclear@0
|
254 // we're still here -> this vertex perfectly matches our given vertex
|
nuclear@0
|
255 matchIndex = uidx;
|
nuclear@0
|
256 break;
|
nuclear@0
|
257 }
|
nuclear@0
|
258
|
nuclear@0
|
259 // found a replacement vertex among the uniques?
|
nuclear@0
|
260 if( matchIndex != 0xffffffff)
|
nuclear@0
|
261 {
|
nuclear@0
|
262 // store where to found the matching unique vertex
|
nuclear@0
|
263 replaceIndex[a] = matchIndex | 0x80000000;
|
nuclear@0
|
264 }
|
nuclear@0
|
265 else
|
nuclear@0
|
266 {
|
nuclear@0
|
267 // no unique vertex matches it upto now -> so add it
|
nuclear@0
|
268 replaceIndex[a] = (unsigned int)uniqueVertices.size();
|
nuclear@0
|
269 uniqueVertices.push_back( v);
|
nuclear@0
|
270 }
|
nuclear@0
|
271 }
|
nuclear@0
|
272
|
nuclear@0
|
273 if (!DefaultLogger::isNullLogger() && DefaultLogger::get()->getLogSeverity() == Logger::VERBOSE) {
|
nuclear@0
|
274 DefaultLogger::get()->debug((Formatter::format(),
|
nuclear@0
|
275 "Mesh ",meshIndex,
|
nuclear@0
|
276 " (",
|
nuclear@0
|
277 (pMesh->mName.length ? pMesh->mName.data : "unnamed"),
|
nuclear@0
|
278 ") | Verts in: ",pMesh->mNumVertices,
|
nuclear@0
|
279 " out: ",
|
nuclear@0
|
280 uniqueVertices.size(),
|
nuclear@0
|
281 " | ~",
|
nuclear@0
|
282 ((pMesh->mNumVertices - uniqueVertices.size()) / (float)pMesh->mNumVertices) * 100.f,
|
nuclear@0
|
283 "%"
|
nuclear@0
|
284 ));
|
nuclear@0
|
285 }
|
nuclear@0
|
286
|
nuclear@0
|
287 // replace vertex data with the unique data sets
|
nuclear@0
|
288 pMesh->mNumVertices = (unsigned int)uniqueVertices.size();
|
nuclear@0
|
289
|
nuclear@0
|
290 // ----------------------------------------------------------------------------
|
nuclear@0
|
291 // NOTE - we're *not* calling Vertex::SortBack() because it would check for
|
nuclear@0
|
292 // presence of every single vertex component once PER VERTEX. And our CPU
|
nuclear@0
|
293 // dislikes branches, even if they're easily predictable.
|
nuclear@0
|
294 // ----------------------------------------------------------------------------
|
nuclear@0
|
295
|
nuclear@0
|
296 // Position
|
nuclear@0
|
297 delete [] pMesh->mVertices;
|
nuclear@0
|
298 pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
|
nuclear@0
|
299 for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
|
nuclear@0
|
300 pMesh->mVertices[a] = uniqueVertices[a].position;
|
nuclear@0
|
301
|
nuclear@0
|
302 // Normals, if present
|
nuclear@0
|
303 if( pMesh->mNormals)
|
nuclear@0
|
304 {
|
nuclear@0
|
305 delete [] pMesh->mNormals;
|
nuclear@0
|
306 pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
|
nuclear@0
|
307 for( unsigned int a = 0; a < pMesh->mNumVertices; a++) {
|
nuclear@0
|
308 pMesh->mNormals[a] = uniqueVertices[a].normal;
|
nuclear@0
|
309 }
|
nuclear@0
|
310 }
|
nuclear@0
|
311 // Tangents, if present
|
nuclear@0
|
312 if( pMesh->mTangents)
|
nuclear@0
|
313 {
|
nuclear@0
|
314 delete [] pMesh->mTangents;
|
nuclear@0
|
315 pMesh->mTangents = new aiVector3D[pMesh->mNumVertices];
|
nuclear@0
|
316 for( unsigned int a = 0; a < pMesh->mNumVertices; a++) {
|
nuclear@0
|
317 pMesh->mTangents[a] = uniqueVertices[a].tangent;
|
nuclear@0
|
318 }
|
nuclear@0
|
319 }
|
nuclear@0
|
320 // Bitangents as well
|
nuclear@0
|
321 if( pMesh->mBitangents)
|
nuclear@0
|
322 {
|
nuclear@0
|
323 delete [] pMesh->mBitangents;
|
nuclear@0
|
324 pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices];
|
nuclear@0
|
325 for( unsigned int a = 0; a < pMesh->mNumVertices; a++) {
|
nuclear@0
|
326 pMesh->mBitangents[a] = uniqueVertices[a].bitangent;
|
nuclear@0
|
327 }
|
nuclear@0
|
328 }
|
nuclear@0
|
329 // Vertex colors
|
nuclear@0
|
330 for( unsigned int a = 0; pMesh->HasVertexColors(a); a++)
|
nuclear@0
|
331 {
|
nuclear@0
|
332 delete [] pMesh->mColors[a];
|
nuclear@0
|
333 pMesh->mColors[a] = new aiColor4D[pMesh->mNumVertices];
|
nuclear@0
|
334 for( unsigned int b = 0; b < pMesh->mNumVertices; b++) {
|
nuclear@0
|
335 pMesh->mColors[a][b] = uniqueVertices[b].colors[a];
|
nuclear@0
|
336 }
|
nuclear@0
|
337 }
|
nuclear@0
|
338 // Texture coords
|
nuclear@0
|
339 for( unsigned int a = 0; pMesh->HasTextureCoords(a); a++)
|
nuclear@0
|
340 {
|
nuclear@0
|
341 delete [] pMesh->mTextureCoords[a];
|
nuclear@0
|
342 pMesh->mTextureCoords[a] = new aiVector3D[pMesh->mNumVertices];
|
nuclear@0
|
343 for( unsigned int b = 0; b < pMesh->mNumVertices; b++) {
|
nuclear@0
|
344 pMesh->mTextureCoords[a][b] = uniqueVertices[b].texcoords[a];
|
nuclear@0
|
345 }
|
nuclear@0
|
346 }
|
nuclear@0
|
347
|
nuclear@0
|
348 // adjust the indices in all faces
|
nuclear@0
|
349 for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
|
nuclear@0
|
350 {
|
nuclear@0
|
351 aiFace& face = pMesh->mFaces[a];
|
nuclear@0
|
352 for( unsigned int b = 0; b < face.mNumIndices; b++) {
|
nuclear@0
|
353 face.mIndices[b] = replaceIndex[face.mIndices[b]] & ~0x80000000;
|
nuclear@0
|
354 }
|
nuclear@0
|
355 }
|
nuclear@0
|
356
|
nuclear@0
|
357 // adjust bone vertex weights.
|
nuclear@0
|
358 for( int a = 0; a < (int)pMesh->mNumBones; a++)
|
nuclear@0
|
359 {
|
nuclear@0
|
360 aiBone* bone = pMesh->mBones[a];
|
nuclear@0
|
361 std::vector<aiVertexWeight> newWeights;
|
nuclear@0
|
362 newWeights.reserve( bone->mNumWeights);
|
nuclear@0
|
363
|
nuclear@0
|
364 for( unsigned int b = 0; b < bone->mNumWeights; b++)
|
nuclear@0
|
365 {
|
nuclear@0
|
366 const aiVertexWeight& ow = bone->mWeights[b];
|
nuclear@0
|
367 // if the vertex is a unique one, translate it
|
nuclear@0
|
368 if( !(replaceIndex[ow.mVertexId] & 0x80000000))
|
nuclear@0
|
369 {
|
nuclear@0
|
370 aiVertexWeight nw;
|
nuclear@0
|
371 nw.mVertexId = replaceIndex[ow.mVertexId];
|
nuclear@0
|
372 nw.mWeight = ow.mWeight;
|
nuclear@0
|
373 newWeights.push_back( nw);
|
nuclear@0
|
374 }
|
nuclear@0
|
375 }
|
nuclear@0
|
376
|
nuclear@0
|
377 if (newWeights.size() > 0) {
|
nuclear@0
|
378 // kill the old and replace them with the translated weights
|
nuclear@0
|
379 delete [] bone->mWeights;
|
nuclear@0
|
380 bone->mNumWeights = (unsigned int)newWeights.size();
|
nuclear@0
|
381
|
nuclear@0
|
382 bone->mWeights = new aiVertexWeight[bone->mNumWeights];
|
nuclear@0
|
383 memcpy( bone->mWeights, &newWeights[0], bone->mNumWeights * sizeof( aiVertexWeight));
|
nuclear@0
|
384 }
|
nuclear@0
|
385 else {
|
nuclear@0
|
386
|
nuclear@0
|
387 /* NOTE:
|
nuclear@0
|
388 *
|
nuclear@0
|
389 * In the algorithm above we're assuming that there are no vertices
|
nuclear@0
|
390 * with a different bone weight setup at the same position. That wouldn't
|
nuclear@0
|
391 * make sense, but it is not absolutely impossible. SkeletonMeshBuilder
|
nuclear@0
|
392 * for example generates such input data if two skeleton points
|
nuclear@0
|
393 * share the same position. Again this doesn't make sense but is
|
nuclear@0
|
394 * reality for some model formats (MD5 for example uses these special
|
nuclear@0
|
395 * nodes as attachment tags for its weapons).
|
nuclear@0
|
396 *
|
nuclear@0
|
397 * Then it is possible that a bone has no weights anymore .... as a quick
|
nuclear@0
|
398 * workaround, we're just removing these bones. If they're animated,
|
nuclear@0
|
399 * model geometry might be modified but at least there's no risk of a crash.
|
nuclear@0
|
400 */
|
nuclear@0
|
401 delete bone;
|
nuclear@0
|
402 --pMesh->mNumBones;
|
nuclear@0
|
403 for (unsigned int n = a; n < pMesh->mNumBones; ++n) {
|
nuclear@0
|
404 pMesh->mBones[n] = pMesh->mBones[n+1];
|
nuclear@0
|
405 }
|
nuclear@0
|
406
|
nuclear@0
|
407 --a;
|
nuclear@0
|
408 DefaultLogger::get()->warn("Removing bone -> no weights remaining");
|
nuclear@0
|
409 }
|
nuclear@0
|
410 }
|
nuclear@0
|
411 return pMesh->mNumVertices;
|
nuclear@0
|
412 }
|
nuclear@0
|
413
|
nuclear@0
|
414 #endif // !! ASSIMP_BUILD_NO_JOINVERTICES_PROCESS
|