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