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 /** @file XFileImporter.cpp
|
nuclear@0
|
42 * @brief Implementation of the XFile importer class
|
nuclear@0
|
43 */
|
nuclear@0
|
44
|
nuclear@0
|
45 #include "AssimpPCH.h"
|
nuclear@0
|
46 #ifndef ASSIMP_BUILD_NO_X_IMPORTER
|
nuclear@0
|
47
|
nuclear@0
|
48 #include "XFileImporter.h"
|
nuclear@0
|
49 #include "XFileParser.h"
|
nuclear@0
|
50 #include "ConvertToLHProcess.h"
|
nuclear@0
|
51
|
nuclear@0
|
52 using namespace Assimp;
|
nuclear@0
|
53
|
nuclear@0
|
54 static const aiImporterDesc desc = {
|
nuclear@0
|
55 "Direct3D XFile Importer",
|
nuclear@0
|
56 "",
|
nuclear@0
|
57 "",
|
nuclear@0
|
58 "",
|
nuclear@0
|
59 aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportCompressedFlavour,
|
nuclear@0
|
60 1,
|
nuclear@0
|
61 3,
|
nuclear@0
|
62 1,
|
nuclear@0
|
63 5,
|
nuclear@0
|
64 "x"
|
nuclear@0
|
65 };
|
nuclear@0
|
66
|
nuclear@0
|
67 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
68 // Constructor to be privately used by Importer
|
nuclear@0
|
69 XFileImporter::XFileImporter()
|
nuclear@0
|
70 {}
|
nuclear@0
|
71
|
nuclear@0
|
72 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
73 // Destructor, private as well
|
nuclear@0
|
74 XFileImporter::~XFileImporter()
|
nuclear@0
|
75 {}
|
nuclear@0
|
76
|
nuclear@0
|
77 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
78 // Returns whether the class can handle the format of the given file.
|
nuclear@0
|
79 bool XFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
|
nuclear@0
|
80 {
|
nuclear@0
|
81 std::string extension = GetExtension(pFile);
|
nuclear@0
|
82 if(extension == "x") {
|
nuclear@0
|
83 return true;
|
nuclear@0
|
84 }
|
nuclear@0
|
85 if (!extension.length() || checkSig) {
|
nuclear@0
|
86 uint32_t token[1];
|
nuclear@0
|
87 token[0] = AI_MAKE_MAGIC("xof ");
|
nuclear@0
|
88 return CheckMagicToken(pIOHandler,pFile,token,1,0);
|
nuclear@0
|
89 }
|
nuclear@0
|
90 return false;
|
nuclear@0
|
91 }
|
nuclear@0
|
92
|
nuclear@0
|
93 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
94 // Get file extension list
|
nuclear@0
|
95 const aiImporterDesc* XFileImporter::GetInfo () const
|
nuclear@0
|
96 {
|
nuclear@0
|
97 return &desc;
|
nuclear@0
|
98 }
|
nuclear@0
|
99
|
nuclear@0
|
100 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
101 // Imports the given file into the given scene structure.
|
nuclear@0
|
102 void XFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
|
nuclear@0
|
103 {
|
nuclear@0
|
104 // read file into memory
|
nuclear@0
|
105 boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
|
nuclear@0
|
106 if( file.get() == NULL)
|
nuclear@0
|
107 throw DeadlyImportError( "Failed to open file " + pFile + ".");
|
nuclear@0
|
108
|
nuclear@0
|
109 size_t fileSize = file->FileSize();
|
nuclear@0
|
110 if( fileSize < 16)
|
nuclear@0
|
111 throw DeadlyImportError( "XFile is too small.");
|
nuclear@0
|
112
|
nuclear@0
|
113 // in the hope that binary files will never start with a BOM ...
|
nuclear@0
|
114 mBuffer.resize( fileSize + 1);
|
nuclear@0
|
115 file->Read( &mBuffer.front(), 1, fileSize);
|
nuclear@0
|
116 ConvertToUTF8(mBuffer);
|
nuclear@0
|
117
|
nuclear@0
|
118 // parse the file into a temporary representation
|
nuclear@0
|
119 XFileParser parser( mBuffer);
|
nuclear@0
|
120
|
nuclear@0
|
121 // and create the proper return structures out of it
|
nuclear@0
|
122 CreateDataRepresentationFromImport( pScene, parser.GetImportedData());
|
nuclear@0
|
123
|
nuclear@0
|
124 // if nothing came from it, report it as error
|
nuclear@0
|
125 if( !pScene->mRootNode)
|
nuclear@0
|
126 throw DeadlyImportError( "XFile is ill-formatted - no content imported.");
|
nuclear@0
|
127 }
|
nuclear@0
|
128
|
nuclear@0
|
129 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
130 // Constructs the return data structure out of the imported data.
|
nuclear@0
|
131 void XFileImporter::CreateDataRepresentationFromImport( aiScene* pScene, XFile::Scene* pData)
|
nuclear@0
|
132 {
|
nuclear@0
|
133 // Read the global materials first so that meshes referring to them can find them later
|
nuclear@0
|
134 ConvertMaterials( pScene, pData->mGlobalMaterials);
|
nuclear@0
|
135
|
nuclear@0
|
136 // copy nodes, extracting meshes and materials on the way
|
nuclear@0
|
137 pScene->mRootNode = CreateNodes( pScene, NULL, pData->mRootNode);
|
nuclear@0
|
138
|
nuclear@0
|
139 // extract animations
|
nuclear@0
|
140 CreateAnimations( pScene, pData);
|
nuclear@0
|
141
|
nuclear@0
|
142 // read the global meshes that were stored outside of any node
|
nuclear@0
|
143 if( pData->mGlobalMeshes.size() > 0)
|
nuclear@0
|
144 {
|
nuclear@0
|
145 // create a root node to hold them if there isn't any, yet
|
nuclear@0
|
146 if( pScene->mRootNode == NULL)
|
nuclear@0
|
147 {
|
nuclear@0
|
148 pScene->mRootNode = new aiNode;
|
nuclear@0
|
149 pScene->mRootNode->mName.Set( "$dummy_node");
|
nuclear@0
|
150 }
|
nuclear@0
|
151
|
nuclear@0
|
152 // convert all global meshes and store them in the root node.
|
nuclear@0
|
153 // If there was one before, the global meshes now suddenly have its transformation matrix...
|
nuclear@0
|
154 // Don't know what to do there, I don't want to insert another node under the present root node
|
nuclear@0
|
155 // just to avoid this.
|
nuclear@0
|
156 CreateMeshes( pScene, pScene->mRootNode, pData->mGlobalMeshes);
|
nuclear@0
|
157 }
|
nuclear@0
|
158
|
nuclear@0
|
159 // Convert everything to OpenGL space... it's the same operation as the conversion back, so we can reuse the step directly
|
nuclear@0
|
160 MakeLeftHandedProcess convertProcess;
|
nuclear@0
|
161 convertProcess.Execute( pScene);
|
nuclear@0
|
162
|
nuclear@0
|
163 FlipWindingOrderProcess flipper;
|
nuclear@0
|
164 flipper.Execute(pScene);
|
nuclear@0
|
165
|
nuclear@0
|
166 // finally: create a dummy material if not material was imported
|
nuclear@0
|
167 if( pScene->mNumMaterials == 0)
|
nuclear@0
|
168 {
|
nuclear@0
|
169 pScene->mNumMaterials = 1;
|
nuclear@0
|
170 // create the Material
|
nuclear@0
|
171 aiMaterial* mat = new aiMaterial;
|
nuclear@0
|
172 int shadeMode = (int) aiShadingMode_Gouraud;
|
nuclear@0
|
173 mat->AddProperty<int>( &shadeMode, 1, AI_MATKEY_SHADING_MODEL);
|
nuclear@0
|
174 // material colours
|
nuclear@0
|
175 int specExp = 1;
|
nuclear@0
|
176
|
nuclear@0
|
177 aiColor3D clr = aiColor3D( 0, 0, 0);
|
nuclear@0
|
178 mat->AddProperty( &clr, 1, AI_MATKEY_COLOR_EMISSIVE);
|
nuclear@0
|
179 mat->AddProperty( &clr, 1, AI_MATKEY_COLOR_SPECULAR);
|
nuclear@0
|
180
|
nuclear@0
|
181 clr = aiColor3D( 0.5f, 0.5f, 0.5f);
|
nuclear@0
|
182 mat->AddProperty( &clr, 1, AI_MATKEY_COLOR_DIFFUSE);
|
nuclear@0
|
183 mat->AddProperty( &specExp, 1, AI_MATKEY_SHININESS);
|
nuclear@0
|
184
|
nuclear@0
|
185 pScene->mMaterials = new aiMaterial*[1];
|
nuclear@0
|
186 pScene->mMaterials[0] = mat;
|
nuclear@0
|
187 }
|
nuclear@0
|
188 }
|
nuclear@0
|
189
|
nuclear@0
|
190 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
191 // Recursively creates scene nodes from the imported hierarchy.
|
nuclear@0
|
192 aiNode* XFileImporter::CreateNodes( aiScene* pScene, aiNode* pParent, const XFile::Node* pNode)
|
nuclear@0
|
193 {
|
nuclear@0
|
194 if( !pNode)
|
nuclear@0
|
195 return NULL;
|
nuclear@0
|
196
|
nuclear@0
|
197 // create node
|
nuclear@0
|
198 aiNode* node = new aiNode;
|
nuclear@0
|
199 node->mName.length = pNode->mName.length();
|
nuclear@0
|
200 node->mParent = pParent;
|
nuclear@0
|
201 memcpy( node->mName.data, pNode->mName.c_str(), pNode->mName.length());
|
nuclear@0
|
202 node->mName.data[node->mName.length] = 0;
|
nuclear@0
|
203 node->mTransformation = pNode->mTrafoMatrix;
|
nuclear@0
|
204
|
nuclear@0
|
205 // convert meshes from the source node
|
nuclear@0
|
206 CreateMeshes( pScene, node, pNode->mMeshes);
|
nuclear@0
|
207
|
nuclear@0
|
208 // handle childs
|
nuclear@0
|
209 if( pNode->mChildren.size() > 0)
|
nuclear@0
|
210 {
|
nuclear@0
|
211 node->mNumChildren = (unsigned int)pNode->mChildren.size();
|
nuclear@0
|
212 node->mChildren = new aiNode* [node->mNumChildren];
|
nuclear@0
|
213
|
nuclear@0
|
214 for( unsigned int a = 0; a < pNode->mChildren.size(); a++)
|
nuclear@0
|
215 node->mChildren[a] = CreateNodes( pScene, node, pNode->mChildren[a]);
|
nuclear@0
|
216 }
|
nuclear@0
|
217
|
nuclear@0
|
218 return node;
|
nuclear@0
|
219 }
|
nuclear@0
|
220
|
nuclear@0
|
221 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
222 // Creates the meshes for the given node.
|
nuclear@0
|
223 void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vector<XFile::Mesh*>& pMeshes)
|
nuclear@0
|
224 {
|
nuclear@0
|
225 if( pMeshes.size() == 0)
|
nuclear@0
|
226 return;
|
nuclear@0
|
227
|
nuclear@0
|
228 // create a mesh for each mesh-material combination in the source node
|
nuclear@0
|
229 std::vector<aiMesh*> meshes;
|
nuclear@0
|
230 for( unsigned int a = 0; a < pMeshes.size(); a++)
|
nuclear@0
|
231 {
|
nuclear@0
|
232 XFile::Mesh* sourceMesh = pMeshes[a];
|
nuclear@0
|
233 // first convert its materials so that we can find them with their index afterwards
|
nuclear@0
|
234 ConvertMaterials( pScene, sourceMesh->mMaterials);
|
nuclear@0
|
235
|
nuclear@0
|
236 unsigned int numMaterials = std::max( (unsigned int)sourceMesh->mMaterials.size(), 1u);
|
nuclear@0
|
237 for( unsigned int b = 0; b < numMaterials; b++)
|
nuclear@0
|
238 {
|
nuclear@0
|
239 // collect the faces belonging to this material
|
nuclear@0
|
240 std::vector<unsigned int> faces;
|
nuclear@0
|
241 unsigned int numVertices = 0;
|
nuclear@0
|
242 if( sourceMesh->mFaceMaterials.size() > 0)
|
nuclear@0
|
243 {
|
nuclear@0
|
244 // if there is a per-face material defined, select the faces with the corresponding material
|
nuclear@0
|
245 for( unsigned int c = 0; c < sourceMesh->mFaceMaterials.size(); c++)
|
nuclear@0
|
246 {
|
nuclear@0
|
247 if( sourceMesh->mFaceMaterials[c] == b)
|
nuclear@0
|
248 {
|
nuclear@0
|
249 faces.push_back( c);
|
nuclear@0
|
250 numVertices += (unsigned int)sourceMesh->mPosFaces[c].mIndices.size();
|
nuclear@0
|
251 }
|
nuclear@0
|
252 }
|
nuclear@0
|
253 } else
|
nuclear@0
|
254 {
|
nuclear@0
|
255 // if there is no per-face material, place everything into one mesh
|
nuclear@0
|
256 for( unsigned int c = 0; c < sourceMesh->mPosFaces.size(); c++)
|
nuclear@0
|
257 {
|
nuclear@0
|
258 faces.push_back( c);
|
nuclear@0
|
259 numVertices += (unsigned int)sourceMesh->mPosFaces[c].mIndices.size();
|
nuclear@0
|
260 }
|
nuclear@0
|
261 }
|
nuclear@0
|
262
|
nuclear@0
|
263 // no faces/vertices using this material? strange...
|
nuclear@0
|
264 if( numVertices == 0)
|
nuclear@0
|
265 continue;
|
nuclear@0
|
266
|
nuclear@0
|
267 // create a submesh using this material
|
nuclear@0
|
268 aiMesh* mesh = new aiMesh;
|
nuclear@0
|
269 meshes.push_back( mesh);
|
nuclear@0
|
270
|
nuclear@0
|
271 // find the material in the scene's material list. Either own material
|
nuclear@0
|
272 // or referenced material, it should already have a valid index
|
nuclear@0
|
273 if( sourceMesh->mFaceMaterials.size() > 0)
|
nuclear@0
|
274 {
|
nuclear@0
|
275 mesh->mMaterialIndex = sourceMesh->mMaterials[b].sceneIndex;
|
nuclear@0
|
276 } else
|
nuclear@0
|
277 {
|
nuclear@0
|
278 mesh->mMaterialIndex = 0;
|
nuclear@0
|
279 }
|
nuclear@0
|
280
|
nuclear@0
|
281 // Create properly sized data arrays in the mesh. We store unique vertices per face,
|
nuclear@0
|
282 // as specified
|
nuclear@0
|
283 mesh->mNumVertices = numVertices;
|
nuclear@0
|
284 mesh->mVertices = new aiVector3D[numVertices];
|
nuclear@0
|
285 mesh->mNumFaces = (unsigned int)faces.size();
|
nuclear@0
|
286 mesh->mFaces = new aiFace[mesh->mNumFaces];
|
nuclear@0
|
287
|
nuclear@0
|
288 // normals?
|
nuclear@0
|
289 if( sourceMesh->mNormals.size() > 0)
|
nuclear@0
|
290 mesh->mNormals = new aiVector3D[numVertices];
|
nuclear@0
|
291 // texture coords
|
nuclear@0
|
292 for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; c++)
|
nuclear@0
|
293 {
|
nuclear@0
|
294 if( sourceMesh->mTexCoords[c].size() > 0)
|
nuclear@0
|
295 mesh->mTextureCoords[c] = new aiVector3D[numVertices];
|
nuclear@0
|
296 }
|
nuclear@0
|
297 // vertex colors
|
nuclear@0
|
298 for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; c++)
|
nuclear@0
|
299 {
|
nuclear@0
|
300 if( sourceMesh->mColors[c].size() > 0)
|
nuclear@0
|
301 mesh->mColors[c] = new aiColor4D[numVertices];
|
nuclear@0
|
302 }
|
nuclear@0
|
303
|
nuclear@0
|
304 // now collect the vertex data of all data streams present in the imported mesh
|
nuclear@0
|
305 unsigned int newIndex = 0;
|
nuclear@0
|
306 std::vector<unsigned int> orgPoints; // from which original point each new vertex stems
|
nuclear@0
|
307 orgPoints.resize( numVertices, 0);
|
nuclear@0
|
308
|
nuclear@0
|
309 for( unsigned int c = 0; c < faces.size(); c++)
|
nuclear@0
|
310 {
|
nuclear@0
|
311 unsigned int f = faces[c]; // index of the source face
|
nuclear@0
|
312 const XFile::Face& pf = sourceMesh->mPosFaces[f]; // position source face
|
nuclear@0
|
313
|
nuclear@0
|
314 // create face. either triangle or triangle fan depending on the index count
|
nuclear@0
|
315 aiFace& df = mesh->mFaces[c]; // destination face
|
nuclear@0
|
316 df.mNumIndices = (unsigned int)pf.mIndices.size();
|
nuclear@0
|
317 df.mIndices = new unsigned int[ df.mNumIndices];
|
nuclear@0
|
318
|
nuclear@0
|
319 // collect vertex data for indices of this face
|
nuclear@0
|
320 for( unsigned int d = 0; d < df.mNumIndices; d++)
|
nuclear@0
|
321 {
|
nuclear@0
|
322 df.mIndices[d] = newIndex;
|
nuclear@0
|
323 orgPoints[newIndex] = pf.mIndices[d];
|
nuclear@0
|
324
|
nuclear@0
|
325 // Position
|
nuclear@0
|
326 mesh->mVertices[newIndex] = sourceMesh->mPositions[pf.mIndices[d]];
|
nuclear@0
|
327 // Normal, if present
|
nuclear@0
|
328 if( mesh->HasNormals())
|
nuclear@0
|
329 mesh->mNormals[newIndex] = sourceMesh->mNormals[sourceMesh->mNormFaces[f].mIndices[d]];
|
nuclear@0
|
330
|
nuclear@0
|
331 // texture coord sets
|
nuclear@0
|
332 for( unsigned int e = 0; e < AI_MAX_NUMBER_OF_TEXTURECOORDS; e++)
|
nuclear@0
|
333 {
|
nuclear@0
|
334 if( mesh->HasTextureCoords( e))
|
nuclear@0
|
335 {
|
nuclear@0
|
336 aiVector2D tex = sourceMesh->mTexCoords[e][pf.mIndices[d]];
|
nuclear@0
|
337 mesh->mTextureCoords[e][newIndex] = aiVector3D( tex.x, 1.0f - tex.y, 0.0f);
|
nuclear@0
|
338 }
|
nuclear@0
|
339 }
|
nuclear@0
|
340 // vertex color sets
|
nuclear@0
|
341 for( unsigned int e = 0; e < AI_MAX_NUMBER_OF_COLOR_SETS; e++)
|
nuclear@0
|
342 if( mesh->HasVertexColors( e))
|
nuclear@0
|
343 mesh->mColors[e][newIndex] = sourceMesh->mColors[e][pf.mIndices[d]];
|
nuclear@0
|
344
|
nuclear@0
|
345 newIndex++;
|
nuclear@0
|
346 }
|
nuclear@0
|
347 }
|
nuclear@0
|
348
|
nuclear@0
|
349 // there should be as much new vertices as we calculated before
|
nuclear@0
|
350 ai_assert( newIndex == numVertices);
|
nuclear@0
|
351
|
nuclear@0
|
352 // convert all bones of the source mesh which influence vertices in this newly created mesh
|
nuclear@0
|
353 const std::vector<XFile::Bone>& bones = sourceMesh->mBones;
|
nuclear@0
|
354 std::vector<aiBone*> newBones;
|
nuclear@0
|
355 for( unsigned int c = 0; c < bones.size(); c++)
|
nuclear@0
|
356 {
|
nuclear@0
|
357 const XFile::Bone& obone = bones[c];
|
nuclear@0
|
358 // set up a vertex-linear array of the weights for quick searching if a bone influences a vertex
|
nuclear@0
|
359 std::vector<float> oldWeights( sourceMesh->mPositions.size(), 0.0f);
|
nuclear@0
|
360 for( unsigned int d = 0; d < obone.mWeights.size(); d++)
|
nuclear@0
|
361 oldWeights[obone.mWeights[d].mVertex] = obone.mWeights[d].mWeight;
|
nuclear@0
|
362
|
nuclear@0
|
363 // collect all vertex weights that influence a vertex in the new mesh
|
nuclear@0
|
364 std::vector<aiVertexWeight> newWeights;
|
nuclear@0
|
365 newWeights.reserve( numVertices);
|
nuclear@0
|
366 for( unsigned int d = 0; d < orgPoints.size(); d++)
|
nuclear@0
|
367 {
|
nuclear@0
|
368 // does the new vertex stem from an old vertex which was influenced by this bone?
|
nuclear@0
|
369 float w = oldWeights[orgPoints[d]];
|
nuclear@0
|
370 if( w > 0.0f)
|
nuclear@0
|
371 newWeights.push_back( aiVertexWeight( d, w));
|
nuclear@0
|
372 }
|
nuclear@0
|
373
|
nuclear@0
|
374 // if the bone has no weights in the newly created mesh, ignore it
|
nuclear@0
|
375 if( newWeights.size() == 0)
|
nuclear@0
|
376 continue;
|
nuclear@0
|
377
|
nuclear@0
|
378 // create
|
nuclear@0
|
379 aiBone* nbone = new aiBone;
|
nuclear@0
|
380 newBones.push_back( nbone);
|
nuclear@0
|
381 // copy name and matrix
|
nuclear@0
|
382 nbone->mName.Set( obone.mName);
|
nuclear@0
|
383 nbone->mOffsetMatrix = obone.mOffsetMatrix;
|
nuclear@0
|
384 nbone->mNumWeights = (unsigned int)newWeights.size();
|
nuclear@0
|
385 nbone->mWeights = new aiVertexWeight[nbone->mNumWeights];
|
nuclear@0
|
386 for( unsigned int d = 0; d < newWeights.size(); d++)
|
nuclear@0
|
387 nbone->mWeights[d] = newWeights[d];
|
nuclear@0
|
388 }
|
nuclear@0
|
389
|
nuclear@0
|
390 // store the bones in the mesh
|
nuclear@0
|
391 mesh->mNumBones = (unsigned int)newBones.size();
|
nuclear@0
|
392 if( newBones.size() > 0)
|
nuclear@0
|
393 {
|
nuclear@0
|
394 mesh->mBones = new aiBone*[mesh->mNumBones];
|
nuclear@0
|
395 std::copy( newBones.begin(), newBones.end(), mesh->mBones);
|
nuclear@0
|
396 }
|
nuclear@0
|
397 }
|
nuclear@0
|
398 }
|
nuclear@0
|
399
|
nuclear@0
|
400 // reallocate scene mesh array to be large enough
|
nuclear@0
|
401 aiMesh** prevArray = pScene->mMeshes;
|
nuclear@0
|
402 pScene->mMeshes = new aiMesh*[pScene->mNumMeshes + meshes.size()];
|
nuclear@0
|
403 if( prevArray)
|
nuclear@0
|
404 {
|
nuclear@0
|
405 memcpy( pScene->mMeshes, prevArray, pScene->mNumMeshes * sizeof( aiMesh*));
|
nuclear@0
|
406 delete [] prevArray;
|
nuclear@0
|
407 }
|
nuclear@0
|
408
|
nuclear@0
|
409 // allocate mesh index array in the node
|
nuclear@0
|
410 pNode->mNumMeshes = (unsigned int)meshes.size();
|
nuclear@0
|
411 pNode->mMeshes = new unsigned int[pNode->mNumMeshes];
|
nuclear@0
|
412
|
nuclear@0
|
413 // store all meshes in the mesh library of the scene and store their indices in the node
|
nuclear@0
|
414 for( unsigned int a = 0; a < meshes.size(); a++)
|
nuclear@0
|
415 {
|
nuclear@0
|
416 pScene->mMeshes[pScene->mNumMeshes] = meshes[a];
|
nuclear@0
|
417 pNode->mMeshes[a] = pScene->mNumMeshes;
|
nuclear@0
|
418 pScene->mNumMeshes++;
|
nuclear@0
|
419 }
|
nuclear@0
|
420 }
|
nuclear@0
|
421
|
nuclear@0
|
422 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
423 // Converts the animations from the given imported data and creates them in the scene.
|
nuclear@0
|
424 void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData)
|
nuclear@0
|
425 {
|
nuclear@0
|
426 std::vector<aiAnimation*> newAnims;
|
nuclear@0
|
427
|
nuclear@0
|
428 for( unsigned int a = 0; a < pData->mAnims.size(); a++)
|
nuclear@0
|
429 {
|
nuclear@0
|
430 const XFile::Animation* anim = pData->mAnims[a];
|
nuclear@0
|
431 // some exporters mock me with empty animation tags.
|
nuclear@0
|
432 if( anim->mAnims.size() == 0)
|
nuclear@0
|
433 continue;
|
nuclear@0
|
434
|
nuclear@0
|
435 // create a new animation to hold the data
|
nuclear@0
|
436 aiAnimation* nanim = new aiAnimation;
|
nuclear@0
|
437 newAnims.push_back( nanim);
|
nuclear@0
|
438 nanim->mName.Set( anim->mName);
|
nuclear@0
|
439 // duration will be determined by the maximum length
|
nuclear@0
|
440 nanim->mDuration = 0;
|
nuclear@0
|
441 nanim->mTicksPerSecond = pData->mAnimTicksPerSecond;
|
nuclear@0
|
442 nanim->mNumChannels = (unsigned int)anim->mAnims.size();
|
nuclear@0
|
443 nanim->mChannels = new aiNodeAnim*[nanim->mNumChannels];
|
nuclear@0
|
444
|
nuclear@0
|
445 for( unsigned int b = 0; b < anim->mAnims.size(); b++)
|
nuclear@0
|
446 {
|
nuclear@0
|
447 const XFile::AnimBone* bone = anim->mAnims[b];
|
nuclear@0
|
448 aiNodeAnim* nbone = new aiNodeAnim;
|
nuclear@0
|
449 nbone->mNodeName.Set( bone->mBoneName);
|
nuclear@0
|
450 nanim->mChannels[b] = nbone;
|
nuclear@0
|
451
|
nuclear@0
|
452 // keyframes are given as combined transformation matrix keys
|
nuclear@0
|
453 if( bone->mTrafoKeys.size() > 0)
|
nuclear@0
|
454 {
|
nuclear@0
|
455 nbone->mNumPositionKeys = (unsigned int)bone->mTrafoKeys.size();
|
nuclear@0
|
456 nbone->mPositionKeys = new aiVectorKey[nbone->mNumPositionKeys];
|
nuclear@0
|
457 nbone->mNumRotationKeys = (unsigned int)bone->mTrafoKeys.size();
|
nuclear@0
|
458 nbone->mRotationKeys = new aiQuatKey[nbone->mNumRotationKeys];
|
nuclear@0
|
459 nbone->mNumScalingKeys = (unsigned int)bone->mTrafoKeys.size();
|
nuclear@0
|
460 nbone->mScalingKeys = new aiVectorKey[nbone->mNumScalingKeys];
|
nuclear@0
|
461
|
nuclear@0
|
462 for( unsigned int c = 0; c < bone->mTrafoKeys.size(); c++)
|
nuclear@0
|
463 {
|
nuclear@0
|
464 // deconstruct each matrix into separate position, rotation and scaling
|
nuclear@0
|
465 double time = bone->mTrafoKeys[c].mTime;
|
nuclear@0
|
466 aiMatrix4x4 trafo = bone->mTrafoKeys[c].mMatrix;
|
nuclear@0
|
467
|
nuclear@0
|
468 // extract position
|
nuclear@0
|
469 aiVector3D pos( trafo.a4, trafo.b4, trafo.c4);
|
nuclear@0
|
470
|
nuclear@0
|
471 nbone->mPositionKeys[c].mTime = time;
|
nuclear@0
|
472 nbone->mPositionKeys[c].mValue = pos;
|
nuclear@0
|
473
|
nuclear@0
|
474 // extract scaling
|
nuclear@0
|
475 aiVector3D scale;
|
nuclear@0
|
476 scale.x = aiVector3D( trafo.a1, trafo.b1, trafo.c1).Length();
|
nuclear@0
|
477 scale.y = aiVector3D( trafo.a2, trafo.b2, trafo.c2).Length();
|
nuclear@0
|
478 scale.z = aiVector3D( trafo.a3, trafo.b3, trafo.c3).Length();
|
nuclear@0
|
479 nbone->mScalingKeys[c].mTime = time;
|
nuclear@0
|
480 nbone->mScalingKeys[c].mValue = scale;
|
nuclear@0
|
481
|
nuclear@0
|
482 // reconstruct rotation matrix without scaling
|
nuclear@0
|
483 aiMatrix3x3 rotmat(
|
nuclear@0
|
484 trafo.a1 / scale.x, trafo.a2 / scale.y, trafo.a3 / scale.z,
|
nuclear@0
|
485 trafo.b1 / scale.x, trafo.b2 / scale.y, trafo.b3 / scale.z,
|
nuclear@0
|
486 trafo.c1 / scale.x, trafo.c2 / scale.y, trafo.c3 / scale.z);
|
nuclear@0
|
487
|
nuclear@0
|
488 // and convert it into a quaternion
|
nuclear@0
|
489 nbone->mRotationKeys[c].mTime = time;
|
nuclear@0
|
490 nbone->mRotationKeys[c].mValue = aiQuaternion( rotmat);
|
nuclear@0
|
491 }
|
nuclear@0
|
492
|
nuclear@0
|
493 // longest lasting key sequence determines duration
|
nuclear@0
|
494 nanim->mDuration = std::max( nanim->mDuration, bone->mTrafoKeys.back().mTime);
|
nuclear@0
|
495 } else
|
nuclear@0
|
496 {
|
nuclear@0
|
497 // separate key sequences for position, rotation, scaling
|
nuclear@0
|
498 nbone->mNumPositionKeys = (unsigned int)bone->mPosKeys.size();
|
nuclear@0
|
499 nbone->mPositionKeys = new aiVectorKey[nbone->mNumPositionKeys];
|
nuclear@0
|
500 for( unsigned int c = 0; c < nbone->mNumPositionKeys; c++)
|
nuclear@0
|
501 {
|
nuclear@0
|
502 aiVector3D pos = bone->mPosKeys[c].mValue;
|
nuclear@0
|
503
|
nuclear@0
|
504 nbone->mPositionKeys[c].mTime = bone->mPosKeys[c].mTime;
|
nuclear@0
|
505 nbone->mPositionKeys[c].mValue = pos;
|
nuclear@0
|
506 }
|
nuclear@0
|
507
|
nuclear@0
|
508 // rotation
|
nuclear@0
|
509 nbone->mNumRotationKeys = (unsigned int)bone->mRotKeys.size();
|
nuclear@0
|
510 nbone->mRotationKeys = new aiQuatKey[nbone->mNumRotationKeys];
|
nuclear@0
|
511 for( unsigned int c = 0; c < nbone->mNumRotationKeys; c++)
|
nuclear@0
|
512 {
|
nuclear@0
|
513 aiMatrix3x3 rotmat = bone->mRotKeys[c].mValue.GetMatrix();
|
nuclear@0
|
514
|
nuclear@0
|
515 nbone->mRotationKeys[c].mTime = bone->mRotKeys[c].mTime;
|
nuclear@0
|
516 nbone->mRotationKeys[c].mValue = aiQuaternion( rotmat);
|
nuclear@0
|
517 nbone->mRotationKeys[c].mValue.w *= -1.0f; // needs quat inversion
|
nuclear@0
|
518 }
|
nuclear@0
|
519
|
nuclear@0
|
520 // scaling
|
nuclear@0
|
521 nbone->mNumScalingKeys = (unsigned int)bone->mScaleKeys.size();
|
nuclear@0
|
522 nbone->mScalingKeys = new aiVectorKey[nbone->mNumScalingKeys];
|
nuclear@0
|
523 for( unsigned int c = 0; c < nbone->mNumScalingKeys; c++)
|
nuclear@0
|
524 nbone->mScalingKeys[c] = bone->mScaleKeys[c];
|
nuclear@0
|
525
|
nuclear@0
|
526 // longest lasting key sequence determines duration
|
nuclear@0
|
527 if( bone->mPosKeys.size() > 0)
|
nuclear@0
|
528 nanim->mDuration = std::max( nanim->mDuration, bone->mPosKeys.back().mTime);
|
nuclear@0
|
529 if( bone->mRotKeys.size() > 0)
|
nuclear@0
|
530 nanim->mDuration = std::max( nanim->mDuration, bone->mRotKeys.back().mTime);
|
nuclear@0
|
531 if( bone->mScaleKeys.size() > 0)
|
nuclear@0
|
532 nanim->mDuration = std::max( nanim->mDuration, bone->mScaleKeys.back().mTime);
|
nuclear@0
|
533 }
|
nuclear@0
|
534 }
|
nuclear@0
|
535 }
|
nuclear@0
|
536
|
nuclear@0
|
537 // store all converted animations in the scene
|
nuclear@0
|
538 if( newAnims.size() > 0)
|
nuclear@0
|
539 {
|
nuclear@0
|
540 pScene->mNumAnimations = (unsigned int)newAnims.size();
|
nuclear@0
|
541 pScene->mAnimations = new aiAnimation* [pScene->mNumAnimations];
|
nuclear@0
|
542 for( unsigned int a = 0; a < newAnims.size(); a++)
|
nuclear@0
|
543 pScene->mAnimations[a] = newAnims[a];
|
nuclear@0
|
544 }
|
nuclear@0
|
545 }
|
nuclear@0
|
546
|
nuclear@0
|
547 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
548 // Converts all materials in the given array and stores them in the scene's material list.
|
nuclear@0
|
549 void XFileImporter::ConvertMaterials( aiScene* pScene, std::vector<XFile::Material>& pMaterials)
|
nuclear@0
|
550 {
|
nuclear@0
|
551 // count the non-referrer materials in the array
|
nuclear@0
|
552 unsigned int numNewMaterials = 0;
|
nuclear@0
|
553 for( unsigned int a = 0; a < pMaterials.size(); a++)
|
nuclear@0
|
554 if( !pMaterials[a].mIsReference)
|
nuclear@0
|
555 numNewMaterials++;
|
nuclear@0
|
556
|
nuclear@0
|
557 // resize the scene's material list to offer enough space for the new materials
|
nuclear@0
|
558 if( numNewMaterials > 0 )
|
nuclear@0
|
559 {
|
nuclear@0
|
560 aiMaterial** prevMats = pScene->mMaterials;
|
nuclear@0
|
561 pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials + numNewMaterials];
|
nuclear@0
|
562 if( prevMats)
|
nuclear@0
|
563 {
|
nuclear@0
|
564 memcpy( pScene->mMaterials, prevMats, pScene->mNumMaterials * sizeof( aiMaterial*));
|
nuclear@0
|
565 delete [] prevMats;
|
nuclear@0
|
566 }
|
nuclear@0
|
567 }
|
nuclear@0
|
568
|
nuclear@0
|
569 // convert all the materials given in the array
|
nuclear@0
|
570 for( unsigned int a = 0; a < pMaterials.size(); a++)
|
nuclear@0
|
571 {
|
nuclear@0
|
572 XFile::Material& oldMat = pMaterials[a];
|
nuclear@0
|
573 if( oldMat.mIsReference)
|
nuclear@0
|
574 {
|
nuclear@0
|
575 // find the material it refers to by name, and store its index
|
nuclear@0
|
576 for( size_t a = 0; a < pScene->mNumMaterials; ++a )
|
nuclear@0
|
577 {
|
nuclear@0
|
578 aiString name;
|
nuclear@0
|
579 pScene->mMaterials[a]->Get( AI_MATKEY_NAME, name);
|
nuclear@0
|
580 if( strcmp( name.C_Str(), oldMat.mName.data()) == 0 )
|
nuclear@0
|
581 {
|
nuclear@0
|
582 oldMat.sceneIndex = a;
|
nuclear@0
|
583 break;
|
nuclear@0
|
584 }
|
nuclear@0
|
585 }
|
nuclear@0
|
586
|
nuclear@0
|
587 if( oldMat.sceneIndex == SIZE_MAX )
|
nuclear@0
|
588 {
|
nuclear@0
|
589 DefaultLogger::get()->warn( boost::str( boost::format( "Could not resolve global material reference \"%s\"") % oldMat.mName));
|
nuclear@0
|
590 oldMat.sceneIndex = 0;
|
nuclear@0
|
591 }
|
nuclear@0
|
592
|
nuclear@0
|
593 continue;
|
nuclear@0
|
594 }
|
nuclear@0
|
595
|
nuclear@0
|
596 aiMaterial* mat = new aiMaterial;
|
nuclear@0
|
597 aiString name;
|
nuclear@0
|
598 name.Set( oldMat.mName);
|
nuclear@0
|
599 mat->AddProperty( &name, AI_MATKEY_NAME);
|
nuclear@0
|
600
|
nuclear@0
|
601 // Shading model: hardcoded to PHONG, there is no such information in an XFile
|
nuclear@0
|
602 // FIX (aramis): If the specular exponent is 0, use gouraud shading. This is a bugfix
|
nuclear@0
|
603 // for some models in the SDK (e.g. good old tiny.x)
|
nuclear@0
|
604 int shadeMode = (int)oldMat.mSpecularExponent == 0.0f
|
nuclear@0
|
605 ? aiShadingMode_Gouraud : aiShadingMode_Phong;
|
nuclear@0
|
606
|
nuclear@0
|
607 mat->AddProperty<int>( &shadeMode, 1, AI_MATKEY_SHADING_MODEL);
|
nuclear@0
|
608 // material colours
|
nuclear@0
|
609 // Unclear: there's no ambient colour, but emissive. What to put for ambient?
|
nuclear@0
|
610 // Probably nothing at all, let the user select a suitable default.
|
nuclear@0
|
611 mat->AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
|
nuclear@0
|
612 mat->AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
|
nuclear@0
|
613 mat->AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
|
nuclear@0
|
614 mat->AddProperty( &oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
|
nuclear@0
|
615
|
nuclear@0
|
616
|
nuclear@0
|
617 // texture, if there is one
|
nuclear@0
|
618 if (1 == oldMat.mTextures.size())
|
nuclear@0
|
619 {
|
nuclear@0
|
620 const XFile::TexEntry& otex = oldMat.mTextures.back();
|
nuclear@0
|
621 if (otex.mName.length())
|
nuclear@0
|
622 {
|
nuclear@0
|
623 // if there is only one texture assume it contains the diffuse color
|
nuclear@0
|
624 aiString tex( otex.mName);
|
nuclear@0
|
625 if( otex.mIsNormalMap)
|
nuclear@0
|
626 mat->AddProperty( &tex, AI_MATKEY_TEXTURE_NORMALS(0));
|
nuclear@0
|
627 else
|
nuclear@0
|
628 mat->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE(0));
|
nuclear@0
|
629 }
|
nuclear@0
|
630 }
|
nuclear@0
|
631 else
|
nuclear@0
|
632 {
|
nuclear@0
|
633 // Otherwise ... try to search for typical strings in the
|
nuclear@0
|
634 // texture's file name like 'bump' or 'diffuse'
|
nuclear@0
|
635 unsigned int iHM = 0,iNM = 0,iDM = 0,iSM = 0,iAM = 0,iEM = 0;
|
nuclear@0
|
636 for( unsigned int b = 0; b < oldMat.mTextures.size(); b++)
|
nuclear@0
|
637 {
|
nuclear@0
|
638 const XFile::TexEntry& otex = oldMat.mTextures[b];
|
nuclear@0
|
639 std::string sz = otex.mName;
|
nuclear@0
|
640 if (!sz.length())continue;
|
nuclear@0
|
641
|
nuclear@0
|
642
|
nuclear@0
|
643 // find the file name
|
nuclear@0
|
644 //const size_t iLen = sz.length();
|
nuclear@0
|
645 std::string::size_type s = sz.find_last_of("\\/");
|
nuclear@0
|
646 if (std::string::npos == s)
|
nuclear@0
|
647 s = 0;
|
nuclear@0
|
648
|
nuclear@0
|
649 // cut off the file extension
|
nuclear@0
|
650 std::string::size_type sExt = sz.find_last_of('.');
|
nuclear@0
|
651 if (std::string::npos != sExt){
|
nuclear@0
|
652 sz[sExt] = '\0';
|
nuclear@0
|
653 }
|
nuclear@0
|
654
|
nuclear@0
|
655 // convert to lower case for easier comparision
|
nuclear@0
|
656 for( unsigned int c = 0; c < sz.length(); c++)
|
nuclear@0
|
657 if( isalpha( sz[c]))
|
nuclear@0
|
658 sz[c] = tolower( sz[c]);
|
nuclear@0
|
659
|
nuclear@0
|
660
|
nuclear@0
|
661 // Place texture filename property under the corresponding name
|
nuclear@0
|
662 aiString tex( oldMat.mTextures[b].mName);
|
nuclear@0
|
663
|
nuclear@0
|
664 // bump map
|
nuclear@0
|
665 if (std::string::npos != sz.find("bump", s) || std::string::npos != sz.find("height", s))
|
nuclear@0
|
666 {
|
nuclear@0
|
667 mat->AddProperty( &tex, AI_MATKEY_TEXTURE_HEIGHT(iHM++));
|
nuclear@0
|
668 } else
|
nuclear@0
|
669 if (otex.mIsNormalMap || std::string::npos != sz.find( "normal", s) || std::string::npos != sz.find("nm", s))
|
nuclear@0
|
670 {
|
nuclear@0
|
671 mat->AddProperty( &tex, AI_MATKEY_TEXTURE_NORMALS(iNM++));
|
nuclear@0
|
672 } else
|
nuclear@0
|
673 if (std::string::npos != sz.find( "spec", s) || std::string::npos != sz.find( "glanz", s))
|
nuclear@0
|
674 {
|
nuclear@0
|
675 mat->AddProperty( &tex, AI_MATKEY_TEXTURE_SPECULAR(iSM++));
|
nuclear@0
|
676 } else
|
nuclear@0
|
677 if (std::string::npos != sz.find( "ambi", s) || std::string::npos != sz.find( "env", s))
|
nuclear@0
|
678 {
|
nuclear@0
|
679 mat->AddProperty( &tex, AI_MATKEY_TEXTURE_AMBIENT(iAM++));
|
nuclear@0
|
680 } else
|
nuclear@0
|
681 if (std::string::npos != sz.find( "emissive", s) || std::string::npos != sz.find( "self", s))
|
nuclear@0
|
682 {
|
nuclear@0
|
683 mat->AddProperty( &tex, AI_MATKEY_TEXTURE_EMISSIVE(iEM++));
|
nuclear@0
|
684 } else
|
nuclear@0
|
685 {
|
nuclear@0
|
686 // Assume it is a diffuse texture
|
nuclear@0
|
687 mat->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE(iDM++));
|
nuclear@0
|
688 }
|
nuclear@0
|
689 }
|
nuclear@0
|
690 }
|
nuclear@0
|
691
|
nuclear@0
|
692 pScene->mMaterials[pScene->mNumMaterials] = mat;
|
nuclear@0
|
693 oldMat.sceneIndex = pScene->mNumMaterials;
|
nuclear@0
|
694 pScene->mNumMaterials++;
|
nuclear@0
|
695 }
|
nuclear@0
|
696 }
|
nuclear@0
|
697
|
nuclear@0
|
698 #endif // !! ASSIMP_BUILD_NO_X_IMPORTER
|
nuclear@0
|
699
|