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 3ds importer class */
|
nuclear@0
|
43
|
nuclear@0
|
44 #include "AssimpPCH.h"
|
nuclear@0
|
45 #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
|
nuclear@0
|
46
|
nuclear@0
|
47 // internal headers
|
nuclear@0
|
48 #include "3DSLoader.h"
|
nuclear@0
|
49 #include "TargetAnimation.h"
|
nuclear@0
|
50
|
nuclear@0
|
51 using namespace Assimp;
|
nuclear@0
|
52
|
nuclear@0
|
53 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
54 // Setup final material indices, generae a default material if necessary
|
nuclear@0
|
55 void Discreet3DSImporter::ReplaceDefaultMaterial()
|
nuclear@0
|
56 {
|
nuclear@0
|
57
|
nuclear@0
|
58 // Try to find an existing material that matches the
|
nuclear@0
|
59 // typical default material setting:
|
nuclear@0
|
60 // - no textures
|
nuclear@0
|
61 // - diffuse color (in grey!)
|
nuclear@0
|
62 // NOTE: This is here to workaround the fact that some
|
nuclear@0
|
63 // exporters are writing a default material, too.
|
nuclear@0
|
64 unsigned int idx = 0xcdcdcdcd;
|
nuclear@0
|
65 for (unsigned int i = 0; i < mScene->mMaterials.size();++i)
|
nuclear@0
|
66 {
|
nuclear@0
|
67 std::string s = mScene->mMaterials[i].mName;
|
nuclear@0
|
68 for (std::string::iterator it = s.begin(); it != s.end(); ++it)
|
nuclear@0
|
69 *it = ::tolower(*it);
|
nuclear@0
|
70
|
nuclear@0
|
71 if (std::string::npos == s.find("default"))continue;
|
nuclear@0
|
72
|
nuclear@0
|
73 if (mScene->mMaterials[i].mDiffuse.r !=
|
nuclear@0
|
74 mScene->mMaterials[i].mDiffuse.g ||
|
nuclear@0
|
75 mScene->mMaterials[i].mDiffuse.r !=
|
nuclear@0
|
76 mScene->mMaterials[i].mDiffuse.b)continue;
|
nuclear@0
|
77
|
nuclear@0
|
78 if (mScene->mMaterials[i].sTexDiffuse.mMapName.length() != 0 ||
|
nuclear@0
|
79 mScene->mMaterials[i].sTexBump.mMapName.length() != 0 ||
|
nuclear@0
|
80 mScene->mMaterials[i].sTexOpacity.mMapName.length() != 0 ||
|
nuclear@0
|
81 mScene->mMaterials[i].sTexEmissive.mMapName.length() != 0 ||
|
nuclear@0
|
82 mScene->mMaterials[i].sTexSpecular.mMapName.length() != 0 ||
|
nuclear@0
|
83 mScene->mMaterials[i].sTexShininess.mMapName.length() != 0 )
|
nuclear@0
|
84 {
|
nuclear@0
|
85 continue;
|
nuclear@0
|
86 }
|
nuclear@0
|
87 idx = i;
|
nuclear@0
|
88 }
|
nuclear@0
|
89 if (0xcdcdcdcd == idx)idx = (unsigned int)mScene->mMaterials.size();
|
nuclear@0
|
90
|
nuclear@0
|
91 // now iterate through all meshes and through all faces and
|
nuclear@0
|
92 // find all faces that are using the default material
|
nuclear@0
|
93 unsigned int cnt = 0;
|
nuclear@0
|
94 for (std::vector<D3DS::Mesh>::iterator
|
nuclear@0
|
95 i = mScene->mMeshes.begin();
|
nuclear@0
|
96 i != mScene->mMeshes.end();++i)
|
nuclear@0
|
97 {
|
nuclear@0
|
98 for (std::vector<unsigned int>::iterator
|
nuclear@0
|
99 a = (*i).mFaceMaterials.begin();
|
nuclear@0
|
100 a != (*i).mFaceMaterials.end();++a)
|
nuclear@0
|
101 {
|
nuclear@0
|
102 // NOTE: The additional check seems to be necessary,
|
nuclear@0
|
103 // some exporters seem to generate invalid data here
|
nuclear@0
|
104 if (0xcdcdcdcd == (*a))
|
nuclear@0
|
105 {
|
nuclear@0
|
106 (*a) = idx;
|
nuclear@0
|
107 ++cnt;
|
nuclear@0
|
108 }
|
nuclear@0
|
109 else if ( (*a) >= mScene->mMaterials.size())
|
nuclear@0
|
110 {
|
nuclear@0
|
111 (*a) = idx;
|
nuclear@0
|
112 DefaultLogger::get()->warn("Material index overflow in 3DS file. Using default material");
|
nuclear@0
|
113 ++cnt;
|
nuclear@0
|
114 }
|
nuclear@0
|
115 }
|
nuclear@0
|
116 }
|
nuclear@0
|
117 if (cnt && idx == mScene->mMaterials.size())
|
nuclear@0
|
118 {
|
nuclear@0
|
119 // We need to create our own default material
|
nuclear@0
|
120 D3DS::Material sMat;
|
nuclear@0
|
121 sMat.mDiffuse = aiColor3D(0.3f,0.3f,0.3f);
|
nuclear@0
|
122 sMat.mName = "%%%DEFAULT";
|
nuclear@0
|
123 mScene->mMaterials.push_back(sMat);
|
nuclear@0
|
124
|
nuclear@0
|
125 DefaultLogger::get()->info("3DS: Generating default material");
|
nuclear@0
|
126 }
|
nuclear@0
|
127 }
|
nuclear@0
|
128
|
nuclear@0
|
129 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
130 // Check whether all indices are valid. Otherwise we'd crash before the validation step is reached
|
nuclear@0
|
131 void Discreet3DSImporter::CheckIndices(D3DS::Mesh& sMesh)
|
nuclear@0
|
132 {
|
nuclear@0
|
133 for (std::vector< D3DS::Face >::iterator i = sMesh.mFaces.begin(); i != sMesh.mFaces.end();++i)
|
nuclear@0
|
134 {
|
nuclear@0
|
135 // check whether all indices are in range
|
nuclear@0
|
136 for (unsigned int a = 0; a < 3;++a)
|
nuclear@0
|
137 {
|
nuclear@0
|
138 if ((*i).mIndices[a] >= sMesh.mPositions.size())
|
nuclear@0
|
139 {
|
nuclear@0
|
140 DefaultLogger::get()->warn("3DS: Vertex index overflow)");
|
nuclear@0
|
141 (*i).mIndices[a] = (uint32_t)sMesh.mPositions.size()-1;
|
nuclear@0
|
142 }
|
nuclear@0
|
143 if ( !sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size())
|
nuclear@0
|
144 {
|
nuclear@0
|
145 DefaultLogger::get()->warn("3DS: Texture coordinate index overflow)");
|
nuclear@0
|
146 (*i).mIndices[a] = (uint32_t)sMesh.mTexCoords.size()-1;
|
nuclear@0
|
147 }
|
nuclear@0
|
148 }
|
nuclear@0
|
149 }
|
nuclear@0
|
150 }
|
nuclear@0
|
151
|
nuclear@0
|
152 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
153 // Generate out unique verbose format representation
|
nuclear@0
|
154 void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh)
|
nuclear@0
|
155 {
|
nuclear@0
|
156 // TODO: really necessary? I don't think. Just a waste of memory and time
|
nuclear@0
|
157 // to do it now in a separate buffer.
|
nuclear@0
|
158
|
nuclear@0
|
159 // Allocate output storage
|
nuclear@0
|
160 std::vector<aiVector3D> vNew (sMesh.mFaces.size() * 3);
|
nuclear@0
|
161 std::vector<aiVector3D> vNew2;
|
nuclear@0
|
162 if (sMesh.mTexCoords.size())
|
nuclear@0
|
163 vNew2.resize(sMesh.mFaces.size() * 3);
|
nuclear@0
|
164
|
nuclear@0
|
165 for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size();++i)
|
nuclear@0
|
166 {
|
nuclear@0
|
167 D3DS::Face& face = sMesh.mFaces[i];
|
nuclear@0
|
168
|
nuclear@0
|
169 // Positions
|
nuclear@0
|
170 for (unsigned int a = 0; a < 3;++a,++base)
|
nuclear@0
|
171 {
|
nuclear@0
|
172 vNew[base] = sMesh.mPositions[face.mIndices[a]];
|
nuclear@0
|
173 if (sMesh.mTexCoords.size())
|
nuclear@0
|
174 vNew2[base] = sMesh.mTexCoords[face.mIndices[a]];
|
nuclear@0
|
175
|
nuclear@0
|
176 face.mIndices[a] = base;
|
nuclear@0
|
177 }
|
nuclear@0
|
178 }
|
nuclear@0
|
179 sMesh.mPositions = vNew;
|
nuclear@0
|
180 sMesh.mTexCoords = vNew2;
|
nuclear@0
|
181 }
|
nuclear@0
|
182
|
nuclear@0
|
183 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
184 // Convert a 3DS texture to texture keys in an aiMaterial
|
nuclear@0
|
185 void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type)
|
nuclear@0
|
186 {
|
nuclear@0
|
187 // Setup the texture name
|
nuclear@0
|
188 aiString tex;
|
nuclear@0
|
189 tex.Set( texture.mMapName);
|
nuclear@0
|
190 mat.AddProperty( &tex, AI_MATKEY_TEXTURE(type,0));
|
nuclear@0
|
191
|
nuclear@0
|
192 // Setup the texture blend factor
|
nuclear@0
|
193 if (is_not_qnan(texture.mTextureBlend))
|
nuclear@0
|
194 mat.AddProperty<float>( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0));
|
nuclear@0
|
195
|
nuclear@0
|
196 // Setup the texture mapping mode
|
nuclear@0
|
197 mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0));
|
nuclear@0
|
198 mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0));
|
nuclear@0
|
199
|
nuclear@0
|
200 // Mirroring - double the scaling values
|
nuclear@0
|
201 // FIXME: this is not really correct ...
|
nuclear@0
|
202 if (texture.mMapMode == aiTextureMapMode_Mirror)
|
nuclear@0
|
203 {
|
nuclear@0
|
204 texture.mScaleU *= 2.f;
|
nuclear@0
|
205 texture.mScaleV *= 2.f;
|
nuclear@0
|
206 texture.mOffsetU /= 2.f;
|
nuclear@0
|
207 texture.mOffsetV /= 2.f;
|
nuclear@0
|
208 }
|
nuclear@0
|
209
|
nuclear@0
|
210 // Setup texture UV transformations
|
nuclear@0
|
211 mat.AddProperty<float>(&texture.mOffsetU,5,AI_MATKEY_UVTRANSFORM(type,0));
|
nuclear@0
|
212 }
|
nuclear@0
|
213
|
nuclear@0
|
214 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
215 // Convert a 3DS material to an aiMaterial
|
nuclear@0
|
216 void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
|
nuclear@0
|
217 aiMaterial& mat)
|
nuclear@0
|
218 {
|
nuclear@0
|
219 // NOTE: Pass the background image to the viewer by bypassing the
|
nuclear@0
|
220 // material system. This is an evil hack, never do it again!
|
nuclear@0
|
221 if (0 != mBackgroundImage.length() && bHasBG)
|
nuclear@0
|
222 {
|
nuclear@0
|
223 aiString tex;
|
nuclear@0
|
224 tex.Set( mBackgroundImage);
|
nuclear@0
|
225 mat.AddProperty( &tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE);
|
nuclear@0
|
226
|
nuclear@0
|
227 // Be sure this is only done for the first material
|
nuclear@0
|
228 mBackgroundImage = std::string("");
|
nuclear@0
|
229 }
|
nuclear@0
|
230
|
nuclear@0
|
231 // At first add the base ambient color of the scene to the material
|
nuclear@0
|
232 oldMat.mAmbient.r += mClrAmbient.r;
|
nuclear@0
|
233 oldMat.mAmbient.g += mClrAmbient.g;
|
nuclear@0
|
234 oldMat.mAmbient.b += mClrAmbient.b;
|
nuclear@0
|
235
|
nuclear@0
|
236 aiString name;
|
nuclear@0
|
237 name.Set( oldMat.mName);
|
nuclear@0
|
238 mat.AddProperty( &name, AI_MATKEY_NAME);
|
nuclear@0
|
239
|
nuclear@0
|
240 // Material colors
|
nuclear@0
|
241 mat.AddProperty( &oldMat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
|
nuclear@0
|
242 mat.AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
|
nuclear@0
|
243 mat.AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
|
nuclear@0
|
244 mat.AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
|
nuclear@0
|
245
|
nuclear@0
|
246 // Phong shininess and shininess strength
|
nuclear@0
|
247 if (D3DS::Discreet3DS::Phong == oldMat.mShading ||
|
nuclear@0
|
248 D3DS::Discreet3DS::Metal == oldMat.mShading)
|
nuclear@0
|
249 {
|
nuclear@0
|
250 if (!oldMat.mSpecularExponent || !oldMat.mShininessStrength)
|
nuclear@0
|
251 {
|
nuclear@0
|
252 oldMat.mShading = D3DS::Discreet3DS::Gouraud;
|
nuclear@0
|
253 }
|
nuclear@0
|
254 else
|
nuclear@0
|
255 {
|
nuclear@0
|
256 mat.AddProperty( &oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
|
nuclear@0
|
257 mat.AddProperty( &oldMat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH);
|
nuclear@0
|
258 }
|
nuclear@0
|
259 }
|
nuclear@0
|
260
|
nuclear@0
|
261 // Opacity
|
nuclear@0
|
262 mat.AddProperty<float>( &oldMat.mTransparency,1,AI_MATKEY_OPACITY);
|
nuclear@0
|
263
|
nuclear@0
|
264 // Bump height scaling
|
nuclear@0
|
265 mat.AddProperty<float>( &oldMat.mBumpHeight,1,AI_MATKEY_BUMPSCALING);
|
nuclear@0
|
266
|
nuclear@0
|
267 // Two sided rendering?
|
nuclear@0
|
268 if (oldMat.mTwoSided)
|
nuclear@0
|
269 {
|
nuclear@0
|
270 int i = 1;
|
nuclear@0
|
271 mat.AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED);
|
nuclear@0
|
272 }
|
nuclear@0
|
273
|
nuclear@0
|
274 // Shading mode
|
nuclear@0
|
275 aiShadingMode eShading = aiShadingMode_NoShading;
|
nuclear@0
|
276 switch (oldMat.mShading)
|
nuclear@0
|
277 {
|
nuclear@0
|
278 case D3DS::Discreet3DS::Flat:
|
nuclear@0
|
279 eShading = aiShadingMode_Flat; break;
|
nuclear@0
|
280
|
nuclear@0
|
281 // I don't know what "Wire" shading should be,
|
nuclear@0
|
282 // assume it is simple lambertian diffuse shading
|
nuclear@0
|
283 case D3DS::Discreet3DS::Wire:
|
nuclear@0
|
284 {
|
nuclear@0
|
285 // Set the wireframe flag
|
nuclear@0
|
286 unsigned int iWire = 1;
|
nuclear@0
|
287 mat.AddProperty<int>( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME);
|
nuclear@0
|
288 }
|
nuclear@0
|
289
|
nuclear@0
|
290 case D3DS::Discreet3DS::Gouraud:
|
nuclear@0
|
291 eShading = aiShadingMode_Gouraud; break;
|
nuclear@0
|
292
|
nuclear@0
|
293 // assume cook-torrance shading for metals.
|
nuclear@0
|
294 case D3DS::Discreet3DS::Phong :
|
nuclear@0
|
295 eShading = aiShadingMode_Phong; break;
|
nuclear@0
|
296
|
nuclear@0
|
297 case D3DS::Discreet3DS::Metal :
|
nuclear@0
|
298 eShading = aiShadingMode_CookTorrance; break;
|
nuclear@0
|
299
|
nuclear@0
|
300 // FIX to workaround a warning with GCC 4 who complained
|
nuclear@0
|
301 // about a missing case Blinn: here - Blinn isn't a valid
|
nuclear@0
|
302 // value in the 3DS Loader, it is just needed for ASE
|
nuclear@0
|
303 case D3DS::Discreet3DS::Blinn :
|
nuclear@0
|
304 eShading = aiShadingMode_Blinn; break;
|
nuclear@0
|
305 }
|
nuclear@0
|
306 mat.AddProperty<int>( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL);
|
nuclear@0
|
307
|
nuclear@0
|
308 // DIFFUSE texture
|
nuclear@0
|
309 if( oldMat.sTexDiffuse.mMapName.length() > 0)
|
nuclear@0
|
310 CopyTexture(mat,oldMat.sTexDiffuse, aiTextureType_DIFFUSE);
|
nuclear@0
|
311
|
nuclear@0
|
312 // SPECULAR texture
|
nuclear@0
|
313 if( oldMat.sTexSpecular.mMapName.length() > 0)
|
nuclear@0
|
314 CopyTexture(mat,oldMat.sTexSpecular, aiTextureType_SPECULAR);
|
nuclear@0
|
315
|
nuclear@0
|
316 // OPACITY texture
|
nuclear@0
|
317 if( oldMat.sTexOpacity.mMapName.length() > 0)
|
nuclear@0
|
318 CopyTexture(mat,oldMat.sTexOpacity, aiTextureType_OPACITY);
|
nuclear@0
|
319
|
nuclear@0
|
320 // EMISSIVE texture
|
nuclear@0
|
321 if( oldMat.sTexEmissive.mMapName.length() > 0)
|
nuclear@0
|
322 CopyTexture(mat,oldMat.sTexEmissive, aiTextureType_EMISSIVE);
|
nuclear@0
|
323
|
nuclear@0
|
324 // BUMP texture
|
nuclear@0
|
325 if( oldMat.sTexBump.mMapName.length() > 0)
|
nuclear@0
|
326 CopyTexture(mat,oldMat.sTexBump, aiTextureType_HEIGHT);
|
nuclear@0
|
327
|
nuclear@0
|
328 // SHININESS texture
|
nuclear@0
|
329 if( oldMat.sTexShininess.mMapName.length() > 0)
|
nuclear@0
|
330 CopyTexture(mat,oldMat.sTexShininess, aiTextureType_SHININESS);
|
nuclear@0
|
331
|
nuclear@0
|
332 // REFLECTION texture
|
nuclear@0
|
333 if( oldMat.sTexReflective.mMapName.length() > 0)
|
nuclear@0
|
334 CopyTexture(mat,oldMat.sTexReflective, aiTextureType_REFLECTION);
|
nuclear@0
|
335
|
nuclear@0
|
336 // Store the name of the material itself, too
|
nuclear@0
|
337 if( oldMat.mName.length()) {
|
nuclear@0
|
338 aiString tex;
|
nuclear@0
|
339 tex.Set( oldMat.mName);
|
nuclear@0
|
340 mat.AddProperty( &tex, AI_MATKEY_NAME);
|
nuclear@0
|
341 }
|
nuclear@0
|
342 }
|
nuclear@0
|
343
|
nuclear@0
|
344 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
345 // Split meshes by their materials and generate output aiMesh'es
|
nuclear@0
|
346 void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
|
nuclear@0
|
347 {
|
nuclear@0
|
348 std::vector<aiMesh*> avOutMeshes;
|
nuclear@0
|
349 avOutMeshes.reserve(mScene->mMeshes.size() * 2);
|
nuclear@0
|
350
|
nuclear@0
|
351 unsigned int iFaceCnt = 0,num = 0;
|
nuclear@0
|
352 aiString name;
|
nuclear@0
|
353
|
nuclear@0
|
354 // we need to split all meshes by their materials
|
nuclear@0
|
355 for (std::vector<D3DS::Mesh>::iterator i = mScene->mMeshes.begin(); i != mScene->mMeshes.end();++i) {
|
nuclear@0
|
356 boost::scoped_array< std::vector<unsigned int> > aiSplit(new std::vector<unsigned int>[mScene->mMaterials.size()]);
|
nuclear@0
|
357
|
nuclear@0
|
358 name.length = ASSIMP_itoa10(name.data,num++);
|
nuclear@0
|
359
|
nuclear@0
|
360 unsigned int iNum = 0;
|
nuclear@0
|
361 for (std::vector<unsigned int>::const_iterator a = (*i).mFaceMaterials.begin();
|
nuclear@0
|
362 a != (*i).mFaceMaterials.end();++a,++iNum)
|
nuclear@0
|
363 {
|
nuclear@0
|
364 aiSplit[*a].push_back(iNum);
|
nuclear@0
|
365 }
|
nuclear@0
|
366 // now generate submeshes
|
nuclear@0
|
367 for (unsigned int p = 0; p < mScene->mMaterials.size();++p)
|
nuclear@0
|
368 {
|
nuclear@0
|
369 if (aiSplit[p].empty()) {
|
nuclear@0
|
370 continue;
|
nuclear@0
|
371 }
|
nuclear@0
|
372 aiMesh* meshOut = new aiMesh();
|
nuclear@0
|
373 meshOut->mName = name;
|
nuclear@0
|
374 meshOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
|
nuclear@0
|
375
|
nuclear@0
|
376 // be sure to setup the correct material index
|
nuclear@0
|
377 meshOut->mMaterialIndex = p;
|
nuclear@0
|
378
|
nuclear@0
|
379 // use the color data as temporary storage
|
nuclear@0
|
380 meshOut->mColors[0] = (aiColor4D*)(&*i);
|
nuclear@0
|
381 avOutMeshes.push_back(meshOut);
|
nuclear@0
|
382
|
nuclear@0
|
383 // convert vertices
|
nuclear@0
|
384 meshOut->mNumFaces = (unsigned int)aiSplit[p].size();
|
nuclear@0
|
385 meshOut->mNumVertices = meshOut->mNumFaces*3;
|
nuclear@0
|
386
|
nuclear@0
|
387 // allocate enough storage for faces
|
nuclear@0
|
388 meshOut->mFaces = new aiFace[meshOut->mNumFaces];
|
nuclear@0
|
389 iFaceCnt += meshOut->mNumFaces;
|
nuclear@0
|
390
|
nuclear@0
|
391 meshOut->mVertices = new aiVector3D[meshOut->mNumVertices];
|
nuclear@0
|
392 meshOut->mNormals = new aiVector3D[meshOut->mNumVertices];
|
nuclear@0
|
393 if ((*i).mTexCoords.size())
|
nuclear@0
|
394 {
|
nuclear@0
|
395 meshOut->mTextureCoords[0] = new aiVector3D[meshOut->mNumVertices];
|
nuclear@0
|
396 }
|
nuclear@0
|
397 for (unsigned int q = 0, base = 0; q < aiSplit[p].size();++q)
|
nuclear@0
|
398 {
|
nuclear@0
|
399 register unsigned int index = aiSplit[p][q];
|
nuclear@0
|
400 aiFace& face = meshOut->mFaces[q];
|
nuclear@0
|
401
|
nuclear@0
|
402 face.mIndices = new unsigned int[3];
|
nuclear@0
|
403 face.mNumIndices = 3;
|
nuclear@0
|
404
|
nuclear@0
|
405 for (unsigned int a = 0; a < 3;++a,++base)
|
nuclear@0
|
406 {
|
nuclear@0
|
407 unsigned int idx = (*i).mFaces[index].mIndices[a];
|
nuclear@0
|
408 meshOut->mVertices[base] = (*i).mPositions[idx];
|
nuclear@0
|
409 meshOut->mNormals [base] = (*i).mNormals[idx];
|
nuclear@0
|
410
|
nuclear@0
|
411 if ((*i).mTexCoords.size())
|
nuclear@0
|
412 meshOut->mTextureCoords[0][base] = (*i).mTexCoords[idx];
|
nuclear@0
|
413
|
nuclear@0
|
414 face.mIndices[a] = base;
|
nuclear@0
|
415 }
|
nuclear@0
|
416 }
|
nuclear@0
|
417 }
|
nuclear@0
|
418 }
|
nuclear@0
|
419
|
nuclear@0
|
420 // Copy them to the output array
|
nuclear@0
|
421 pcOut->mNumMeshes = (unsigned int)avOutMeshes.size();
|
nuclear@0
|
422 pcOut->mMeshes = new aiMesh*[pcOut->mNumMeshes]();
|
nuclear@0
|
423 for (unsigned int a = 0; a < pcOut->mNumMeshes;++a) {
|
nuclear@0
|
424 pcOut->mMeshes[a] = avOutMeshes[a];
|
nuclear@0
|
425 }
|
nuclear@0
|
426
|
nuclear@0
|
427 // We should have at least one face here
|
nuclear@0
|
428 if (!iFaceCnt) {
|
nuclear@0
|
429 throw DeadlyImportError("No faces loaded. The mesh is empty");
|
nuclear@0
|
430 }
|
nuclear@0
|
431 }
|
nuclear@0
|
432
|
nuclear@0
|
433 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
434 // Add a node to the scenegraph and setup its final transformation
|
nuclear@0
|
435 void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
nuclear@0
|
436 D3DS::Node* pcIn, aiMatrix4x4& /*absTrafo*/)
|
nuclear@0
|
437 {
|
nuclear@0
|
438 std::vector<unsigned int> iArray;
|
nuclear@0
|
439 iArray.reserve(3);
|
nuclear@0
|
440
|
nuclear@0
|
441 aiMatrix4x4 abs;
|
nuclear@0
|
442
|
nuclear@0
|
443 // Find all meshes with the same name as the node
|
nuclear@0
|
444 for (unsigned int a = 0; a < pcSOut->mNumMeshes;++a)
|
nuclear@0
|
445 {
|
nuclear@0
|
446 const D3DS::Mesh* pcMesh = (const D3DS::Mesh*)pcSOut->mMeshes[a]->mColors[0];
|
nuclear@0
|
447 ai_assert(NULL != pcMesh);
|
nuclear@0
|
448
|
nuclear@0
|
449 if (pcIn->mName == pcMesh->mName)
|
nuclear@0
|
450 iArray.push_back(a);
|
nuclear@0
|
451 }
|
nuclear@0
|
452 if (!iArray.empty())
|
nuclear@0
|
453 {
|
nuclear@0
|
454 // The matrix should be identical for all meshes with the
|
nuclear@0
|
455 // same name. It HAS to be identical for all meshes .....
|
nuclear@0
|
456 D3DS::Mesh* imesh = ((D3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0]);
|
nuclear@0
|
457
|
nuclear@0
|
458 // Compute the inverse of the transformation matrix to move the
|
nuclear@0
|
459 // vertices back to their relative and local space
|
nuclear@0
|
460 aiMatrix4x4 mInv = imesh->mMat, mInvTransposed = imesh->mMat;
|
nuclear@0
|
461 mInv.Inverse();mInvTransposed.Transpose();
|
nuclear@0
|
462 aiVector3D pivot = pcIn->vPivot;
|
nuclear@0
|
463
|
nuclear@0
|
464 pcOut->mNumMeshes = (unsigned int)iArray.size();
|
nuclear@0
|
465 pcOut->mMeshes = new unsigned int[iArray.size()];
|
nuclear@0
|
466 for (unsigned int i = 0;i < iArray.size();++i) {
|
nuclear@0
|
467 const unsigned int iIndex = iArray[i];
|
nuclear@0
|
468 aiMesh* const mesh = pcSOut->mMeshes[iIndex];
|
nuclear@0
|
469
|
nuclear@0
|
470 // Transform the vertices back into their local space
|
nuclear@0
|
471 // fixme: consider computing normals after this, so we don't need to transform them
|
nuclear@0
|
472 const aiVector3D* const pvEnd = mesh->mVertices+mesh->mNumVertices;
|
nuclear@0
|
473 aiVector3D* pvCurrent = mesh->mVertices, *t2 = mesh->mNormals;
|
nuclear@0
|
474
|
nuclear@0
|
475 for (;pvCurrent != pvEnd;++pvCurrent,++t2) {
|
nuclear@0
|
476 *pvCurrent = mInv * (*pvCurrent);
|
nuclear@0
|
477 *t2 = mInvTransposed * (*t2);
|
nuclear@0
|
478 }
|
nuclear@0
|
479
|
nuclear@0
|
480 // Handle negative transformation matrix determinant -> invert vertex x
|
nuclear@0
|
481 if (imesh->mMat.Determinant() < 0.0f)
|
nuclear@0
|
482 {
|
nuclear@0
|
483 /* we *must* have normals */
|
nuclear@0
|
484 for (pvCurrent = mesh->mVertices,t2 = mesh->mNormals;pvCurrent != pvEnd;++pvCurrent,++t2) {
|
nuclear@0
|
485 pvCurrent->x *= -1.f;
|
nuclear@0
|
486 t2->x *= -1.f;
|
nuclear@0
|
487 }
|
nuclear@0
|
488 DefaultLogger::get()->info("3DS: Flipping mesh X-Axis");
|
nuclear@0
|
489 }
|
nuclear@0
|
490
|
nuclear@0
|
491 // Handle pivot point
|
nuclear@0
|
492 if(pivot.x || pivot.y || pivot.z)
|
nuclear@0
|
493 {
|
nuclear@0
|
494 for (pvCurrent = mesh->mVertices;pvCurrent != pvEnd;++pvCurrent) {
|
nuclear@0
|
495 *pvCurrent -= pivot;
|
nuclear@0
|
496 }
|
nuclear@0
|
497 }
|
nuclear@0
|
498
|
nuclear@0
|
499 // Setup the mesh index
|
nuclear@0
|
500 pcOut->mMeshes[i] = iIndex;
|
nuclear@0
|
501 }
|
nuclear@0
|
502 }
|
nuclear@0
|
503
|
nuclear@0
|
504 // Setup the name of the node
|
nuclear@0
|
505 pcOut->mName.Set(pcIn->mName);
|
nuclear@0
|
506
|
nuclear@0
|
507 // Now build the transformation matrix of the node
|
nuclear@0
|
508 // ROTATION
|
nuclear@0
|
509 if (pcIn->aRotationKeys.size()){
|
nuclear@0
|
510
|
nuclear@0
|
511 // FIX to get to Assimp's quaternion conventions
|
nuclear@0
|
512 for (std::vector<aiQuatKey>::iterator it = pcIn->aRotationKeys.begin(); it != pcIn->aRotationKeys.end(); ++it) {
|
nuclear@0
|
513 (*it).mValue.w *= -1.f;
|
nuclear@0
|
514 }
|
nuclear@0
|
515
|
nuclear@0
|
516 pcOut->mTransformation = aiMatrix4x4( pcIn->aRotationKeys[0].mValue.GetMatrix() );
|
nuclear@0
|
517 }
|
nuclear@0
|
518 else if (pcIn->aCameraRollKeys.size())
|
nuclear@0
|
519 {
|
nuclear@0
|
520 aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(- pcIn->aCameraRollKeys[0].mValue),
|
nuclear@0
|
521 pcOut->mTransformation);
|
nuclear@0
|
522 }
|
nuclear@0
|
523
|
nuclear@0
|
524 // SCALING
|
nuclear@0
|
525 aiMatrix4x4& m = pcOut->mTransformation;
|
nuclear@0
|
526 if (pcIn->aScalingKeys.size())
|
nuclear@0
|
527 {
|
nuclear@0
|
528 const aiVector3D& v = pcIn->aScalingKeys[0].mValue;
|
nuclear@0
|
529 m.a1 *= v.x; m.b1 *= v.x; m.c1 *= v.x;
|
nuclear@0
|
530 m.a2 *= v.y; m.b2 *= v.y; m.c2 *= v.y;
|
nuclear@0
|
531 m.a3 *= v.z; m.b3 *= v.z; m.c3 *= v.z;
|
nuclear@0
|
532 }
|
nuclear@0
|
533
|
nuclear@0
|
534 // TRANSLATION
|
nuclear@0
|
535 if (pcIn->aPositionKeys.size())
|
nuclear@0
|
536 {
|
nuclear@0
|
537 const aiVector3D& v = pcIn->aPositionKeys[0].mValue;
|
nuclear@0
|
538 m.a4 += v.x;
|
nuclear@0
|
539 m.b4 += v.y;
|
nuclear@0
|
540 m.c4 += v.z;
|
nuclear@0
|
541 }
|
nuclear@0
|
542
|
nuclear@0
|
543 // Generate animation channels for the node
|
nuclear@0
|
544 if (pcIn->aPositionKeys.size() > 1 || pcIn->aRotationKeys.size() > 1 ||
|
nuclear@0
|
545 pcIn->aScalingKeys.size() > 1 || pcIn->aCameraRollKeys.size() > 1 ||
|
nuclear@0
|
546 pcIn->aTargetPositionKeys.size() > 1)
|
nuclear@0
|
547 {
|
nuclear@0
|
548 aiAnimation* anim = pcSOut->mAnimations[0];
|
nuclear@0
|
549 ai_assert(NULL != anim);
|
nuclear@0
|
550
|
nuclear@0
|
551 if (pcIn->aCameraRollKeys.size() > 1)
|
nuclear@0
|
552 {
|
nuclear@0
|
553 DefaultLogger::get()->debug("3DS: Converting camera roll track ...");
|
nuclear@0
|
554
|
nuclear@0
|
555 // Camera roll keys - in fact they're just rotations
|
nuclear@0
|
556 // around the camera's z axis. The angles are given
|
nuclear@0
|
557 // in degrees (and they're clockwise).
|
nuclear@0
|
558 pcIn->aRotationKeys.resize(pcIn->aCameraRollKeys.size());
|
nuclear@0
|
559 for (unsigned int i = 0; i < pcIn->aCameraRollKeys.size();++i)
|
nuclear@0
|
560 {
|
nuclear@0
|
561 aiQuatKey& q = pcIn->aRotationKeys[i];
|
nuclear@0
|
562 aiFloatKey& f = pcIn->aCameraRollKeys[i];
|
nuclear@0
|
563
|
nuclear@0
|
564 q.mTime = f.mTime;
|
nuclear@0
|
565
|
nuclear@0
|
566 // FIX to get to Assimp quaternion conventions
|
nuclear@0
|
567 q.mValue = aiQuaternion(0.f,0.f,AI_DEG_TO_RAD( /*-*/ f.mValue));
|
nuclear@0
|
568 }
|
nuclear@0
|
569 }
|
nuclear@0
|
570 #if 0
|
nuclear@0
|
571 if (pcIn->aTargetPositionKeys.size() > 1)
|
nuclear@0
|
572 {
|
nuclear@0
|
573 DefaultLogger::get()->debug("3DS: Converting target track ...");
|
nuclear@0
|
574
|
nuclear@0
|
575 // Camera or spot light - need to convert the separate
|
nuclear@0
|
576 // target position channel to our representation
|
nuclear@0
|
577 TargetAnimationHelper helper;
|
nuclear@0
|
578
|
nuclear@0
|
579 if (pcIn->aPositionKeys.empty())
|
nuclear@0
|
580 {
|
nuclear@0
|
581 // We can just pass zero here ...
|
nuclear@0
|
582 helper.SetFixedMainAnimationChannel(aiVector3D());
|
nuclear@0
|
583 }
|
nuclear@0
|
584 else helper.SetMainAnimationChannel(&pcIn->aPositionKeys);
|
nuclear@0
|
585 helper.SetTargetAnimationChannel(&pcIn->aTargetPositionKeys);
|
nuclear@0
|
586
|
nuclear@0
|
587 // Do the conversion
|
nuclear@0
|
588 std::vector<aiVectorKey> distanceTrack;
|
nuclear@0
|
589 helper.Process(&distanceTrack);
|
nuclear@0
|
590
|
nuclear@0
|
591 // Now add a new node as child, name it <ourName>.Target
|
nuclear@0
|
592 // and assign the distance track to it. This is that the
|
nuclear@0
|
593 // information where the target is and how it moves is
|
nuclear@0
|
594 // not lost
|
nuclear@0
|
595 D3DS::Node* nd = new D3DS::Node();
|
nuclear@0
|
596 pcIn->push_back(nd);
|
nuclear@0
|
597
|
nuclear@0
|
598 nd->mName = pcIn->mName + ".Target";
|
nuclear@0
|
599
|
nuclear@0
|
600 aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
|
nuclear@0
|
601 nda->mNodeName.Set(nd->mName);
|
nuclear@0
|
602
|
nuclear@0
|
603 nda->mNumPositionKeys = (unsigned int)distanceTrack.size();
|
nuclear@0
|
604 nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys];
|
nuclear@0
|
605 ::memcpy(nda->mPositionKeys,&distanceTrack[0],
|
nuclear@0
|
606 sizeof(aiVectorKey)*nda->mNumPositionKeys);
|
nuclear@0
|
607 }
|
nuclear@0
|
608 #endif
|
nuclear@0
|
609
|
nuclear@0
|
610 // Cameras or lights define their transformation in their parent node and in the
|
nuclear@0
|
611 // corresponding light or camera chunks. However, we read and process the latter
|
nuclear@0
|
612 // to to be able to return valid cameras/lights even if no scenegraph is given.
|
nuclear@0
|
613 for (unsigned int n = 0; n < pcSOut->mNumCameras;++n) {
|
nuclear@0
|
614 if (pcSOut->mCameras[n]->mName == pcOut->mName) {
|
nuclear@0
|
615 pcSOut->mCameras[n]->mLookAt = aiVector3D(0.f,0.f,1.f);
|
nuclear@0
|
616 }
|
nuclear@0
|
617 }
|
nuclear@0
|
618 for (unsigned int n = 0; n < pcSOut->mNumLights;++n) {
|
nuclear@0
|
619 if (pcSOut->mLights[n]->mName == pcOut->mName) {
|
nuclear@0
|
620 pcSOut->mLights[n]->mDirection = aiVector3D(0.f,0.f,1.f);
|
nuclear@0
|
621 }
|
nuclear@0
|
622 }
|
nuclear@0
|
623
|
nuclear@0
|
624 // Allocate a new node anim and setup its name
|
nuclear@0
|
625 aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
|
nuclear@0
|
626 nda->mNodeName.Set(pcIn->mName);
|
nuclear@0
|
627
|
nuclear@0
|
628 // POSITION keys
|
nuclear@0
|
629 if (pcIn->aPositionKeys.size() > 0)
|
nuclear@0
|
630 {
|
nuclear@0
|
631 nda->mNumPositionKeys = (unsigned int)pcIn->aPositionKeys.size();
|
nuclear@0
|
632 nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys];
|
nuclear@0
|
633 ::memcpy(nda->mPositionKeys,&pcIn->aPositionKeys[0],
|
nuclear@0
|
634 sizeof(aiVectorKey)*nda->mNumPositionKeys);
|
nuclear@0
|
635 }
|
nuclear@0
|
636
|
nuclear@0
|
637 // ROTATION keys
|
nuclear@0
|
638 if (pcIn->aRotationKeys.size() > 0)
|
nuclear@0
|
639 {
|
nuclear@0
|
640 nda->mNumRotationKeys = (unsigned int)pcIn->aRotationKeys.size();
|
nuclear@0
|
641 nda->mRotationKeys = new aiQuatKey[nda->mNumRotationKeys];
|
nuclear@0
|
642
|
nuclear@0
|
643 // Rotations are quaternion offsets
|
nuclear@0
|
644 aiQuaternion abs;
|
nuclear@0
|
645 for (unsigned int n = 0; n < nda->mNumRotationKeys;++n)
|
nuclear@0
|
646 {
|
nuclear@0
|
647 const aiQuatKey& q = pcIn->aRotationKeys[n];
|
nuclear@0
|
648
|
nuclear@0
|
649 abs = (n ? abs * q.mValue : q.mValue);
|
nuclear@0
|
650 nda->mRotationKeys[n].mTime = q.mTime;
|
nuclear@0
|
651 nda->mRotationKeys[n].mValue = abs.Normalize();
|
nuclear@0
|
652 }
|
nuclear@0
|
653 }
|
nuclear@0
|
654
|
nuclear@0
|
655 // SCALING keys
|
nuclear@0
|
656 if (pcIn->aScalingKeys.size() > 0)
|
nuclear@0
|
657 {
|
nuclear@0
|
658 nda->mNumScalingKeys = (unsigned int)pcIn->aScalingKeys.size();
|
nuclear@0
|
659 nda->mScalingKeys = new aiVectorKey[nda->mNumScalingKeys];
|
nuclear@0
|
660 ::memcpy(nda->mScalingKeys,&pcIn->aScalingKeys[0],
|
nuclear@0
|
661 sizeof(aiVectorKey)*nda->mNumScalingKeys);
|
nuclear@0
|
662 }
|
nuclear@0
|
663 }
|
nuclear@0
|
664
|
nuclear@0
|
665 // Allocate storage for children
|
nuclear@0
|
666 pcOut->mNumChildren = (unsigned int)pcIn->mChildren.size();
|
nuclear@0
|
667 pcOut->mChildren = new aiNode*[pcIn->mChildren.size()];
|
nuclear@0
|
668
|
nuclear@0
|
669 // Recursively process all children
|
nuclear@0
|
670 const unsigned int size = pcIn->mChildren.size();
|
nuclear@0
|
671 for (unsigned int i = 0; i < size;++i)
|
nuclear@0
|
672 {
|
nuclear@0
|
673 pcOut->mChildren[i] = new aiNode();
|
nuclear@0
|
674 pcOut->mChildren[i]->mParent = pcOut;
|
nuclear@0
|
675 AddNodeToGraph(pcSOut,pcOut->mChildren[i],pcIn->mChildren[i],abs);
|
nuclear@0
|
676 }
|
nuclear@0
|
677 }
|
nuclear@0
|
678
|
nuclear@0
|
679 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
680 // Find out how many node animation channels we'll have finally
|
nuclear@0
|
681 void CountTracks(D3DS::Node* node, unsigned int& cnt)
|
nuclear@0
|
682 {
|
nuclear@0
|
683 //////////////////////////////////////////////////////////////////////////////
|
nuclear@0
|
684 // We will never generate more than one channel for a node, so
|
nuclear@0
|
685 // this is rather easy here.
|
nuclear@0
|
686
|
nuclear@0
|
687 if (node->aPositionKeys.size() > 1 || node->aRotationKeys.size() > 1 ||
|
nuclear@0
|
688 node->aScalingKeys.size() > 1 || node->aCameraRollKeys.size() > 1 ||
|
nuclear@0
|
689 node->aTargetPositionKeys.size() > 1)
|
nuclear@0
|
690 {
|
nuclear@0
|
691 ++cnt;
|
nuclear@0
|
692
|
nuclear@0
|
693 // account for the additional channel for the camera/spotlight target position
|
nuclear@0
|
694 if (node->aTargetPositionKeys.size() > 1)++cnt;
|
nuclear@0
|
695 }
|
nuclear@0
|
696
|
nuclear@0
|
697 // Recursively process all children
|
nuclear@0
|
698 for (unsigned int i = 0; i < node->mChildren.size();++i)
|
nuclear@0
|
699 CountTracks(node->mChildren[i],cnt);
|
nuclear@0
|
700 }
|
nuclear@0
|
701
|
nuclear@0
|
702 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
703 // Generate the output node graph
|
nuclear@0
|
704 void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
|
nuclear@0
|
705 {
|
nuclear@0
|
706 pcOut->mRootNode = new aiNode();
|
nuclear@0
|
707 if (0 == mRootNode->mChildren.size())
|
nuclear@0
|
708 {
|
nuclear@0
|
709 //////////////////////////////////////////////////////////////////////////////
|
nuclear@0
|
710 // It seems the file is so messed up that it has not even a hierarchy.
|
nuclear@0
|
711 // generate a flat hiearachy which looks like this:
|
nuclear@0
|
712 //
|
nuclear@0
|
713 // ROOT_NODE
|
nuclear@0
|
714 // |
|
nuclear@0
|
715 // ----------------------------------------
|
nuclear@0
|
716 // | | | | |
|
nuclear@0
|
717 // MESH_0 MESH_1 MESH_2 ... MESH_N CAMERA_0 ....
|
nuclear@0
|
718 //
|
nuclear@0
|
719 DefaultLogger::get()->warn("No hierarchy information has been found in the file. ");
|
nuclear@0
|
720
|
nuclear@0
|
721 pcOut->mRootNode->mNumChildren = pcOut->mNumMeshes +
|
nuclear@0
|
722 mScene->mCameras.size() + mScene->mLights.size();
|
nuclear@0
|
723
|
nuclear@0
|
724 pcOut->mRootNode->mChildren = new aiNode* [ pcOut->mRootNode->mNumChildren ];
|
nuclear@0
|
725 pcOut->mRootNode->mName.Set("<3DSDummyRoot>");
|
nuclear@0
|
726
|
nuclear@0
|
727 // Build dummy nodes for all meshes
|
nuclear@0
|
728 unsigned int a = 0;
|
nuclear@0
|
729 for (unsigned int i = 0; i < pcOut->mNumMeshes;++i,++a)
|
nuclear@0
|
730 {
|
nuclear@0
|
731 aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
|
nuclear@0
|
732 pcNode->mParent = pcOut->mRootNode;
|
nuclear@0
|
733 pcNode->mMeshes = new unsigned int[1];
|
nuclear@0
|
734 pcNode->mMeshes[0] = i;
|
nuclear@0
|
735 pcNode->mNumMeshes = 1;
|
nuclear@0
|
736
|
nuclear@0
|
737 // Build a name for the node
|
nuclear@0
|
738 pcNode->mName.length = sprintf(pcNode->mName.data,"3DSMesh_%i",i);
|
nuclear@0
|
739 }
|
nuclear@0
|
740
|
nuclear@0
|
741 // Build dummy nodes for all cameras
|
nuclear@0
|
742 for (unsigned int i = 0; i < (unsigned int )mScene->mCameras.size();++i,++a)
|
nuclear@0
|
743 {
|
nuclear@0
|
744 aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
|
nuclear@0
|
745 pcNode->mParent = pcOut->mRootNode;
|
nuclear@0
|
746
|
nuclear@0
|
747 // Build a name for the node
|
nuclear@0
|
748 pcNode->mName = mScene->mCameras[i]->mName;
|
nuclear@0
|
749 }
|
nuclear@0
|
750
|
nuclear@0
|
751 // Build dummy nodes for all lights
|
nuclear@0
|
752 for (unsigned int i = 0; i < (unsigned int )mScene->mLights.size();++i,++a)
|
nuclear@0
|
753 {
|
nuclear@0
|
754 aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
|
nuclear@0
|
755 pcNode->mParent = pcOut->mRootNode;
|
nuclear@0
|
756
|
nuclear@0
|
757 // Build a name for the node
|
nuclear@0
|
758 pcNode->mName = mScene->mLights[i]->mName;
|
nuclear@0
|
759 }
|
nuclear@0
|
760 }
|
nuclear@0
|
761 else
|
nuclear@0
|
762 {
|
nuclear@0
|
763 // First of all: find out how many scaling, rotation and translation
|
nuclear@0
|
764 // animation tracks we'll have afterwards
|
nuclear@0
|
765 unsigned int numChannel = 0;
|
nuclear@0
|
766 CountTracks(mRootNode,numChannel);
|
nuclear@0
|
767
|
nuclear@0
|
768 if (numChannel)
|
nuclear@0
|
769 {
|
nuclear@0
|
770 // Allocate a primary animation channel
|
nuclear@0
|
771 pcOut->mNumAnimations = 1;
|
nuclear@0
|
772 pcOut->mAnimations = new aiAnimation*[1];
|
nuclear@0
|
773 aiAnimation* anim = pcOut->mAnimations[0] = new aiAnimation();
|
nuclear@0
|
774
|
nuclear@0
|
775 anim->mName.Set("3DSMasterAnim");
|
nuclear@0
|
776
|
nuclear@0
|
777 // Allocate enough storage for all node animation channels,
|
nuclear@0
|
778 // but don't set the mNumChannels member - we'll use it to
|
nuclear@0
|
779 // index into the array
|
nuclear@0
|
780 anim->mChannels = new aiNodeAnim*[numChannel];
|
nuclear@0
|
781 }
|
nuclear@0
|
782
|
nuclear@0
|
783 aiMatrix4x4 m;
|
nuclear@0
|
784 AddNodeToGraph(pcOut, pcOut->mRootNode, mRootNode,m);
|
nuclear@0
|
785 }
|
nuclear@0
|
786
|
nuclear@0
|
787 // We used the first vertex color set to store some emporary values so we need to cleanup here
|
nuclear@0
|
788 for (unsigned int a = 0; a < pcOut->mNumMeshes;++a)
|
nuclear@0
|
789 pcOut->mMeshes[a]->mColors[0] = NULL;
|
nuclear@0
|
790
|
nuclear@0
|
791 pcOut->mRootNode->mTransformation = aiMatrix4x4(
|
nuclear@0
|
792 1.f,0.f,0.f,0.f,
|
nuclear@0
|
793 0.f,0.f,1.f,0.f,
|
nuclear@0
|
794 0.f,-1.f,0.f,0.f,
|
nuclear@0
|
795 0.f,0.f,0.f,1.f) * pcOut->mRootNode->mTransformation;
|
nuclear@0
|
796
|
nuclear@0
|
797 // If the root node is unnamed name it "<3DSRoot>"
|
nuclear@0
|
798 if (::strstr( pcOut->mRootNode->mName.data, "UNNAMED" ) ||
|
nuclear@0
|
799 (pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$') )
|
nuclear@0
|
800 {
|
nuclear@0
|
801 pcOut->mRootNode->mName.Set("<3DSRoot>");
|
nuclear@0
|
802 }
|
nuclear@0
|
803 }
|
nuclear@0
|
804
|
nuclear@0
|
805 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
806 // Convert all meshes in the scene and generate the final output scene.
|
nuclear@0
|
807 void Discreet3DSImporter::ConvertScene(aiScene* pcOut)
|
nuclear@0
|
808 {
|
nuclear@0
|
809 // Allocate enough storage for all output materials
|
nuclear@0
|
810 pcOut->mNumMaterials = (unsigned int)mScene->mMaterials.size();
|
nuclear@0
|
811 pcOut->mMaterials = new aiMaterial*[pcOut->mNumMaterials];
|
nuclear@0
|
812
|
nuclear@0
|
813 // ... and convert the 3DS materials to aiMaterial's
|
nuclear@0
|
814 for (unsigned int i = 0; i < pcOut->mNumMaterials;++i)
|
nuclear@0
|
815 {
|
nuclear@0
|
816 aiMaterial* pcNew = new aiMaterial();
|
nuclear@0
|
817 ConvertMaterial(mScene->mMaterials[i],*pcNew);
|
nuclear@0
|
818 pcOut->mMaterials[i] = pcNew;
|
nuclear@0
|
819 }
|
nuclear@0
|
820
|
nuclear@0
|
821 // Generate the output mesh list
|
nuclear@0
|
822 ConvertMeshes(pcOut);
|
nuclear@0
|
823
|
nuclear@0
|
824 // Now copy all light sources to the output scene
|
nuclear@0
|
825 pcOut->mNumLights = (unsigned int)mScene->mLights.size();
|
nuclear@0
|
826 if (pcOut->mNumLights)
|
nuclear@0
|
827 {
|
nuclear@0
|
828 pcOut->mLights = new aiLight*[pcOut->mNumLights];
|
nuclear@0
|
829 ::memcpy(pcOut->mLights,&mScene->mLights[0],sizeof(void*)*pcOut->mNumLights);
|
nuclear@0
|
830 }
|
nuclear@0
|
831
|
nuclear@0
|
832 // Now copy all cameras to the output scene
|
nuclear@0
|
833 pcOut->mNumCameras = (unsigned int)mScene->mCameras.size();
|
nuclear@0
|
834 if (pcOut->mNumCameras)
|
nuclear@0
|
835 {
|
nuclear@0
|
836 pcOut->mCameras = new aiCamera*[pcOut->mNumCameras];
|
nuclear@0
|
837 ::memcpy(pcOut->mCameras,&mScene->mCameras[0],sizeof(void*)*pcOut->mNumCameras);
|
nuclear@0
|
838 }
|
nuclear@0
|
839 }
|
nuclear@0
|
840
|
nuclear@0
|
841 #endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER
|