1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
5
6 Copyright (c) 2006-2012, assimp team
7
8 All rights reserved.
9
10 Redistribution and use of this software in source and binary forms,
11 with or without modification, are permitted provided that the following
12 conditions are met:
13
14 * Redistributions of source code must retain the above
15 copyright notice, this list of conditions and the
16 following disclaimer.
17
18 * Redistributions in binary form must reproduce the above
19 copyright notice, this list of conditions and the
20 following disclaimer in the documentation and/or other
21 materials provided with the distribution.
22
23 * Neither the name of the assimp team, nor the names of its
24 contributors may be used to endorse or promote products
25 derived from this software without specific prior
26 written permission of the assimp team.
27
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 ---------------------------------------------------------------------------
40 */
41
42 /** @file LWOLoader.cpp
43 * @brief Implementation of the LWO importer class
44 */
45
46 #include "AssimpPCH.h"
47 #ifndef ASSIMP_BUILD_NO_LWO_IMPORTER
48
49 // internal headers
50 #include "LWOLoader.h"
51 #include "StringComparison.h"
52 #include "SGSpatialSort.h"
53 #include "ByteSwap.h"
54 #include "ProcessHelper.h"
55 #include "ConvertToLHProcess.h"
56
57 using namespace Assimp;
58
59 // ------------------------------------------------------------------------------------------------
60 // Constructor to be privately used by Importer
LWOImporter()61 LWOImporter::LWOImporter()
62 {}
63
64 // ------------------------------------------------------------------------------------------------
65 // Destructor, private as well
~LWOImporter()66 LWOImporter::~LWOImporter()
67 {}
68
69 // ------------------------------------------------------------------------------------------------
70 // Returns whether the class can handle the format of the given file.
CanRead(const std::string & pFile,IOSystem * pIOHandler,bool checkSig) const71 bool LWOImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
72 {
73 const std::string extension = GetExtension(pFile);
74 if (extension == "lwo" || extension == "lxo")
75 return true;
76
77 // if check for extension is not enough, check for the magic tokens
78 if (!extension.length() || checkSig) {
79 uint32_t tokens[3];
80 tokens[0] = AI_LWO_FOURCC_LWOB;
81 tokens[1] = AI_LWO_FOURCC_LWO2;
82 tokens[2] = AI_LWO_FOURCC_LXOB;
83 return CheckMagicToken(pIOHandler,pFile,tokens,3,8);
84 }
85 return false;
86 }
87
88 // ------------------------------------------------------------------------------------------------
89 // Setup configuration properties
SetupProperties(const Importer * pImp)90 void LWOImporter::SetupProperties(const Importer* pImp)
91 {
92 configSpeedFlag = ( 0 != pImp->GetPropertyInteger(AI_CONFIG_FAVOUR_SPEED,0) ? true : false);
93 configLayerIndex = pImp->GetPropertyInteger (AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY,UINT_MAX);
94 configLayerName = pImp->GetPropertyString (AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY,"");
95 }
96
97 // ------------------------------------------------------------------------------------------------
98 // Imports the given file into the given scene structure.
InternReadFile(const std::string & pFile,aiScene * pScene,IOSystem * pIOHandler)99 void LWOImporter::InternReadFile( const std::string& pFile,
100 aiScene* pScene,
101 IOSystem* pIOHandler)
102 {
103 boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
104
105 // Check whether we can read from the file
106 if( file.get() == NULL)
107 throw DeadlyImportError( "Failed to open LWO file " + pFile + ".");
108
109 if((this->fileSize = (unsigned int)file->FileSize()) < 12)
110 throw DeadlyImportError("LWO: The file is too small to contain the IFF header");
111
112 // Allocate storage and copy the contents of the file to a memory buffer
113 std::vector< uint8_t > mBuffer(fileSize);
114 file->Read( &mBuffer[0], 1, fileSize);
115 this->pScene = pScene;
116
117 // Determine the type of the file
118 uint32_t fileType;
119 const char* sz = IFF::ReadHeader(&mBuffer[0],fileType);
120 if (sz)throw DeadlyImportError(sz);
121
122 mFileBuffer = &mBuffer[0] + 12;
123 fileSize -= 12;
124
125 // Initialize some members with their default values
126 hasNamedLayer = false;
127
128 // Create temporary storage on the stack but store pointers to it in the class
129 // instance. Therefore everything will be destructed properly if an exception
130 // is thrown and we needn't take care of that.
131 LayerList _mLayers;
132 SurfaceList _mSurfaces;
133 TagList _mTags;
134 TagMappingTable _mMapping;
135
136 mLayers = &_mLayers;
137 mTags = &_mTags;
138 mMapping = &_mMapping;
139 mSurfaces = &_mSurfaces;
140
141 // Allocate a default layer (layer indices are 1-based from now)
142 mLayers->push_back(Layer());
143 mCurLayer = &mLayers->back();
144 mCurLayer->mName = "<LWODefault>";
145 mCurLayer->mIndex = -1;
146
147 // old lightwave file format (prior to v6)
148 if (AI_LWO_FOURCC_LWOB == fileType) {
149 DefaultLogger::get()->info("LWO file format: LWOB (<= LightWave 5.5)");
150
151 mIsLWO2 = false;
152 mIsLXOB = false;
153 LoadLWOBFile();
154 }
155 // New lightwave format
156 else if (AI_LWO_FOURCC_LWO2 == fileType) {
157 mIsLXOB = false;
158 DefaultLogger::get()->info("LWO file format: LWO2 (>= LightWave 6)");
159 }
160 // MODO file format
161 else if (AI_LWO_FOURCC_LXOB == fileType) {
162 mIsLXOB = true;
163 DefaultLogger::get()->info("LWO file format: LXOB (Modo)");
164 }
165 // we don't know this format
166 else
167 {
168 char szBuff[5];
169 szBuff[0] = (char)(fileType >> 24u);
170 szBuff[1] = (char)(fileType >> 16u);
171 szBuff[2] = (char)(fileType >> 8u);
172 szBuff[3] = (char)(fileType);
173 szBuff[4] = '\0';
174 throw DeadlyImportError(std::string("Unknown LWO sub format: ") + szBuff);
175 }
176
177 if (AI_LWO_FOURCC_LWOB != fileType) {
178 mIsLWO2 = true;
179 LoadLWO2File();
180
181 // The newer lightwave format allows the user to configure the
182 // loader that just one layer is used. If this is the case
183 // we need to check now whether the requested layer has been found.
184 if (UINT_MAX != configLayerIndex) {
185 unsigned int layerCount = 0;
186 for(std::list<LWO::Layer>::iterator itLayers=mLayers->begin(); itLayers!=mLayers->end(); itLayers++)
187 if (!itLayers->skip)
188 layerCount++;
189 if (layerCount!=2)
190 throw DeadlyImportError("LWO2: The requested layer was not found");
191 }
192
193 if (configLayerName.length() && !hasNamedLayer) {
194 throw DeadlyImportError("LWO2: Unable to find the requested layer: "
195 + configLayerName);
196 }
197 }
198
199 // now, as we have loaded all data, we can resolve cross-referenced tags and clips
200 ResolveTags();
201 ResolveClips();
202
203 // now process all layers and build meshes and nodes
204 std::vector<aiMesh*> apcMeshes;
205 std::map<uint16_t, aiNode*> apcNodes;
206
207 apcMeshes.reserve(mLayers->size()*std::min(((unsigned int)mSurfaces->size()/2u), 1u));
208
209 unsigned int iDefaultSurface = UINT_MAX; // index of the default surface
210 for (LayerList::iterator lit = mLayers->begin(), lend = mLayers->end();lit != lend;++lit) {
211 LWO::Layer& layer = *lit;
212 if (layer.skip)
213 continue;
214
215 // I don't know whether there could be dummy layers, but it would be possible
216 const unsigned int meshStart = (unsigned int)apcMeshes.size();
217 if (!layer.mFaces.empty() && !layer.mTempPoints.empty()) {
218
219 // now sort all faces by the surfaces assigned to them
220 std::vector<SortedRep> pSorted(mSurfaces->size()+1);
221
222 unsigned int i = 0;
223 for (FaceList::iterator it = layer.mFaces.begin(), end = layer.mFaces.end();it != end;++it,++i) {
224 // Check whether we support this face's type
225 if ((*it).type != AI_LWO_FACE && (*it).type != AI_LWO_PTCH &&
226 (*it).type != AI_LWO_BONE && (*it).type != AI_LWO_SUBD) {
227 continue;
228 }
229
230 unsigned int idx = (*it).surfaceIndex;
231 if (idx >= mTags->size())
232 {
233 DefaultLogger::get()->warn("LWO: Invalid face surface index");
234 idx = UINT_MAX;
235 }
236 if(UINT_MAX == idx || UINT_MAX == (idx = _mMapping[idx])) {
237 if (UINT_MAX == iDefaultSurface) {
238 iDefaultSurface = (unsigned int)mSurfaces->size();
239 mSurfaces->push_back(LWO::Surface());
240 LWO::Surface& surf = mSurfaces->back();
241 surf.mColor.r = surf.mColor.g = surf.mColor.b = 0.6f;
242 surf.mName = "LWODefaultSurface";
243 }
244 idx = iDefaultSurface;
245 }
246 pSorted[idx].push_back(i);
247 }
248 if (UINT_MAX == iDefaultSurface) {
249 pSorted.erase(pSorted.end()-1);
250 }
251 for (unsigned int p = 0,i = 0;i < mSurfaces->size();++i) {
252 SortedRep& sorted = pSorted[i];
253 if (sorted.empty())
254 continue;
255
256 // generate the mesh
257 aiMesh* mesh = new aiMesh();
258 apcMeshes.push_back(mesh);
259 mesh->mNumFaces = (unsigned int)sorted.size();
260
261 // count the number of vertices
262 SortedRep::const_iterator it = sorted.begin(), end = sorted.end();
263 for (;it != end;++it) {
264 mesh->mNumVertices += layer.mFaces[*it].mNumIndices;
265 }
266
267 aiVector3D *nrm = NULL, * pv = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
268 aiFace* pf = mesh->mFaces = new aiFace[mesh->mNumFaces];
269 mesh->mMaterialIndex = i;
270
271 // find out which vertex color channels and which texture coordinate
272 // channels are really required by the material attached to this mesh
273 unsigned int vUVChannelIndices[AI_MAX_NUMBER_OF_TEXTURECOORDS];
274 unsigned int vVColorIndices[AI_MAX_NUMBER_OF_COLOR_SETS];
275
276 #if _DEBUG
277 for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_TEXTURECOORDS;++mui ) {
278 vUVChannelIndices[mui] = UINT_MAX;
279 }
280 for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_COLOR_SETS;++mui ) {
281 vVColorIndices[mui] = UINT_MAX;
282 }
283 #endif
284
285 FindUVChannels(_mSurfaces[i],sorted,layer,vUVChannelIndices);
286 FindVCChannels(_mSurfaces[i],sorted,layer,vVColorIndices);
287
288 // allocate storage for UV and CV channels
289 aiVector3D* pvUV[AI_MAX_NUMBER_OF_TEXTURECOORDS];
290 for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_TEXTURECOORDS;++mui ) {
291 if (UINT_MAX == vUVChannelIndices[mui]) {
292 break;
293 }
294
295 pvUV[mui] = mesh->mTextureCoords[mui] = new aiVector3D[mesh->mNumVertices];
296
297 // LightWave doesn't support more than 2 UV components (?)
298 mesh->mNumUVComponents[0] = 2;
299 }
300
301 if (layer.mNormals.name.length())
302 nrm = mesh->mNormals = new aiVector3D[mesh->mNumVertices];
303
304 aiColor4D* pvVC[AI_MAX_NUMBER_OF_COLOR_SETS];
305 for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_COLOR_SETS;++mui) {
306 if (UINT_MAX == vVColorIndices[mui]) {
307 break;
308 }
309 pvVC[mui] = mesh->mColors[mui] = new aiColor4D[mesh->mNumVertices];
310 }
311
312 // we would not need this extra array, but the code is much cleaner if we use it
313 std::vector<unsigned int>& smoothingGroups = layer.mPointReferrers;
314 smoothingGroups.erase (smoothingGroups.begin(),smoothingGroups.end());
315 smoothingGroups.resize(mesh->mNumFaces,0);
316
317 // now convert all faces
318 unsigned int vert = 0;
319 std::vector<unsigned int>::iterator outIt = smoothingGroups.begin();
320 for (it = sorted.begin(); it != end;++it,++outIt) {
321 const LWO::Face& face = layer.mFaces[*it];
322 *outIt = face.smoothGroup;
323
324 // copy all vertices
325 for (unsigned int q = 0; q < face.mNumIndices;++q,++vert) {
326 register unsigned int idx = face.mIndices[q];
327 *pv++ = layer.mTempPoints[idx] /*- layer.mPivot*/;
328
329 // process UV coordinates
330 for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_TEXTURECOORDS;++w) {
331 if (UINT_MAX == vUVChannelIndices[w]) {
332 break;
333 }
334 aiVector3D*& pp = pvUV[w];
335 const aiVector2D& src = ((aiVector2D*)&layer.mUVChannels[vUVChannelIndices[w]].rawData[0])[idx];
336 pp->x = src.x;
337 pp->y = src.y;
338 pp++;
339 }
340
341 // process normals (MODO extension)
342 if (nrm) {
343 *nrm = ((aiVector3D*)&layer.mNormals.rawData[0])[idx];
344 nrm->z *= -1.f;
345 ++nrm;
346 }
347
348 // process vertex colors
349 for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_COLOR_SETS;++w) {
350 if (UINT_MAX == vVColorIndices[w]) {
351 break;
352 }
353 *pvVC[w] = ((aiColor4D*)&layer.mVColorChannels[vVColorIndices[w]].rawData[0])[idx];
354
355 // If a RGB color map is explicitly requested delete the
356 // alpha channel - it could theoretically be != 1.
357 if(_mSurfaces[i].mVCMapType == AI_LWO_RGB)
358 pvVC[w]->a = 1.f;
359
360 pvVC[w]++;
361 }
362
363 #if 0
364 // process vertex weights. We can't properly reconstruct the whole skeleton for now,
365 // but we can create dummy bones for all weight channels which we have.
366 for (unsigned int w = 0; w < layer.mWeightChannels.size();++w)
367 {
368 }
369 #endif
370
371 face.mIndices[q] = vert;
372 }
373 pf->mIndices = face.mIndices;
374 pf->mNumIndices = face.mNumIndices;
375 unsigned int** p = (unsigned int**)&face.mIndices;*p = NULL; // HACK: make sure it won't be deleted
376 pf++;
377 }
378
379 if (!mesh->mNormals) {
380 // Compute normal vectors for the mesh - we can't use our GenSmoothNormal-
381 // Step here since it wouldn't handle smoothing groups correctly for LWO.
382 // So we use a separate implementation.
383 ComputeNormals(mesh,smoothingGroups,_mSurfaces[i]);
384 }
385 else DefaultLogger::get()->debug("LWO2: No need to compute normals, they're already there");
386 ++p;
387 }
388 }
389
390 // Generate nodes to render the mesh. Store the source layer in the mParent member of the nodes
391 unsigned int num = apcMeshes.size() - meshStart;
392 if (layer.mName != "<LWODefault>" || num > 0) {
393 aiNode* pcNode = new aiNode();
394 apcNodes[layer.mIndex] = pcNode;
395 pcNode->mName.Set(layer.mName);
396 pcNode->mParent = (aiNode*)&layer;
397 pcNode->mNumMeshes = num;
398
399 if (pcNode->mNumMeshes) {
400 pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
401 for (unsigned int p = 0; p < pcNode->mNumMeshes;++p)
402 pcNode->mMeshes[p] = p + meshStart;
403 }
404 }
405 }
406
407 if (apcNodes.empty() || apcMeshes.empty())
408 throw DeadlyImportError("LWO: No meshes loaded");
409
410 // The RemoveRedundantMaterials step will clean this up later
411 pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = (unsigned int)mSurfaces->size()];
412 for (unsigned int mat = 0; mat < pScene->mNumMaterials;++mat) {
413 aiMaterial* pcMat = new aiMaterial();
414 pScene->mMaterials[mat] = pcMat;
415 ConvertMaterial((*mSurfaces)[mat],pcMat);
416 }
417
418 // copy the meshes to the output structure
419 pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes = (unsigned int)apcMeshes.size() ];
420 ::memcpy(pScene->mMeshes,&apcMeshes[0],pScene->mNumMeshes*sizeof(void*));
421
422 // generate the final node graph
423 GenerateNodeGraph(apcNodes);
424 }
425
426 // ------------------------------------------------------------------------------------------------
ComputeNormals(aiMesh * mesh,const std::vector<unsigned int> & smoothingGroups,const LWO::Surface & surface)427 void LWOImporter::ComputeNormals(aiMesh* mesh, const std::vector<unsigned int>& smoothingGroups,
428 const LWO::Surface& surface)
429 {
430 // Allocate output storage
431 mesh->mNormals = new aiVector3D[mesh->mNumVertices];
432
433 // First generate per-face normals
434 aiVector3D* out;
435 std::vector<aiVector3D> faceNormals;
436
437 // ... in some cases that's already enough
438 if (!surface.mMaximumSmoothAngle)
439 out = mesh->mNormals;
440 else {
441 faceNormals.resize(mesh->mNumVertices);
442 out = &faceNormals[0];
443 }
444
445 aiFace* begin = mesh->mFaces, *const end = mesh->mFaces+mesh->mNumFaces;
446 for (; begin != end; ++begin) {
447 aiFace& face = *begin;
448
449 // LWO doc: "the normal is defined as the cross product of the first and last edges"
450 aiVector3D* pV1 = mesh->mVertices + face.mIndices[0];
451 aiVector3D* pV2 = mesh->mVertices + face.mIndices[1];
452 aiVector3D* pV3 = mesh->mVertices + face.mIndices[face.mNumIndices-1];
453
454 aiVector3D vNor = ((*pV2 - *pV1) ^(*pV3 - *pV1)).Normalize();
455 for (unsigned int i = 0; i < face.mNumIndices;++i)
456 out[face.mIndices[i]] = vNor;
457 }
458 if (!surface.mMaximumSmoothAngle)return;
459 const float posEpsilon = ComputePositionEpsilon(mesh);
460
461 // Now generate the spatial sort tree
462 SGSpatialSort sSort;
463 std::vector<unsigned int>::const_iterator it = smoothingGroups.begin();
464 for( begin = mesh->mFaces; begin != end; ++begin, ++it)
465 {
466 aiFace& face = *begin;
467 for (unsigned int i = 0; i < face.mNumIndices;++i)
468 {
469 register unsigned int tt = face.mIndices[i];
470 sSort.Add(mesh->mVertices[tt],tt,*it);
471 }
472 }
473 // Sort everything - this takes O(nlogn) time
474 sSort.Prepare();
475 std::vector<unsigned int> poResult;
476 poResult.reserve(20);
477
478 // Generate vertex normals. We have O(logn) for the binary lookup, which we need
479 // for n elements, thus the EXPECTED complexity is O(nlogn)
480 if (surface.mMaximumSmoothAngle < 3.f && !configSpeedFlag) {
481 const float fLimit = math::cos(surface.mMaximumSmoothAngle);
482
483 for( begin = mesh->mFaces, it = smoothingGroups.begin(); begin != end; ++begin, ++it) {
484 const aiFace& face = *begin;
485 unsigned int* beginIdx = face.mIndices, *const endIdx = face.mIndices+face.mNumIndices;
486 for (; beginIdx != endIdx; ++beginIdx)
487 {
488 register unsigned int idx = *beginIdx;
489 sSort.FindPositions(mesh->mVertices[idx],*it,posEpsilon,poResult,true);
490 std::vector<unsigned int>::const_iterator a, end = poResult.end();
491
492 aiVector3D vNormals;
493 for (a = poResult.begin();a != end;++a) {
494 const aiVector3D& v = faceNormals[*a];
495 if (v * faceNormals[idx] < fLimit)
496 continue;
497 vNormals += v;
498 }
499 mesh->mNormals[idx] = vNormals.Normalize();
500 }
501 }
502 }
503 // faster code path in case there is no smooth angle
504 else {
505 std::vector<bool> vertexDone(mesh->mNumVertices,false);
506 for( begin = mesh->mFaces, it = smoothingGroups.begin(); begin != end; ++begin, ++it) {
507 const aiFace& face = *begin;
508 unsigned int* beginIdx = face.mIndices, *const endIdx = face.mIndices+face.mNumIndices;
509 for (; beginIdx != endIdx; ++beginIdx)
510 {
511 register unsigned int idx = *beginIdx;
512 if (vertexDone[idx])
513 continue;
514 sSort.FindPositions(mesh->mVertices[idx],*it,posEpsilon,poResult,true);
515 std::vector<unsigned int>::const_iterator a, end = poResult.end();
516
517 aiVector3D vNormals;
518 for (a = poResult.begin();a != end;++a) {
519 const aiVector3D& v = faceNormals[*a];
520 vNormals += v;
521 }
522 vNormals.Normalize();
523 for (a = poResult.begin();a != end;++a) {
524 mesh->mNormals[*a] = vNormals;
525 vertexDone[*a] = true;
526 }
527 }
528 }
529 }
530 }
531
532 // ------------------------------------------------------------------------------------------------
GenerateNodeGraph(std::map<uint16_t,aiNode * > & apcNodes)533 void LWOImporter::GenerateNodeGraph(std::map<uint16_t,aiNode*>& apcNodes)
534 {
535 // now generate the final nodegraph - generate a root node and attach children
536 aiNode* root = pScene->mRootNode = new aiNode();
537 root->mName.Set("<LWORoot>");
538
539 //Set parent of all children, inserting pivots
540 //std::cout << "Set parent of all children" << std::endl;
541 std::map<uint16_t, aiNode*> mapPivot;
542 for (std::map<uint16_t,aiNode*>::iterator itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) {
543
544 //Get the parent index
545 LWO::Layer* nodeLayer = (LWO::Layer*)(itapcNodes->second->mParent);
546 uint16_t parentIndex = nodeLayer->mParent;
547
548 //Create pivot node, store it into the pivot map, and set the parent as the pivot
549 aiNode* pivotNode = new aiNode();
550 pivotNode->mName.Set("Pivot-"+std::string(itapcNodes->second->mName.data));
551 mapPivot[-(itapcNodes->first+2)] = pivotNode;
552 itapcNodes->second->mParent = pivotNode;
553
554 //Look for the parent node to attach the pivot to
555 if (apcNodes.find(parentIndex) != apcNodes.end()) {
556 pivotNode->mParent = apcNodes[parentIndex];
557 } else {
558 //If not, attach to the root node
559 pivotNode->mParent = root;
560 }
561
562 //Set the node and the pivot node transformation
563 itapcNodes->second->mTransformation.a4 = -nodeLayer->mPivot.x;
564 itapcNodes->second->mTransformation.b4 = -nodeLayer->mPivot.y;
565 itapcNodes->second->mTransformation.c4 = -nodeLayer->mPivot.z;
566 pivotNode->mTransformation.a4 = nodeLayer->mPivot.x;
567 pivotNode->mTransformation.b4 = nodeLayer->mPivot.y;
568 pivotNode->mTransformation.c4 = nodeLayer->mPivot.z;
569 }
570
571 //Merge pivot map into node map
572 //std::cout << "Merge pivot map into node map" << std::endl;
573 for (std::map<uint16_t, aiNode*>::iterator itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end(); ++itMapPivot) {
574 apcNodes[itMapPivot->first] = itMapPivot->second;
575 }
576
577 //Set children of all parents
578 apcNodes[-1] = root;
579 for (std::map<uint16_t,aiNode*>::iterator itMapParentNodes = apcNodes.begin(); itMapParentNodes != apcNodes.end(); ++itMapParentNodes) {
580 for (std::map<uint16_t,aiNode*>::iterator itMapChildNodes = apcNodes.begin(); itMapChildNodes != apcNodes.end(); ++itMapChildNodes) {
581 if ((itMapParentNodes->first != itMapChildNodes->first) && (itMapParentNodes->second == itMapChildNodes->second->mParent)) {
582 ++(itMapParentNodes->second->mNumChildren);
583 }
584 }
585 if (itMapParentNodes->second->mNumChildren) {
586 itMapParentNodes->second->mChildren = new aiNode* [ itMapParentNodes->second->mNumChildren ];
587 uint16_t p = 0;
588 for (std::map<uint16_t,aiNode*>::iterator itMapChildNodes = apcNodes.begin(); itMapChildNodes != apcNodes.end(); ++itMapChildNodes) {
589 if ((itMapParentNodes->first != itMapChildNodes->first) && (itMapParentNodes->second == itMapChildNodes->second->mParent)) {
590 itMapParentNodes->second->mChildren[p++] = itMapChildNodes->second;
591 }
592 }
593 }
594 }
595
596 if (!pScene->mRootNode->mNumChildren)
597 throw DeadlyImportError("LWO: Unable to build a valid node graph");
598
599 // Remove a single root node with no meshes assigned to it ...
600 if (1 == pScene->mRootNode->mNumChildren) {
601 aiNode* pc = pScene->mRootNode->mChildren[0];
602 pc->mParent = pScene->mRootNode->mChildren[0] = NULL;
603 delete pScene->mRootNode;
604 pScene->mRootNode = pc;
605 }
606
607 // convert the whole stuff to RH with CCW winding
608 MakeLeftHandedProcess maker;
609 maker.Execute(pScene);
610
611 FlipWindingOrderProcess flipper;
612 flipper.Execute(pScene);
613 }
614
615 // ------------------------------------------------------------------------------------------------
ResolveTags()616 void LWOImporter::ResolveTags()
617 {
618 // --- this function is used for both LWO2 and LWOB
619 mMapping->resize(mTags->size(), UINT_MAX);
620 for (unsigned int a = 0; a < mTags->size();++a) {
621
622 const std::string& c = (*mTags)[a];
623 for (unsigned int i = 0; i < mSurfaces->size();++i) {
624
625 const std::string& d = (*mSurfaces)[i].mName;
626 if (!ASSIMP_stricmp(c,d)) {
627
628 (*mMapping)[a] = i;
629 break;
630 }
631 }
632 }
633 }
634
635 // ------------------------------------------------------------------------------------------------
ResolveClips()636 void LWOImporter::ResolveClips()
637 {
638 for( unsigned int i = 0; i < mClips.size();++i) {
639
640 Clip& clip = mClips[i];
641 if (Clip::REF == clip.type) {
642
643 if (clip.clipRef >= mClips.size()) {
644 DefaultLogger::get()->error("LWO2: Clip referrer index is out of range");
645 clip.clipRef = 0;
646 }
647
648 Clip& dest = mClips[clip.clipRef];
649 if (Clip::REF == dest.type) {
650 DefaultLogger::get()->error("LWO2: Clip references another clip reference");
651 clip.type = Clip::UNSUPPORTED;
652 }
653
654 else {
655 clip.path = dest.path;
656 clip.type = dest.type;
657 }
658 }
659 }
660 }
661
662 // ------------------------------------------------------------------------------------------------
AdjustTexturePath(std::string & out)663 void LWOImporter::AdjustTexturePath(std::string& out)
664 {
665 // --- this function is used for both LWO2 and LWOB
666 if (!mIsLWO2 && ::strstr(out.c_str(), "(sequence)")) {
667
668 // remove the (sequence) and append 000
669 DefaultLogger::get()->info("LWOB: Sequence of animated texture found. It will be ignored");
670 out = out.substr(0,out.length()-10) + "000";
671 }
672
673 // format: drive:path/file - we just need to insert a slash after the drive
674 std::string::size_type n = out.find_first_of(':');
675 if (std::string::npos != n) {
676 out.insert(n+1,"/");
677 }
678 }
679
680 // ------------------------------------------------------------------------------------------------
LoadLWOTags(unsigned int size)681 void LWOImporter::LoadLWOTags(unsigned int size)
682 {
683 // --- this function is used for both LWO2 and LWOB
684
685 const char* szCur = (const char*)mFileBuffer, *szLast = szCur;
686 const char* const szEnd = szLast+size;
687 while (szCur < szEnd)
688 {
689 if (!(*szCur))
690 {
691 const size_t len = (size_t)(szCur-szLast);
692 // FIX: skip empty-sized tags
693 if (len)
694 mTags->push_back(std::string(szLast,len));
695 szCur += (len&0x1 ? 1 : 2);
696 szLast = szCur;
697 }
698 szCur++;
699 }
700 }
701
702 // ------------------------------------------------------------------------------------------------
LoadLWOPoints(unsigned int length)703 void LWOImporter::LoadLWOPoints(unsigned int length)
704 {
705 // --- this function is used for both LWO2 and LWOB but for
706 // LWO2 we need to allocate 25% more storage - it could be we'll
707 // need to duplicate some points later.
708 register unsigned int regularSize = (unsigned int)mCurLayer->mTempPoints.size() + length / 12;
709 if (mIsLWO2)
710 {
711 mCurLayer->mTempPoints.reserve ( regularSize + (regularSize>>2u) );
712 mCurLayer->mTempPoints.resize ( regularSize );
713
714 // initialize all point referrers with the default values
715 mCurLayer->mPointReferrers.reserve ( regularSize + (regularSize>>2u) );
716 mCurLayer->mPointReferrers.resize ( regularSize, UINT_MAX );
717 }
718 else mCurLayer->mTempPoints.resize( regularSize );
719
720 // perform endianess conversions
721 #ifndef AI_BUILD_BIG_ENDIAN
722 for (unsigned int i = 0; i < length>>2;++i)
723 ByteSwap::Swap4( mFileBuffer + (i << 2));
724 #endif
725 ::memcpy(&mCurLayer->mTempPoints[0],mFileBuffer,length);
726 }
727
728 // ------------------------------------------------------------------------------------------------
LoadLWO2Polygons(unsigned int length)729 void LWOImporter::LoadLWO2Polygons(unsigned int length)
730 {
731 LE_NCONST uint16_t* const end = (LE_NCONST uint16_t*)(mFileBuffer+length);
732 const uint32_t type = GetU4();
733
734 // Determine the type of the polygons
735 switch (type)
736 {
737 // read unsupported stuff too (although we wont process it)
738 case AI_LWO_MBAL:
739 DefaultLogger::get()->warn("LWO2: Encountered unsupported primitive chunk (METABALL)");
740 break;
741 case AI_LWO_CURV:
742 DefaultLogger::get()->warn("LWO2: Encountered unsupported primitive chunk (SPLINE)");;
743 break;
744
745 // These are ok with no restrictions
746 case AI_LWO_PTCH:
747 case AI_LWO_FACE:
748 case AI_LWO_BONE:
749 case AI_LWO_SUBD:
750 break;
751 default:
752
753 // hm!? wtf is this? ok ...
754 DefaultLogger::get()->error("LWO2: Ignoring unknown polygon type.");
755 break;
756 }
757
758 // first find out how many faces and vertices we'll finally need
759 uint16_t* cursor= (uint16_t*)mFileBuffer;
760
761 unsigned int iNumFaces = 0,iNumVertices = 0;
762 CountVertsAndFacesLWO2(iNumVertices,iNumFaces,cursor,end);
763
764 // allocate the output array and copy face indices
765 if (iNumFaces) {
766 cursor = (uint16_t*)mFileBuffer;
767
768 mCurLayer->mFaces.resize(iNumFaces,LWO::Face(type));
769 FaceList::iterator it = mCurLayer->mFaces.begin();
770 CopyFaceIndicesLWO2(it,cursor,end);
771 }
772 }
773
774 // ------------------------------------------------------------------------------------------------
CountVertsAndFacesLWO2(unsigned int & verts,unsigned int & faces,uint16_t * & cursor,const uint16_t * const end,unsigned int max)775 void LWOImporter::CountVertsAndFacesLWO2(unsigned int& verts, unsigned int& faces,
776 uint16_t*& cursor, const uint16_t* const end, unsigned int max)
777 {
778 while (cursor < end && max--)
779 {
780 AI_LSWAP2P(cursor);
781 uint16_t numIndices = *cursor++;
782 numIndices &= 0x03FF;
783 verts += numIndices;++faces;
784
785 for(uint16_t i = 0; i < numIndices; i++)
786 ReadVSizedIntLWO2((uint8_t*&)cursor);
787 }
788 }
789
790 // ------------------------------------------------------------------------------------------------
CopyFaceIndicesLWO2(FaceList::iterator & it,uint16_t * & cursor,const uint16_t * const end)791 void LWOImporter::CopyFaceIndicesLWO2(FaceList::iterator& it,
792 uint16_t*& cursor,
793 const uint16_t* const end)
794 {
795 while (cursor < end) {
796
797 LWO::Face& face = *it++;;
798 if((face.mNumIndices = (*cursor++) & 0x03FF)) /* byte swapping has already been done */ {
799 face.mIndices = new unsigned int[face.mNumIndices];
800 for(unsigned int i = 0; i < face.mNumIndices; i++)
801 {
802 face.mIndices[i] = ReadVSizedIntLWO2((uint8_t*&)cursor) + mCurLayer->mPointIDXOfs;
803 if(face.mIndices[i] > mCurLayer->mTempPoints.size())
804 {
805 DefaultLogger::get()->warn("LWO2: Failure evaluating face record, index is out of range");
806 face.mIndices[i] = (unsigned int)mCurLayer->mTempPoints.size()-1;
807 }
808 }
809 }
810 else throw DeadlyImportError("LWO2: Encountered invalid face record with zero indices");
811 }
812 }
813
814
815 // ------------------------------------------------------------------------------------------------
LoadLWO2PolygonTags(unsigned int length)816 void LWOImporter::LoadLWO2PolygonTags(unsigned int length)
817 {
818 LE_NCONST uint8_t* const end = mFileBuffer+length;
819
820 AI_LWO_VALIDATE_CHUNK_LENGTH(length,PTAG,4);
821 uint32_t type = GetU4();
822
823 if (type != AI_LWO_SURF && type != AI_LWO_SMGP)
824 return;
825
826 while (mFileBuffer < end) {
827
828 unsigned int i = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mFaceIDXOfs;
829 unsigned int j = GetU2();
830
831 if (i >= mCurLayer->mFaces.size()) {
832 DefaultLogger::get()->warn("LWO2: face index in PTAG is out of range");
833 continue;
834 }
835
836 switch (type) {
837
838 case AI_LWO_SURF:
839 mCurLayer->mFaces[i].surfaceIndex = j;
840 break;
841 case AI_LWO_SMGP: /* is that really used? */
842 mCurLayer->mFaces[i].smoothGroup = j;
843 break;
844 };
845 }
846 }
847
848 // ------------------------------------------------------------------------------------------------
849 template <class T>
FindEntry(std::vector<T> & list,const std::string & name,bool perPoly)850 VMapEntry* FindEntry(std::vector< T >& list,const std::string& name, bool perPoly)
851 {
852 for (typename std::vector< T >::iterator it = list.begin(), end = list.end();it != end; ++it) {
853 if ((*it).name == name) {
854 if (!perPoly) {
855 DefaultLogger::get()->warn("LWO2: Found two VMAP sections with equal names");
856 }
857 return &(*it);
858 }
859 }
860 list.push_back( T() );
861 VMapEntry* p = &list.back();
862 p->name = name;
863 return p;
864 }
865
866 // ------------------------------------------------------------------------------------------------
867 template <class T>
CreateNewEntry(T & chan,unsigned int srcIdx)868 inline void CreateNewEntry(T& chan, unsigned int srcIdx)
869 {
870 if (!chan.name.length())
871 return;
872
873 chan.abAssigned[srcIdx] = true;
874 chan.abAssigned.resize(chan.abAssigned.size()+1,false);
875
876 for (unsigned int a = 0; a < chan.dims;++a)
877 chan.rawData.push_back(chan.rawData[srcIdx*chan.dims+a]);
878 }
879
880 // ------------------------------------------------------------------------------------------------
881 template <class T>
CreateNewEntry(std::vector<T> & list,unsigned int srcIdx)882 inline void CreateNewEntry(std::vector< T >& list, unsigned int srcIdx)
883 {
884 for (typename std::vector< T >::iterator it = list.begin(), end = list.end();it != end;++it) {
885 CreateNewEntry( *it, srcIdx );
886 }
887 }
888
889 // ------------------------------------------------------------------------------------------------
DoRecursiveVMAPAssignment(VMapEntry * base,unsigned int numRead,unsigned int idx,float * data)890 inline void LWOImporter::DoRecursiveVMAPAssignment(VMapEntry* base, unsigned int numRead,
891 unsigned int idx, float* data)
892 {
893 ai_assert(NULL != data);
894 LWO::ReferrerList& refList = mCurLayer->mPointReferrers;
895 unsigned int i;
896
897 base->abAssigned[idx] = true;
898 for (i = 0; i < numRead;++i) {
899 base->rawData[idx*base->dims+i]= data[i];
900 }
901
902 if (UINT_MAX != (i = refList[idx])) {
903 DoRecursiveVMAPAssignment(base,numRead,i,data);
904 }
905 }
906
907 // ------------------------------------------------------------------------------------------------
AddToSingleLinkedList(ReferrerList & refList,unsigned int srcIdx,unsigned int destIdx)908 inline void AddToSingleLinkedList(ReferrerList& refList, unsigned int srcIdx, unsigned int destIdx)
909 {
910 if(UINT_MAX == refList[srcIdx]) {
911 refList[srcIdx] = destIdx;
912 return;
913 }
914 AddToSingleLinkedList(refList,refList[srcIdx],destIdx);
915 }
916
917 // ------------------------------------------------------------------------------------------------
918 // Load LWO2 vertex map
LoadLWO2VertexMap(unsigned int length,bool perPoly)919 void LWOImporter::LoadLWO2VertexMap(unsigned int length, bool perPoly)
920 {
921 LE_NCONST uint8_t* const end = mFileBuffer+length;
922
923 AI_LWO_VALIDATE_CHUNK_LENGTH(length,VMAP,6);
924 unsigned int type = GetU4();
925 unsigned int dims = GetU2();
926
927 VMapEntry* base;
928
929 // read the name of the vertex map
930 std::string name;
931 GetS0(name,length);
932
933 switch (type)
934 {
935 case AI_LWO_TXUV:
936 if (dims != 2) {
937 DefaultLogger::get()->warn("LWO2: Skipping UV channel \'"
938 + name + "\' with !2 components");
939 return;
940 }
941 base = FindEntry(mCurLayer->mUVChannels,name,perPoly);
942 break;
943 case AI_LWO_WGHT:
944 case AI_LWO_MNVW:
945 if (dims != 1) {
946 DefaultLogger::get()->warn("LWO2: Skipping Weight Channel \'"
947 + name + "\' with !1 components");
948 return;
949 }
950 base = FindEntry((type == AI_LWO_WGHT ? mCurLayer->mWeightChannels
951 : mCurLayer->mSWeightChannels),name,perPoly);
952 break;
953 case AI_LWO_RGB:
954 case AI_LWO_RGBA:
955 if (dims != 3 && dims != 4) {
956 DefaultLogger::get()->warn("LWO2: Skipping Color Map \'"
957 + name + "\' with a dimension > 4 or < 3");
958 return;
959 }
960 base = FindEntry(mCurLayer->mVColorChannels,name,perPoly);
961 break;
962
963 case AI_LWO_MODO_NORM:
964 /* This is a non-standard extension chunk used by Luxology's MODO.
965 * It stores per-vertex normals. This VMAP exists just once, has
966 * 3 dimensions and is btw extremely beautiful.
967 */
968 if (name != "vert_normals" || dims != 3 || mCurLayer->mNormals.name.length())
969 return;
970
971 DefaultLogger::get()->info("Processing non-standard extension: MODO VMAP.NORM.vert_normals");
972
973 mCurLayer->mNormals.name = name;
974 base = & mCurLayer->mNormals;
975 break;
976
977 case AI_LWO_PICK: /* these VMAPs are just silently dropped */
978 case AI_LWO_MORF:
979 case AI_LWO_SPOT:
980 return;
981
982 default:
983 if (name == "APS.Level") {
984 // XXX handle this (seems to be subdivision-related).
985 }
986 DefaultLogger::get()->warn("LWO2: Skipping unknown VMAP/VMAD channel \'" + name + "\'");
987 return;
988 };
989 base->Allocate((unsigned int)mCurLayer->mTempPoints.size());
990
991 // now read all entries in the map
992 type = std::min(dims,base->dims);
993 const unsigned int diff = (dims - type)<<2u;
994
995 LWO::FaceList& list = mCurLayer->mFaces;
996 LWO::PointList& pointList = mCurLayer->mTempPoints;
997 LWO::ReferrerList& refList = mCurLayer->mPointReferrers;
998
999 float temp[4];
1000
1001 const unsigned int numPoints = (unsigned int)pointList.size();
1002 const unsigned int numFaces = (unsigned int)list.size();
1003
1004 while (mFileBuffer < end) {
1005
1006 unsigned int idx = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mPointIDXOfs;
1007 if (idx >= numPoints) {
1008 DefaultLogger::get()->warn("LWO2: Failure evaluating VMAP/VMAD entry \'" + name + "\', vertex index is out of range");
1009 mFileBuffer += base->dims<<2u;
1010 continue;
1011 }
1012 if (perPoly) {
1013 unsigned int polyIdx = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mFaceIDXOfs;
1014 if (base->abAssigned[idx]) {
1015 // we have already a VMAP entry for this vertex - thus
1016 // we need to duplicate the corresponding polygon.
1017 if (polyIdx >= numFaces) {
1018 DefaultLogger::get()->warn("LWO2: Failure evaluating VMAD entry \'" + name + "\', polygon index is out of range");
1019 mFileBuffer += base->dims<<2u;
1020 continue;
1021 }
1022
1023 LWO::Face& src = list[polyIdx];
1024
1025 // generate a new unique vertex for the corresponding index - but only
1026 // if we can find the index in the face
1027 bool had = false;
1028 for (unsigned int i = 0; i < src.mNumIndices;++i) {
1029
1030 unsigned int srcIdx = src.mIndices[i], tmp = idx;
1031 do {
1032 if (tmp == srcIdx)
1033 break;
1034 }
1035 while ((tmp = refList[tmp]) != UINT_MAX);
1036 if (tmp == UINT_MAX) {
1037 continue;
1038 }
1039
1040 had = true;
1041 refList.resize(refList.size()+1, UINT_MAX);
1042
1043 idx = (unsigned int)pointList.size();
1044 src.mIndices[i] = (unsigned int)pointList.size();
1045
1046 // store the index of the new vertex in the old vertex
1047 // so we get a single linked list we can traverse in
1048 // only one direction
1049 AddToSingleLinkedList(refList,srcIdx,src.mIndices[i]);
1050 pointList.push_back(pointList[srcIdx]);
1051
1052 CreateNewEntry(mCurLayer->mVColorChannels, srcIdx );
1053 CreateNewEntry(mCurLayer->mUVChannels, srcIdx );
1054 CreateNewEntry(mCurLayer->mWeightChannels, srcIdx );
1055 CreateNewEntry(mCurLayer->mSWeightChannels, srcIdx );
1056 CreateNewEntry(mCurLayer->mNormals, srcIdx );
1057 }
1058 if (!had) {
1059 DefaultLogger::get()->warn("LWO2: Failure evaluating VMAD entry \'" + name + "\', vertex index wasn't found in that polygon");
1060 ai_assert(had);
1061 }
1062 }
1063 }
1064 for (unsigned int l = 0; l < type;++l)
1065 temp[l] = GetF4();
1066
1067 DoRecursiveVMAPAssignment(base,type,idx, temp);
1068 mFileBuffer += diff;
1069 }
1070 }
1071
1072 // ------------------------------------------------------------------------------------------------
1073 // Load LWO2 clip
LoadLWO2Clip(unsigned int length)1074 void LWOImporter::LoadLWO2Clip(unsigned int length)
1075 {
1076 AI_LWO_VALIDATE_CHUNK_LENGTH(length,CLIP,10);
1077
1078 mClips.push_back(LWO::Clip());
1079 LWO::Clip& clip = mClips.back();
1080
1081 // first - get the index of the clip
1082 clip.idx = GetU4();
1083
1084 IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer);
1085 switch (head->type)
1086 {
1087 case AI_LWO_STIL:
1088 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,STIL,1);
1089
1090 // "Normal" texture
1091 GetS0(clip.path,head->length);
1092 clip.type = Clip::STILL;
1093 break;
1094
1095 case AI_LWO_ISEQ:
1096 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,ISEQ,16);
1097 // Image sequence. We'll later take the first.
1098 {
1099 uint8_t digits = GetU1(); mFileBuffer++;
1100 int16_t offset = GetU2(); mFileBuffer+=4;
1101 int16_t start = GetU2(); mFileBuffer+=4;
1102
1103 std::string s;
1104 std::ostringstream ss;
1105 GetS0(s,head->length);
1106
1107 head->length -= (unsigned int)s.length()+1;
1108 ss << s;
1109 ss << std::setw(digits) << offset + start;
1110 GetS0(s,head->length);
1111 ss << s;
1112 clip.path = ss.str();
1113 clip.type = Clip::SEQ;
1114 }
1115 break;
1116
1117 case AI_LWO_STCC:
1118 DefaultLogger::get()->warn("LWO2: Color shifted images are not supported");
1119 break;
1120
1121 case AI_LWO_ANIM:
1122 DefaultLogger::get()->warn("LWO2: Animated textures are not supported");
1123 break;
1124
1125 case AI_LWO_XREF:
1126 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,XREF,4);
1127
1128 // Just a cross-reference to another CLIp
1129 clip.type = Clip::REF;
1130 clip.clipRef = GetU4();
1131 break;
1132
1133 case AI_LWO_NEGA:
1134 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,NEGA,2);
1135 clip.negate = (0 != GetU2());
1136 break;
1137
1138 default:
1139 DefaultLogger::get()->warn("LWO2: Encountered unknown CLIP subchunk");
1140 }
1141 }
1142
1143 // ------------------------------------------------------------------------------------------------
1144 // Load envelope description
LoadLWO2Envelope(unsigned int length)1145 void LWOImporter::LoadLWO2Envelope(unsigned int length)
1146 {
1147 LE_NCONST uint8_t* const end = mFileBuffer + length;
1148 AI_LWO_VALIDATE_CHUNK_LENGTH(length,ENVL,4);
1149
1150 mEnvelopes.push_back(LWO::Envelope());
1151 LWO::Envelope& envelope = mEnvelopes.back();
1152
1153 // Get the index of the envelope
1154 envelope.index = ReadVSizedIntLWO2(mFileBuffer);
1155
1156 // It looks like there might be an extra U4 right after the index,
1157 // at least in modo (LXOB) files: we'll ignore it if it's zero,
1158 // otherwise it represents the start of a subchunk, so we backtrack.
1159 if (mIsLXOB)
1160 {
1161 uint32_t extra = GetU4();
1162 if (extra)
1163 {
1164 mFileBuffer -= 4;
1165 }
1166 }
1167
1168 // ... and read all subchunks
1169 while (true)
1170 {
1171 if (mFileBuffer + 6 >= end)break;
1172 LE_NCONST IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer);
1173
1174 if (mFileBuffer + head->length > end)
1175 throw DeadlyImportError("LWO2: Invalid envelope chunk length");
1176
1177 uint8_t* const next = mFileBuffer+head->length;
1178 switch (head->type)
1179 {
1180 // Type & representation of the envelope
1181 case AI_LWO_TYPE:
1182 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,TYPE,2);
1183 mFileBuffer++; // skip user format
1184
1185 // Determine type of envelope
1186 envelope.type = (LWO::EnvelopeType)*mFileBuffer;
1187 ++mFileBuffer;
1188 break;
1189
1190 // precondition
1191 case AI_LWO_PRE:
1192 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,PRE,2);
1193 envelope.pre = (LWO::PrePostBehaviour)GetU2();
1194 break;
1195
1196 // postcondition
1197 case AI_LWO_POST:
1198 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,POST,2);
1199 envelope.post = (LWO::PrePostBehaviour)GetU2();
1200 break;
1201
1202 // keyframe
1203 case AI_LWO_KEY:
1204 {
1205 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,KEY,8);
1206
1207 envelope.keys.push_back(LWO::Key());
1208 LWO::Key& key = envelope.keys.back();
1209
1210 key.time = GetF4();
1211 key.value = GetF4();
1212 break;
1213 }
1214
1215 // interval interpolation
1216 case AI_LWO_SPAN:
1217 {
1218 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,SPAN,4);
1219 if (envelope.keys.size()<2)
1220 DefaultLogger::get()->warn("LWO2: Unexpected SPAN chunk");
1221 else {
1222 LWO::Key& key = envelope.keys.back();
1223 switch (GetU4())
1224 {
1225 case AI_LWO_STEP:
1226 key.inter = LWO::IT_STEP;break;
1227 case AI_LWO_LINE:
1228 key.inter = LWO::IT_LINE;break;
1229 case AI_LWO_TCB:
1230 key.inter = LWO::IT_TCB;break;
1231 case AI_LWO_HERM:
1232 key.inter = LWO::IT_HERM;break;
1233 case AI_LWO_BEZI:
1234 key.inter = LWO::IT_BEZI;break;
1235 case AI_LWO_BEZ2:
1236 key.inter = LWO::IT_BEZ2;break;
1237 default:
1238 DefaultLogger::get()->warn("LWO2: Unknown interval interpolation mode");
1239 };
1240
1241 // todo ... read params
1242 }
1243 break;
1244 }
1245
1246 default:
1247 DefaultLogger::get()->warn("LWO2: Encountered unknown ENVL subchunk");
1248 }
1249 // regardless how much we did actually read, go to the next chunk
1250 mFileBuffer = next;
1251 }
1252 }
1253
1254 // ------------------------------------------------------------------------------------------------
1255 // Load file - master function
LoadLWO2File()1256 void LWOImporter::LoadLWO2File()
1257 {
1258 bool skip = false;
1259
1260 LE_NCONST uint8_t* const end = mFileBuffer + fileSize;
1261 while (true)
1262 {
1263 if (mFileBuffer + sizeof(IFF::ChunkHeader) > end)break;
1264 IFF::ChunkHeader* const head = IFF::LoadChunk(mFileBuffer);
1265
1266 if (mFileBuffer + head->length > end)
1267 {
1268 throw DeadlyImportError("LWO2: Chunk length points behind the file");
1269 break;
1270 }
1271 uint8_t* const next = mFileBuffer+head->length;
1272 unsigned int iUnnamed = 0;
1273
1274 switch (head->type)
1275 {
1276 // new layer
1277 case AI_LWO_LAYR:
1278 {
1279 // add a new layer to the list ....
1280 mLayers->push_back ( LWO::Layer() );
1281 LWO::Layer& layer = mLayers->back();
1282 mCurLayer = &layer;
1283
1284 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,LAYR,16);
1285
1286 // layer index.
1287 layer.mIndex = GetU2();
1288
1289 // Continue loading this layer or ignore it? Check the layer index property
1290 if (UINT_MAX != configLayerIndex && (configLayerIndex-1) != layer.mIndex) {
1291 skip = true;
1292 }
1293 else skip = false;
1294
1295 // pivot point
1296 mFileBuffer += 2; /* unknown */
1297 mCurLayer->mPivot.x = GetF4();
1298 mCurLayer->mPivot.y = GetF4();
1299 mCurLayer->mPivot.z = GetF4();
1300 GetS0(layer.mName,head->length-16);
1301
1302 // if the name is empty, generate a default name
1303 if (layer.mName.empty()) {
1304 char buffer[128]; // should be sufficiently large
1305 ::sprintf(buffer,"Layer_%i", iUnnamed++);
1306 layer.mName = buffer;
1307 }
1308
1309 // load this layer or ignore it? Check the layer name property
1310 if (configLayerName.length() && configLayerName != layer.mName) {
1311 skip = true;
1312 }
1313 else hasNamedLayer = true;
1314
1315 // optional: parent of this layer
1316 if (mFileBuffer + 2 <= next)
1317 layer.mParent = GetU2();
1318 else layer.mParent = -1;
1319
1320 // Set layer skip parameter
1321 layer.skip = skip;
1322
1323 break;
1324 }
1325
1326 // vertex list
1327 case AI_LWO_PNTS:
1328 {
1329 if (skip)
1330 break;
1331
1332 unsigned int old = (unsigned int)mCurLayer->mTempPoints.size();
1333 LoadLWOPoints(head->length);
1334 mCurLayer->mPointIDXOfs = old;
1335 break;
1336 }
1337 // vertex tags
1338 case AI_LWO_VMAD:
1339 if (mCurLayer->mFaces.empty())
1340 {
1341 DefaultLogger::get()->warn("LWO2: Unexpected VMAD chunk");
1342 break;
1343 }
1344 // --- intentionally no break here
1345 case AI_LWO_VMAP:
1346 {
1347 if (skip)
1348 break;
1349
1350 if (mCurLayer->mTempPoints.empty())
1351 DefaultLogger::get()->warn("LWO2: Unexpected VMAP chunk");
1352 else LoadLWO2VertexMap(head->length,head->type == AI_LWO_VMAD);
1353 break;
1354 }
1355 // face list
1356 case AI_LWO_POLS:
1357 {
1358 if (skip)
1359 break;
1360
1361 unsigned int old = (unsigned int)mCurLayer->mFaces.size();
1362 LoadLWO2Polygons(head->length);
1363 mCurLayer->mFaceIDXOfs = old;
1364 break;
1365 }
1366 // polygon tags
1367 case AI_LWO_PTAG:
1368 {
1369 if (skip)
1370 break;
1371
1372 if (mCurLayer->mFaces.empty())
1373 DefaultLogger::get()->warn("LWO2: Unexpected PTAG");
1374 else LoadLWO2PolygonTags(head->length);
1375 break;
1376 }
1377 // list of tags
1378 case AI_LWO_TAGS:
1379 {
1380 if (!mTags->empty())
1381 DefaultLogger::get()->warn("LWO2: SRFS chunk encountered twice");
1382 else LoadLWOTags(head->length);
1383 break;
1384 }
1385
1386 // surface chunk
1387 case AI_LWO_SURF:
1388 {
1389 LoadLWO2Surface(head->length);
1390 break;
1391 }
1392
1393 // clip chunk
1394 case AI_LWO_CLIP:
1395 {
1396 LoadLWO2Clip(head->length);
1397 break;
1398 }
1399
1400 // envelope chunk
1401 case AI_LWO_ENVL:
1402 {
1403 LoadLWO2Envelope(head->length);
1404 break;
1405 }
1406 }
1407 mFileBuffer = next;
1408 }
1409 }
1410
1411 #endif // !! ASSIMP_BUILD_NO_LWO_IMPORTER
1412