Bläddra i källkod

STL bugfix. LWO2 next WIP version, deactivated for the moment (as I'm away for a week. LWOB (LightWave 1-4) remains activated).

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@113 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
aramis_acg 17 år sedan
förälder
incheckning
b2a1268711
6 ändrade filer med 759 tillägg och 478 borttagningar
  1. 34 0
      code/LWOFileData.h
  2. 335 117
      code/LWOLoader.cpp
  3. 40 27
      code/LWOLoader.h
  4. 0 2
      code/STLLoader.cpp
  5. 10 0
      include/aiScene.h
  6. 340 332
      workspaces/vc8/assimp.vcproj

+ 34 - 0
code/LWOFileData.h

@@ -52,6 +52,7 @@ Original copyright notice: "Ernie Wright  17 Sep 00"
 
 #include "IFF.h"
 #include <vector>
+#include <list>
 #include "../include/aiMesh.h"
 
 namespace Assimp {
@@ -334,6 +335,39 @@ struct Surface
 		break; \
 	} \
 
+
+typedef std::vector<aiVector3D>		PointList;
+typedef std::vector<LWO::Face>		FaceList;
+typedef std::vector<LWO::Surface>	SurfaceList;
+typedef std::vector<std::string>	TagList;
+typedef std::vector<unsigned int>	TagMappingTable;
+
+
+// ---------------------------------------------------------------------------
+/** \brief Represents a layer in the file
+ */
+struct Layer
+{
+	Layer()
+		: mParent (0xffff)
+	{}
+
+	/** Temporary point list from the file */
+	PointList mTempPoints;
+
+	/** Temporary face list from the file*/
+	FaceList mFaces;
+
+	/** Parent index */
+	uint16_t mParent;
+
+	/** Name of the layer */
+	std::string mName;
+};
+
+typedef std::list<LWO::Layer>		LayerList;
+
+
 }}
 
 

+ 335 - 117
code/LWOLoader.cpp

@@ -126,13 +126,11 @@ void LWOImporter::InternReadFile( const std::string& pFile,
 	mFileBuffer = &mBuffer[0] + 12;
 	fileSize -= 12;
 
-	// create temporary storage on the stack but store points to
-	// it in the class instance. Therefoe everything will be destructed
-	// properly if an exception is thrown.
-	PointList _mTempPoints;		
-	mTempPoints = &_mTempPoints;
-	FaceList _mFaces;			
-	mFaces = &_mFaces;
+	// create temporary storage on the stack but store pointers to it in the class 
+	// instance. Therefore everything will be destructed properly if an exception 
+	// is thrown and we needn't take care of that.
+	LayerList _mLayers;
+	mLayers = &_mLayers;
 	TagList _mTags;				
 	mTags = &_mTags;
 	TagMappingTable _mMapping;	
@@ -140,6 +138,11 @@ void LWOImporter::InternReadFile( const std::string& pFile,
 	SurfaceList _mSurfaces;		
 	mSurfaces = &_mSurfaces;
 
+	// allocate a default layer
+	mLayers->push_back(Layer());
+	mCurLayer = &mLayers->back();
+	mCurLayer->mName = "<LWODefault>";
+
 	// old lightwave file format (prior to v6)
 	if (AI_LWO_FOURCC_LWOB == fileType)
 	{
@@ -150,6 +153,7 @@ void LWOImporter::InternReadFile( const std::string& pFile,
 	// new lightwave format
 	else if (AI_LWO_FOURCC_LWO2 == fileType)
 	{
+		throw new ImportErrorException("LWO2 is under development and currently disabled.");
 		mIsLWO2 = true;
 		this->LoadLWO2File();
 	}
@@ -166,100 +170,210 @@ void LWOImporter::InternReadFile( const std::string& pFile,
 	}
 	ResolveTags();
 
-	// now sort all faces by the surfaces assigned to them
-	typedef std::vector<unsigned int> SortedRep;
-	std::vector<SortedRep> pSorted(mSurfaces->size()+1);
+	// now process all layers and build meshes and nodes
+	std::vector<aiMesh*> apcMeshes;
+	std::vector<aiNode*> apcNodes;
+	apcNodes.reserve(mLayers->size());
+	apcMeshes.reserve(mLayers->size()*std::min((mSurfaces->size()/2u), 1u));
 
-	unsigned int i = 0;
-	unsigned int iDefaultSurface = 0xffffffff;
-	for (FaceList::iterator it = mFaces->begin(), end = mFaces->end();
-		it != end;++it,++i)
+	// the RemoveRedundantMaterials step will clean this up later
+	pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = mSurfaces->size()];
+	for (unsigned int mat = 0; mat < pScene->mNumMaterials;++mat)
 	{
-		unsigned int idx = (*it).surfaceIndex;
-		if (idx >= mTags->size())
-		{
-			DefaultLogger::get()->warn("LWO: Invalid face surface index");
-			idx = mTags->size()-1;
-		}
-		if(0xffffffff == (idx = _mMapping[idx]))
+		MaterialHelper* pcMat = new MaterialHelper();
+		pScene->mMaterials[mat] = pcMat;
+		ConvertMaterial((*mSurfaces)[mat],pcMat);
+	}
+
+	unsigned int iDefaultSurface = 0xffffffff; // index of the default surface
+	for (LayerList::const_iterator lit = mLayers->begin(), lend = mLayers->end();
+		lit != lend;++lit)
+	{
+		const LWO::Layer& layer = *lit;
+
+		// I don't know whether there could be dummy layers, but it would be possible
+		const unsigned int meshStart = apcMeshes.size();
+		if (!layer.mFaces.empty() && !layer.mTempPoints.empty())
 		{
-			if (0xffffffff == iDefaultSurface)
+			// now sort all faces by the surfaces assigned to them
+			typedef std::vector<unsigned int> SortedRep;
+			std::vector<SortedRep> pSorted(mSurfaces->size()+1);
+
+			unsigned int i = 0;
+			for (FaceList::const_iterator it = layer.mFaces.begin(), end = layer.mFaces.end();
+				it != end;++it,++i)
 			{
-				iDefaultSurface = mSurfaces->size();
-				mSurfaces->push_back(LWO::Surface());
-				LWO::Surface& surf = mSurfaces->back();
-				surf.mColor.r = surf.mColor.g = surf.mColor.b = 0.6f; 
+				unsigned int idx = (*it).surfaceIndex;
+				if (idx >= mTags->size())
+				{
+					DefaultLogger::get()->warn("LWO: Invalid face surface index");
+					idx = mTags->size()-1;
+				}
+				if(0xffffffff == (idx = _mMapping[idx]))
+				{
+					if (0xffffffff == iDefaultSurface)
+					{
+						iDefaultSurface = mSurfaces->size();
+						mSurfaces->push_back(LWO::Surface());
+						LWO::Surface& surf = mSurfaces->back();
+						surf.mColor.r = surf.mColor.g = surf.mColor.b = 0.6f; 
+					}
+					idx = iDefaultSurface;
+				}
+				pSorted[idx].push_back(i);
 			}
-			idx = iDefaultSurface;
-		}
-		pSorted[idx].push_back(i);
-	}
-	if (0xffffffff == iDefaultSurface)pSorted.erase(pSorted.end()-1);
+			if (0xffffffff == iDefaultSurface)pSorted.erase(pSorted.end()-1);
 
-	// now generate output meshes
-	for (unsigned int p = 0; p < mSurfaces->size();++p)
-		if (!pSorted[p].empty())pScene->mNumMeshes++;
+			// now generate output meshes
+			for (unsigned int p = 0; p < mSurfaces->size();++p)
+				if (!pSorted[p].empty())pScene->mNumMeshes++;
 
-	if (!(pScene->mNumMaterials = pScene->mNumMeshes))
-		throw new ImportErrorException("LWO: There are no meshes");
+			if (!pScene->mNumMeshes)
+				throw new ImportErrorException("LWO: There are no meshes");
 
-	pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
-	pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
-	for (unsigned int p = 0,i = 0;i < mSurfaces->size();++i)
-	{
-		SortedRep& sorted = pSorted[i];
-		if (sorted.empty())continue;
+			pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
+			for (unsigned int p = 0,i = 0;i < mSurfaces->size();++i)
+			{
+				SortedRep& sorted = pSorted[i];
+				if (sorted.empty())continue;
 
-		// generate the mesh 
-		aiMesh* mesh = pScene->mMeshes[p] = new aiMesh();
-		mesh->mNumFaces = sorted.size();
-		if ((*mSurfaces)[i].mMaximumSmoothAngle)
-			mesh->mMaxSmoothingAngle = AI_DEG_TO_RAD((*mSurfaces)[i].mMaximumSmoothAngle);
+				// generate the mesh 
+				aiMesh* mesh = new aiMesh();
+				apcMeshes.push_back(mesh);
+				mesh->mNumFaces = sorted.size();
 
-		for (SortedRep::const_iterator it = sorted.begin(), end = sorted.end();
-			it != end;++it)
-		{
-			mesh->mNumVertices += _mFaces[*it].mNumIndices;
+				for (SortedRep::const_iterator it = sorted.begin(), end = sorted.end();
+					it != end;++it)
+				{
+					mesh->mNumVertices += layer.mFaces[*it].mNumIndices;
+				}
+
+				aiVector3D* pv = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
+				aiFace* pf = mesh->mFaces = new aiFace[mesh->mNumFaces];
+				mesh->mMaterialIndex = i;
+
+				// now convert all faces
+				unsigned int vert = 0;
+				for (SortedRep::const_iterator it = sorted.begin(), end = sorted.end();
+					it != end;++it)
+				{
+					const LWO::Face& face = layer.mFaces[*it];
+
+					// copy all vertices
+					for (unsigned int q = 0; q  < face.mNumIndices;++q)
+					{
+						*pv++ = layer.mTempPoints[face.mIndices[q]];
+						face.mIndices[q] = vert++;
+					}
+
+					pf->mIndices = face.mIndices;
+					pf->mNumIndices = face.mNumIndices;
+					const_cast<unsigned int*>(face.mIndices) = NULL; // make sure it won't be deleted
+					pf++;
+				}
+				++p;
+			}
 		}
 
-		aiVector3D* pv = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
-		aiFace* pf = mesh->mFaces = new aiFace[mesh->mNumFaces];
-		mesh->mMaterialIndex = p;
+		// generate nodes to render the mesh. Store the parent index
+		// in the mParent member of the nodes
+		aiNode* pcNode = new aiNode();
+		apcNodes.push_back(pcNode);
+		pcNode->mName.Set(layer.mName);
+		pcNode->mParent = reinterpret_cast<aiNode*>(layer.mParent);
+		pcNode->mNumMeshes = apcMeshes.size() - meshStart;
+		pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
+		for (unsigned int p = 0; p < pcNode->mNumMeshes;++p)
+			pcNode->mMeshes[p] = p + meshStart;
+	}
+	// generate the final node graph
+	GenerateNodeGraph(apcNodes);
 
-		// now convert all faces
-		unsigned int vert = 0;
-		for (SortedRep::const_iterator it = sorted.begin(), end = sorted.end();
-			it != end;++it)
-		{
-			LWO::Face& face = _mFaces[*it];
+	// copy the meshes to the output structure
+	if (apcMeshes.size()) // shouldn't occur, just to be sure we don't crash
+	{
+		pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes = apcMeshes.size() ];
+		::memcpy(pScene->mMeshes,&apcMeshes[0],pScene->mNumMeshes*sizeof(void*));
+	}
+}
 
-			// copy all vertices
-			for (unsigned int q = 0; q  < face.mNumIndices;++q)
+// ------------------------------------------------------------------------------------------------
+void LWOImporter::GenerateNodeGraph(std::vector<aiNode*>& apcNodes)
+{
+	// now generate the final nodegraph
+	uint16_t curIndex = 0;
+	while (curIndex < (uint16_t)apcNodes.size())
+	{
+		aiNode* node;
+		uint16_t iCurParent = curIndex-1;
+		node = curIndex ? apcNodes[iCurParent] : new aiNode("<dummy_root>");
+
+		unsigned int numChilds = 0;
+		for (unsigned int i = 0; i < apcNodes.size();++i)
+		{
+			if (i == iCurParent)continue;
+			if ( reinterpret_cast<uint16_t>(apcNodes[i]->mParent) == iCurParent)++numChilds;
+		}
+		if (numChilds)
+		{
+			if (!pScene->mRootNode)
 			{
-				*pv++ = _mTempPoints[face.mIndices[q]];
-				face.mIndices[q] = vert++;
+				pScene->mRootNode = node;
+			}
+			node->mChildren = new aiNode* [ node->mNumChildren = numChilds ];
+			for (unsigned int i = 0, p = 0; i < apcNodes.size();++i)
+			{
+				if (i == iCurParent)continue;
+				uint16_t parent = reinterpret_cast<uint16_t>(apcNodes[i]->mParent);
+				if (parent == iCurParent)
+				{
+					node->mChildren[p++] = apcNodes[i];
+					apcNodes[i]->mParent = node;
+					apcNodes[i] = NULL;
+				}
 			}
-
-			pf->mIndices = face.mIndices;
-			pf->mNumIndices = face.mNumIndices;
-			face.mIndices = NULL; // make sure it won't be deleted
-			pf++;
 		}
-
-		// generate the corresponding material
-		MaterialHelper* pcMat = new MaterialHelper();
-		pScene->mMaterials[p] = pcMat;
-		ConvertMaterial((*mSurfaces)[i],pcMat);
-		++p;
+		else if (!curIndex)delete node;
+		++curIndex;
+	}
+	// remove a single root node
+	// TODO: implement directly in the above loop, no need to deallocate here
+	if (1 == pScene->mRootNode->mNumChildren)
+	{
+		aiNode* pc = pScene->mRootNode->mChildren[0];
+		pc->mParent = pScene->mRootNode->mChildren[0] = NULL;
+		delete pScene->mRootNode;
+		pScene->mRootNode = pc;
 	}
 
-	// create a dummy nodegraph - the root node renders everything
-	aiNode* p = pScene->mRootNode = new aiNode();
-	p->mNumMeshes = pScene->mNumMeshes;
-	p->mMeshes = new unsigned int[pScene->mNumMeshes];
-	p->mName.Set("<LWORoot>");
-	for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
-		p->mMeshes[i] = i;
+	// add unreferenced nodes to a dummy root
+	unsigned int m = 0;
+	for (std::vector<aiNode*>::iterator it = apcNodes.begin(), end = apcNodes.end();
+		it != end;++it)
+	{
+		aiNode* p = *it;
+		if (p)++m;
+	}
+	if (m)
+	{
+		aiNode* pc = new aiNode();
+		pc->mName.Set("<dummy_root>");
+		aiNode** cc = pc->mChildren = new aiNode*[ pc->mNumChildren = m+1 ];
+		for (std::vector<aiNode*>::iterator it = apcNodes.begin(), end = apcNodes.end();
+			it != end;++it)
+		{
+			aiNode* p = *it;
+			if (p)*cc++ = p;
+		}
+		if (pScene->mRootNode)
+		{
+			*cc = pScene->mRootNode;
+			pScene->mRootNode->mParent = pc;
+		}
+		else --pc->mNumChildren;
+		pScene->mRootNode = pc;
+	}
+	if (!pScene->mRootNode)throw new ImportErrorException("LWO: Unable to build a valid node graph");
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -282,7 +396,7 @@ void LWOImporter::CountVertsAndFaces(unsigned int& verts, unsigned int& faces,
 }
 
 // ------------------------------------------------------------------------------------------------
-void LWOImporter::CopyFaceIndices(LWOImporter::FaceList::iterator& it,
+void LWOImporter::CopyFaceIndices(FaceList::iterator& it,
 	LE_NCONST uint16_t*& cursor, 
 	const uint16_t* const end,
 	unsigned int max)
@@ -296,11 +410,11 @@ void LWOImporter::CopyFaceIndices(LWOImporter::FaceList::iterator& it,
 			face.mIndices = new unsigned int[face.mNumIndices];
 			for (unsigned int i = 0; i < face.mNumIndices;++i)
 			{
-				face.mIndices[i] = *cursor++;
-				if (face.mIndices[i] >= mTempPoints->size())
+				unsigned int & mi = face.mIndices[i] = *cursor++;
+				if (mi > mCurLayer->mTempPoints.size())
 				{
-					face.mIndices[i] = mTempPoints->size()-1;
-					DefaultLogger::get()->warn("LWO: Face index is out of range");
+					DefaultLogger::get()->warn("LWO: face index is out of range");
+					mi = mCurLayer->mTempPoints.size()-1;
 				}
 			}
 		}
@@ -384,14 +498,53 @@ void LWOImporter::LoadLWOTags(unsigned int size)
 	}
 }
 
+// ------------------------------------------------------------------------------------------------
+void LWOImporter::LoadLWOPoints(unsigned int length)
+{
+	mCurLayer->mTempPoints.resize( length / 12 );
+
+	// perform endianess conversions
+#ifndef AI_BUILD_BIG_ENDIAN
+	for (unsigned int i = 0; i < length>>2;++i)
+		ByteSwap::Swap4( mFileBuffer + (i << 2));
+#endif
+	::memcpy(&mCurLayer->mTempPoints[0],mFileBuffer,length);
+}
+
+// ------------------------------------------------------------------------------------------------
+void LWOImporter::LoadLWOPolygons(unsigned int length)
+{
+	// first find out how many faces and vertices we'll finally need
+	LE_NCONST uint16_t* const end	= (LE_NCONST uint16_t*)(mFileBuffer+length);
+	LE_NCONST uint16_t* cursor		= (LE_NCONST uint16_t*)mFileBuffer;
+
+	// perform endianess conversions
+#ifndef AI_BUILD_BIG_ENDIAN
+	while (cursor < end)ByteSwap::Swap2(cursor++);
+	cursor = (LE_NCONST uint16_t*)mFileBuffer;
+#endif
+
+	unsigned int iNumFaces = 0,iNumVertices = 0;
+	CountVertsAndFaces(iNumVertices,iNumFaces,cursor,end);
+
+	// allocate the output array and copy face indices
+	if (iNumFaces)
+	{
+		cursor = (LE_NCONST uint16_t*)mFileBuffer;
+		// this->mTempPoints->resize(iNumVertices);
+		mCurLayer->mFaces.resize(iNumFaces);
+		FaceList::iterator it = mCurLayer->mFaces.begin();
+		CopyFaceIndices(it,cursor,end);
+	}
+}
+
 // ------------------------------------------------------------------------------------------------
 void LWOImporter::LoadLWOBFile()
 {
 	LE_NCONST uint8_t* const end = mFileBuffer + fileSize;
 	while (true)
 	{
-		if (mFileBuffer + sizeof(IFF::ChunkHeader) > end)
-			break;
+		if (mFileBuffer + sizeof(IFF::ChunkHeader) > end)break;
 		LE_NCONST IFF::ChunkHeader* const head = (LE_NCONST IFF::ChunkHeader*)mFileBuffer;
 		AI_LSWAP4(head->length);
 		AI_LSWAP4(head->type);
@@ -408,58 +561,123 @@ void LWOImporter::LoadLWOBFile()
 			// vertex list
 		case AI_LWO_PNTS:
 			{
-				mTempPoints->resize( head->length / 12 );
-#ifndef AI_BUILD_BIG_ENDIAN
-				for (unsigned int i = 0; i < head->length>>2;++i)
-					ByteSwap::Swap4( mFileBuffer + (i << 2));
-#endif
-				::memcpy(&(*mTempPoints)[0],mFileBuffer,head->length);
+				if (!mCurLayer->mTempPoints.empty())
+					DefaultLogger::get()->warn("LWO: PNTS chunk encountered twice");
+				else LoadLWOPoints(head->length);
 				break;
 			}
 			// face list
 		case AI_LWO_POLS:
 			{
-				// first find out how many faces and vertices we'll finally need
-				LE_NCONST uint16_t* const end	= (LE_NCONST uint16_t*)next;
-				LE_NCONST uint16_t* cursor		= (LE_NCONST uint16_t*)mFileBuffer;
+				if (!mCurLayer->mFaces.empty())
+					DefaultLogger::get()->warn("LWO: POLS chunk encountered twice");
+				else LoadLWOPolygons(head->length);
+				break;
+			}
+			// list of tags
+		case AI_LWO_SRFS:
+			{
+				if (!mTags->empty())
+					DefaultLogger::get()->warn("LWO: SRFS chunk encountered twice");
+				else LoadLWOTags(head->length);
+				break;
+			}
 
-#ifndef AI_BUILD_BIG_ENDIAN
-				while (cursor < end)ByteSwap::Swap2(cursor++);
-				cursor = (LE_NCONST uint16_t*)mFileBuffer;
-#endif
+			// surface chunk
+		case AI_LWO_SURF:
+			{
+				if (!mSurfaces->empty())
+					DefaultLogger::get()->warn("LWO: SURF chunk encountered twice");
+				else LoadLWOBSurface(head->length);
+				break;
+			}
+		}
+		mFileBuffer = next;
+	}
+}
+// ------------------------------------------------------------------------------------------------
+void LWOImporter::LoadLWO2File()
+{
+	LE_NCONST uint8_t* const end = mFileBuffer + fileSize;
+	while (true)
+	{
+		if (mFileBuffer + sizeof(IFF::ChunkHeader) > end)break;
+		LE_NCONST IFF::ChunkHeader* const head = (LE_NCONST IFF::ChunkHeader*)mFileBuffer;
+		AI_LSWAP4(head->length);
+		AI_LSWAP4(head->type);
+		mFileBuffer += sizeof(IFF::ChunkHeader);
+		if (mFileBuffer + head->length > end)
+		{
+			throw new ImportErrorException("LWOB: Invalid file, the size attribute of "
+				"a chunk points behind the end of the file");
+			break;
+		}
+		LE_NCONST uint8_t* const next = mFileBuffer+head->length;
+		unsigned int iUnnamed = 0;
+		switch (head->type)
+		{
+			// new layer
+		case AI_LWO_LAYR:
+			{
+				// add a new layer to the list ....
+				mLayers->push_back ( LWO::Layer() );
+				LWO::Layer& layer = mLayers->back();
+				mCurLayer = &layer;
 
-				unsigned int iNumFaces = 0,iNumVertices = 0;
-				CountVertsAndFaces(iNumVertices,iNumFaces,cursor,end);
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,LAYR,16);
 
-				// allocate the output array and copy face indices
-				if (iNumFaces)
+				// and parse its properties
+				mFileBuffer += 16;
+				ParseString(layer.mName,head->length-16);
+
+				// if the name is empty, generate a default name
+				if (layer.mName.empty())
 				{
-					cursor = (LE_NCONST uint16_t*)mFileBuffer;
-					this->mTempPoints->resize(iNumVertices);
-					this->mFaces->resize(iNumFaces);
-					FaceList::iterator it = this->mFaces->begin();
-					CopyFaceIndices(it,cursor,end);
+					char buffer[128]; // should be sufficiently large
+					::sprintf(buffer,"Layer_%i", iUnnamed++);
+					layer.mName = buffer;
 				}
+
+				if (mFileBuffer + 2 <= next)
+					layer.mParent = *((uint16_t*)mFileBuffer);
+
+				break;
+			}
+
+			// vertex list
+		case AI_LWO_PNTS:
+			{
+				if (!mCurLayer->mTempPoints.empty())
+					DefaultLogger::get()->warn("LWO: PNTS chunk encountered twice");
+				else LoadLWOPoints(head->length);
+				break;
+			}
+			// face list
+		case AI_LWO_POLS:
+			{
+				if (!mCurLayer->mFaces.empty())
+					DefaultLogger::get()->warn("LWO: POLS chunk encountered twice");
+				else LoadLWOPolygons(head->length);
 				break;
 			}
 			// list of tags
 		case AI_LWO_SRFS:
 			{
-				LoadLWOTags(head->length);
+				if (!mTags->empty())
+					DefaultLogger::get()->warn("LWO: SRFS chunk encountered twice");
+				else LoadLWOTags(head->length);
 				break;
 			}
 
 			// surface chunk
 		case AI_LWO_SURF:
 			{
-				LoadLWOBSurface(head->length);
+				if (!mSurfaces->empty())
+					DefaultLogger::get()->warn("LWO: SURF chunk encountered twice");
+				else LoadLWOBSurface(head->length);
 				break;
 			}
 		}
 		mFileBuffer = next;
 	}
-}
-// ------------------------------------------------------------------------------------------------
-void LWOImporter::LoadLWO2File()
-{
 }

+ 40 - 27
code/LWOLoader.h

@@ -48,8 +48,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "LWOFileData.h"
 #include "MaterialSystem.h"
 
-#include <vector>
 struct aiTexture;
+struct aiNode;
 
 namespace Assimp	{
 using namespace LWO;
@@ -61,6 +61,7 @@ class LWOImporter : public BaseImporter
 {
 	friend class Importer;
 
+
 protected:
 	/** Constructor to be privately used by Importer */
 	LWOImporter();
@@ -101,6 +102,7 @@ protected:
 	void InternReadFile( const std::string& pFile, aiScene* pScene, 
 		IOSystem* pIOHandler);
 
+private:
 
 	// -------------------------------------------------------------------
 	/** Loads a LWO file in the older LWOB format (LW < 6)
@@ -150,33 +152,20 @@ protected:
 	void LoadLWOTags(unsigned int size);
 
 	// -------------------------------------------------------------------
-	/** Resolve the tag and surface lists that have been loaded.
-	* Generates the mMapping table.
+	/** Load polygons from a POLS chunk
+	 *  @param length Size of the chunk
 	*/
-	void ResolveTags();
+	void LoadLWOPolygons(unsigned int length);
 
 	// -------------------------------------------------------------------
-	/** Computes a proper texture form a procedural gradient
-	 *  description.
-	 *  @param grad Gradient description
-     *  @param out List of output textures. The new texture should
-	 *    be added to the list, if the conversion was successful.
-	 *  @return true if successful
+	/** Load polygons from a PNTS chunk
+	 *  @param length Size of the chunk
 	*/
-	bool ComputeGradientTexture(LWO::GradientInfo& grad,
-		std::vector<aiTexture*>& out);
-
+	void LoadLWOPoints(unsigned int length);
 
-	typedef std::vector<aiVector3D>		PointList;
-	typedef std::vector<LWO::Face>		FaceList;
-	typedef std::vector<LWO::Surface>	SurfaceList;
-	typedef std::vector<std::string>	TagList;
-	typedef std::vector<unsigned int>	TagMappingTable;
-
-private:
 
 	// -------------------------------------------------------------------
-	/** Count vertices and faces in a LWOB file
+	/** Count vertices and faces in a LWOB/LWO2 file
 	*/
 	void CountVertsAndFaces(unsigned int& verts, 
 		unsigned int& faces,
@@ -185,13 +174,30 @@ private:
 		unsigned int max = 0xffffffff);
 
 	// -------------------------------------------------------------------
-	/** Read vertices and faces in a LWOB file
+	/** Read vertices and faces in a LWOB/LWO2 file
 	*/
-	void CopyFaceIndices(FaceList::iterator& it,
+	void CopyFaceIndices(LWO::FaceList::iterator& it,
 		LE_NCONST uint16_t*& cursor, 
 		const uint16_t* const end, 
 		unsigned int max = 0xffffffff);
 
+	// -------------------------------------------------------------------
+	/** Resolve the tag and surface lists that have been loaded.
+	* Generates the mMapping table.
+	*/
+	void ResolveTags();
+
+	// -------------------------------------------------------------------
+	/** Computes a proper texture form a procedural gradient
+	 *  description.
+	 *  @param grad Gradient description
+     *  @param out List of output textures. The new texture should
+	 *    be added to the list, if the conversion was successful.
+	 *  @return true if successful
+	*/
+	bool ComputeGradientTexture(LWO::GradientInfo& grad,
+		std::vector<aiTexture*>& out);
+
 	// -------------------------------------------------------------------
 	/** Parse a string from the current file position
 	*/
@@ -207,16 +213,23 @@ private:
 	*/
 	void ConvertMaterial(const LWO::Surface& surf,MaterialHelper* pcMat);
 
+	// -------------------------------------------------------------------
+	/** Generate the final node graph
+	 *  Unused nodes are deleted.
+	 *  @param apcNodes Flat list of nodes
+	*/
+	void GenerateNodeGraph(std::vector<aiNode*>& apcNodes);
+
 protected:
 
 	/** true if the file is a LWO2 file*/
 	bool mIsLWO2;
 
-	/** Temporary point list from the file */
-	PointList* mTempPoints;
+	/** Temporary list of layers from the file */
+	LayerList* mLayers;
 
-	/** Temporary face list from the file*/
-	FaceList* mFaces;
+	/** Pointer to the current layer */
+	LWO::Layer* mCurLayer;
 
 	/** Temporary tag list from the file */
 	TagList* mTags;

+ 0 - 2
code/STLLoader.cpp

@@ -166,8 +166,6 @@ void STLImporter::InternReadFile(
 	pScene->mNumMaterials = 1;
 	pScene->mMaterials = new aiMaterial*[1];
 	pScene->mMaterials[0] = pcMat;
-
-	delete[] this->mBuffer;AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
 }
 // ------------------------------------------------------------------------------------------------
 // Read an ASCII STL file

+ 10 - 0
include/aiScene.h

@@ -100,6 +100,16 @@ struct aiNode
 		mNumMeshes = 0; mMeshes = NULL;
 	}
 
+	/** Construction from a specific name */
+	aiNode(const std::string& name) 
+	{ 
+		// set all members to zero by default
+		mParent = NULL; 
+		mNumChildren = 0; mChildren = NULL;
+		mNumMeshes = 0; mMeshes = NULL;
+		mName = name;
+	}
+
 	/** Destructor */
 	~aiNode()
 	{

+ 340 - 332
workspaces/vc8/assimp.vcproj

@@ -818,74 +818,6 @@
 				RelativePath="..\..\code\VertexTriangleAdjacency.h"
 				>
 			</File>
-			<Filter
-				Name="Obj"
-				>
-				<File
-					RelativePath="..\..\code\ObjFileData.h"
-					>
-				</File>
-				<File
-					RelativePath="..\..\code\ObjFileImporter.h"
-					>
-				</File>
-				<File
-					RelativePath="..\..\code\ObjFileMtlImporter.h"
-					>
-				</File>
-				<File
-					RelativePath="..\..\code\ObjFileParser.h"
-					>
-				</File>
-				<File
-					RelativePath="..\..\code\ObjTools.h"
-					>
-				</File>
-			</Filter>
-			<Filter
-				Name="3DS"
-				>
-				<File
-					RelativePath="..\..\code\3DSHelper.h"
-					>
-				</File>
-				<File
-					RelativePath="..\..\code\3DSLoader.h"
-					>
-				</File>
-				<File
-					RelativePath="..\..\code\3DSSpatialSort.h"
-					>
-				</File>
-			</Filter>
-			<Filter
-				Name="MD3"
-				>
-				<File
-					RelativePath="..\..\code\MD3FileData.h"
-					>
-				</File>
-				<File
-					RelativePath="..\..\code\MD3Loader.h"
-					>
-				</File>
-			</Filter>
-			<Filter
-				Name="MD2"
-				>
-				<File
-					RelativePath="..\..\code\MD2FileData.h"
-					>
-				</File>
-				<File
-					RelativePath="..\..\code\MD2Loader.h"
-					>
-				</File>
-				<File
-					RelativePath="..\..\code\MD2NormalTable.h"
-					>
-				</File>
-			</Filter>
 			<Filter
 				Name="Compiler"
 				>
@@ -898,78 +830,6 @@
 					>
 				</File>
 			</Filter>
-			<Filter
-				Name="X"
-				>
-				<File
-					RelativePath="..\..\code\XFileHelper.h"
-					>
-				</File>
-				<File
-					RelativePath="..\..\code\XFileImporter.h"
-					>
-				</File>
-				<File
-					RelativePath="..\..\code\XFileParser.h"
-					>
-				</File>
-			</Filter>
-			<Filter
-				Name="Ply"
-				>
-				<File
-					RelativePath="..\..\code\PlyLoader.h"
-					>
-				</File>
-				<File
-					RelativePath="..\..\code\PlyParser.h"
-					>
-				</File>
-			</Filter>
-			<Filter
-				Name="MD5"
-				>
-				<File
-					RelativePath="..\..\code\MD5Loader.h"
-					>
-				</File>
-				<File
-					RelativePath="..\..\code\MD5Parser.h"
-					>
-				</File>
-			</Filter>
-			<Filter
-				Name="MDL"
-				>
-				<File
-					RelativePath="..\..\code\HalfLifeFileData.h"
-					>
-				</File>
-				<File
-					RelativePath="..\..\code\MDLDefaultColorMap.h"
-					>
-				</File>
-				<File
-					RelativePath="..\..\code\MDLFileData.h"
-					>
-				</File>
-				<File
-					RelativePath="..\..\code\MDLLoader.h"
-					>
-				</File>
-			</Filter>
-			<Filter
-				Name="ASE"
-				>
-				<File
-					RelativePath="..\..\code\ASELoader.h"
-					>
-				</File>
-				<File
-					RelativePath="..\..\code\ASEParser.h"
-					>
-				</File>
-			</Filter>
 			<Filter
 				Name="Logger"
 				>
@@ -995,68 +855,212 @@
 				</File>
 			</Filter>
 			<Filter
-				Name="HMPLoader"
+				Name="Loaders"
 				>
-				<File
-					RelativePath="..\..\code\HMPFileData.h"
+				<Filter
+					Name="3DS"
 					>
-				</File>
-				<File
-					RelativePath="..\..\code\HMPLoader.h"
+					<File
+						RelativePath="..\..\code\3DSHelper.h"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\3DSLoader.h"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\3DSSpatialSort.h"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="ASE"
 					>
-				</File>
-			</Filter>
-			<Filter
-				Name="SMD"
-				>
-				<File
-					RelativePath="..\..\code\SMDLoader.h"
+					<File
+						RelativePath="..\..\code\ASELoader.h"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\ASEParser.h"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="HMPLoader"
 					>
-				</File>
-			</Filter>
-			<Filter
-				Name="STL"
-				>
-				<File
-					RelativePath="..\..\code\STLLoader.h"
+					<File
+						RelativePath="..\..\code\HMPFileData.h"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\HMPLoader.h"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="LWO"
 					>
-				</File>
-			</Filter>
-			<Filter
-				Name="LWO"
-				>
-				<File
-					RelativePath="..\..\code\LWOFileData.h"
+					<File
+						RelativePath="..\..\code\LWOFileData.h"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\LWOLoader.h"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="MD2"
 					>
-				</File>
-				<File
-					RelativePath="..\..\code\LWOLoader.h"
+					<File
+						RelativePath="..\..\code\MD2FileData.h"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\MD2Loader.h"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\MD2NormalTable.h"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="MD3"
 					>
-				</File>
-			</Filter>
-			<Filter
-				Name="MDC"
-				>
-				<File
-					RelativePath="..\..\code\MDCFileData.h"
+					<File
+						RelativePath="..\..\code\MD3FileData.h"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\MD3Loader.h"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="MD5"
 					>
-				</File>
-				<File
-					RelativePath="..\..\code\MDCLoader.h"
+					<File
+						RelativePath="..\..\code\MD5Loader.h"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\MD5Parser.h"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="MDC"
 					>
-				</File>
-				<File
-					RelativePath="..\..\code\MDCNormalTable.h"
+					<File
+						RelativePath="..\..\code\MDCFileData.h"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\MDCLoader.h"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\MDCNormalTable.h"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="MDL"
 					>
-				</File>
-			</Filter>
-			<Filter
-				Name="MDR"
-				>
-				<File
-					RelativePath="..\..\code\MDRFileData.h"
+					<File
+						RelativePath="..\..\code\HalfLifeFileData.h"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\MDLDefaultColorMap.h"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\MDLFileData.h"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\MDLLoader.h"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="MDR"
 					>
-				</File>
+					<File
+						RelativePath="..\..\code\MDRFileData.h"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="Obj"
+					>
+					<File
+						RelativePath="..\..\code\ObjFileData.h"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\ObjFileImporter.h"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\ObjFileMtlImporter.h"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\ObjFileParser.h"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\ObjTools.h"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="Ply"
+					>
+					<File
+						RelativePath="..\..\code\PlyLoader.h"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\PlyParser.h"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="SMD"
+					>
+					<File
+						RelativePath="..\..\code\SMDLoader.h"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="STL"
+					>
+					<File
+						RelativePath="..\..\code\STLLoader.h"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="X"
+					>
+					<File
+						RelativePath="..\..\code\XFileHelper.h"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\XFileImporter.h"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\XFileParser.h"
+						>
+					</File>
+				</Filter>
 			</Filter>
 		</Filter>
 		<Filter
@@ -1170,173 +1174,177 @@
 				RelativePath="..\..\code\VertexTriangleAdjacency.cpp"
 				>
 			</File>
-			<Filter
-				Name="Obj"
-				>
-				<File
-					RelativePath="..\..\code\ObjFileImporter.cpp"
-					>
-				</File>
-				<File
-					RelativePath="..\..\code\ObjFileMtlImporter.cpp"
-					>
-				</File>
-				<File
-					RelativePath="..\..\code\ObjFileParser.cpp"
-					>
-				</File>
-			</Filter>
-			<Filter
-				Name="3DS"
-				>
-				<File
-					RelativePath="..\..\code\3DSConverter.cpp"
-					>
-				</File>
-				<File
-					RelativePath="..\..\code\3DSGenNormals.cpp"
-					>
-				</File>
-				<File
-					RelativePath="..\..\code\3DSLoader.cpp"
-					>
-				</File>
-				<File
-					RelativePath="..\..\code\3DSSpatialSort.cpp"
-					>
-				</File>
-			</Filter>
-			<Filter
-				Name="MD3"
-				>
-				<File
-					RelativePath="..\..\code\MD3Loader.cpp"
-					>
-				</File>
-			</Filter>
-			<Filter
-				Name="MD2"
-				>
-				<File
-					RelativePath="..\..\code\MD2Loader.cpp"
-					>
-				</File>
-			</Filter>
 			<Filter
 				Name="Compiler"
 				>
 			</Filter>
 			<Filter
-				Name="X"
+				Name="extra"
 				>
 				<File
-					RelativePath="..\..\code\XFileImporter.cpp"
-					>
-				</File>
-				<File
-					RelativePath="..\..\code\XFileParser.cpp"
+					RelativePath="..\..\code\extra\MakeVerboseFormat.cpp"
 					>
 				</File>
 			</Filter>
 			<Filter
-				Name="Ply"
+				Name="Loaders"
 				>
-				<File
-					RelativePath="..\..\code\PlyLoader.cpp"
-					>
-				</File>
-				<File
-					RelativePath="..\..\code\PlyParser.cpp"
+				<Filter
+					Name="3DS"
 					>
-				</File>
-			</Filter>
-			<Filter
-				Name="MDL"
-				>
-				<File
-					RelativePath="..\..\code\MDLLoader.cpp"
+					<File
+						RelativePath="..\..\code\3DSConverter.cpp"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\3DSGenNormals.cpp"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\3DSLoader.cpp"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\3DSSpatialSort.cpp"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="ASE"
 					>
-				</File>
-				<File
-					RelativePath="..\..\code\MDLMaterialLoader.cpp"
+					<File
+						RelativePath="..\..\code\ASELoader.cpp"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\ASEParser.cpp"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="HMP"
 					>
-				</File>
-			</Filter>
-			<Filter
-				Name="ASE"
-				>
-				<File
-					RelativePath="..\..\code\ASELoader.cpp"
+					<File
+						RelativePath="..\..\code\HMPLoader.cpp"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="LWO"
 					>
-				</File>
-				<File
-					RelativePath="..\..\code\ASEParser.cpp"
+					<File
+						RelativePath="..\..\code\LWOLoader.cpp"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\LWOMaterial.cpp"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="MD2"
 					>
-				</File>
-			</Filter>
-			<Filter
-				Name="extra"
-				>
-				<File
-					RelativePath="..\..\code\extra\MakeVerboseFormat.cpp"
+					<File
+						RelativePath="..\..\code\MD2Loader.cpp"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="MD3"
 					>
-				</File>
-			</Filter>
-			<Filter
-				Name="HMP"
-				>
-				<File
-					RelativePath="..\..\code\HMPLoader.cpp"
+					<File
+						RelativePath="..\..\code\MD3Loader.cpp"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="MD5"
 					>
-				</File>
-			</Filter>
-			<Filter
-				Name="SMD"
-				>
-				<File
-					RelativePath="..\..\code\SMDLoader.cpp"
+					<File
+						RelativePath="..\..\code\MD5Loader.cpp"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\MD5Parser.cpp"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="MDC"
 					>
-				</File>
-			</Filter>
-			<Filter
-				Name="MD5"
-				>
-				<File
-					RelativePath="..\..\code\MD5Loader.cpp"
+					<File
+						RelativePath="..\..\code\MDCLoader.cpp"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="MDL"
 					>
-				</File>
-				<File
-					RelativePath="..\..\code\MD5Parser.cpp"
+					<File
+						RelativePath="..\..\code\MDLLoader.cpp"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\MDLMaterialLoader.cpp"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="Obj"
 					>
-				</File>
-			</Filter>
-			<Filter
-				Name="STL"
-				>
-				<File
-					RelativePath="..\..\code\STLLoader.cpp"
+					<File
+						RelativePath="..\..\code\ObjFileImporter.cpp"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\ObjFileMtlImporter.cpp"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\ObjFileParser.cpp"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="Ply"
 					>
-				</File>
-			</Filter>
-			<Filter
-				Name="LWO"
-				>
-				<File
-					RelativePath="..\..\code\LWOLoader.cpp"
+					<File
+						RelativePath="..\..\code\PlyLoader.cpp"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\PlyParser.cpp"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="SMD"
 					>
-				</File>
-				<File
-					RelativePath="..\..\code\LWOMaterial.cpp"
+					<File
+						RelativePath="..\..\code\SMDLoader.cpp"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="STL"
 					>
-				</File>
-			</Filter>
-			<Filter
-				Name="MDC"
-				>
-				<File
-					RelativePath="..\..\code\MDCLoader.cpp"
+					<File
+						RelativePath="..\..\code\STLLoader.cpp"
+						>
+					</File>
+				</Filter>
+				<Filter
+					Name="X"
 					>
-				</File>
+					<File
+						RelativePath="..\..\code\XFileImporter.cpp"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\XFileParser.cpp"
+						>
+					</File>
+				</Filter>
 			</Filter>
 		</Filter>
 		<Filter