Переглянути джерело

merge https://github.com/gellule/assimp.git

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@1096 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
aramis_acg 13 роки тому
батько
коміт
5957e9996b
5 змінених файлів з 150 додано та 132 видалено
  1. 11 7
      code/LWOAnimation.cpp
  2. 70 73
      code/LWOLoader.cpp
  3. 1 1
      code/LWOLoader.h
  4. 66 51
      code/LWSLoader.cpp
  5. 2 0
      code/LWSLoader.h

+ 11 - 7
code/LWOAnimation.cpp

@@ -243,14 +243,13 @@ void AnimResolver::ExtractBindPose(aiMatrix4x4& out)
 	if (scale_z) scaling.z = scale_z->keys[0].value;
 
 	// build the final matrix
-	aiMatrix4x4 s,r,t;
-	
-	r.FromEulerAnglesXYZ(angles);
-	//aiMatrix4x4::RotationY(angles.y,r);
-	// fixme: make FromEulerAngles static, too
+	aiMatrix4x4 s,rx,ry,rz,t;
+	aiMatrix4x4::RotationZ(angles.z, rz);
+	aiMatrix4x4::RotationX(angles.y, rx);
+	aiMatrix4x4::RotationY(angles.x, ry);
 	aiMatrix4x4::Translation(translation,t);
 	aiMatrix4x4::Scaling(scaling,s);
-	out = s*r*t;
+	out = t*ry*rx*rz*s;
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -567,10 +566,15 @@ void AnimResolver::ExtractAnimChannel(aiNodeAnim** out, unsigned int flags /*= 0
 		anim->mRotationKeys = new aiQuatKey[ anim->mNumRotationKeys = keys.size() ];
 		
 		// convert heading, pitch, bank to quaternion
+		// mValue.x=Heading=Rot(Y), mValue.y=Pitch=Rot(X), mValue.z=Bank=Rot(Z)
+		// Lightwave's rotation order is ZXY
+		aiVector3D X(1.0,0.0,0.0);
+		aiVector3D Y(0.0,1.0,0.0);
+		aiVector3D Z(0.0,0.0,1.0);
 		for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) {
 			aiQuatKey& qk = anim->mRotationKeys[i];
 			qk.mTime  = keys[i].mTime;
-			qk.mValue = aiQuaternion( -keys[i].mValue.x ,-keys[i].mValue.z ,-keys[i].mValue.y );
+			qk.mValue = aiQuaternion(Y,keys[i].mValue.x)*aiQuaternion(X,keys[i].mValue.y)*aiQuaternion(Z,keys[i].mValue.z);
 		}
 	}
 

+ 70 - 73
code/LWOLoader.cpp

@@ -142,6 +142,7 @@ void LWOImporter::InternReadFile( const std::string& pFile,
 	mLayers->push_back(Layer());
 	mCurLayer = &mLayers->back();
 	mCurLayer->mName = "<LWODefault>";
+	mCurLayer->mIndex = -1;
 
 	// old lightwave file format (prior to v6)
 	if (AI_LWO_FOURCC_LWOB == fileType)	{
@@ -180,8 +181,14 @@ void LWOImporter::InternReadFile( const std::string& pFile,
 		// The newer lightwave format allows the user to configure the
 		// loader that just one layer is used. If this is the case
 		// we need to check now whether the requested layer has been found.
-		if (UINT_MAX != configLayerIndex && configLayerIndex > mLayers->size())
-			throw DeadlyImportError("LWO2: The requested layer was not found");
+		if (UINT_MAX != configLayerIndex) {
+			unsigned int layerCount = 0;
+			for(std::list<LWO::Layer>::iterator itLayers=mLayers->begin(); itLayers!=mLayers->end(); itLayers++)
+				if (!itLayers->skip)
+					layerCount++;
+			if (layerCount!=2)
+				throw DeadlyImportError("LWO2: The requested layer was not found");
+		}
 
 		if (configLayerName.length() && !hasNamedLayer)	{
 			throw DeadlyImportError("LWO2: Unable to find the requested layer: " 
@@ -195,8 +202,8 @@ void LWOImporter::InternReadFile( const std::string& pFile,
 
 	// now process all layers and build meshes and nodes
 	std::vector<aiMesh*> apcMeshes;
-	std::vector<aiNode*> apcNodes;
-	apcNodes. reserve(mLayers->size());
+	std::map<uint16_t, aiNode*> apcNodes;
+
 	apcMeshes.reserve(mLayers->size()*std::min(((unsigned int)mSurfaces->size()/2u), 1u));
 
 	unsigned int iDefaultSurface = UINT_MAX; // index of the default surface
@@ -384,7 +391,7 @@ void LWOImporter::InternReadFile( const std::string& pFile,
 		unsigned int num = apcMeshes.size() - meshStart;
 		if (layer.mName != "<LWODefault>" || num > 0) {
 			aiNode* pcNode = new aiNode();
-			apcNodes.push_back(pcNode);
+			apcNodes[layer.mIndex] = pcNode;
 			pcNode->mName.Set(layer.mName);
 			pcNode->mParent = (aiNode*)&layer;
 			pcNode->mNumMeshes = num;
@@ -523,78 +530,69 @@ void LWOImporter::ComputeNormals(aiMesh* mesh, const std::vector<unsigned int>&
 }
 
 // ------------------------------------------------------------------------------------------------
-void LWOImporter::AddChildren(aiNode* node, uint16_t parent, std::vector<aiNode*>& apcNodes)
+void LWOImporter::GenerateNodeGraph(std::map<uint16_t,aiNode*>& apcNodes)
 {
-	for (std::vector<aiNode*>::iterator it = apcNodes.begin(); it != apcNodes.end(); ++it)	{
-		if (*it) {
-			LWO::Layer* layer = (LWO::Layer*)(*it)->mParent;
-			if (layer->mParent == parent && layer->mIndex != parent)
-				++node->mNumChildren;
-		}
-	}
+	// now generate the final nodegraph - generate a root node and attach children
+	aiNode* root = pScene->mRootNode = new aiNode();
+	root->mName.Set("<LWORoot>");
 
-	if (node->mNumChildren)	{
-		unsigned int p = 0;
-
-		node->mChildren = new aiNode* [ node->mNumChildren ];
-		for (std::vector<aiNode*>::iterator it = apcNodes.begin(); it != apcNodes.end(); ++it)	{
-			if (*it) {
-				LWO::Layer* layer = (LWO::Layer*)(*it)->mParent;
-				if (layer->mParent == parent && layer->mIndex != parent)	{
-					aiNode* nd = node->mChildren[p++] = *it;
-					nd->mParent = node;
-
-					// fixme: ignore pivot points for the moment
-					//nd->mTransformation.a4 = layer->mPivot.x;
-					//nd->mTransformation.b4 = layer->mPivot.y;
-					//nd->mTransformation.c4 = layer->mPivot.z;
-
-					// recursively add more children
-					(*it) = NULL;
-					AddChildren(nd,layer->mIndex,apcNodes);
-				}
-			}
+	//Set parent of all children, inserting pivots
+	std::cout << "Set parent of all children" << std::endl;
+	std::map<uint16_t, aiNode*> mapPivot;
+	for (std::map<uint16_t,aiNode*>::iterator itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) {
+
+		//Get the parent index
+		LWO::Layer* nodeLayer = (LWO::Layer*)(itapcNodes->second->mParent);
+		uint16_t parentIndex = nodeLayer->mParent;
+
+		//Create pivot node, store it into the pivot map, and set the parent as the pivot
+		aiNode* pivotNode = new aiNode();
+		pivotNode->mName.Set("Pivot-"+std::string(itapcNodes->second->mName.data));
+		mapPivot[-(itapcNodes->first+2)] = pivotNode;
+		itapcNodes->second->mParent = pivotNode;
+
+		//Look for the parent node to attach the pivot to
+		if (apcNodes.find(parentIndex) != apcNodes.end()) {
+			pivotNode->mParent = apcNodes[parentIndex];
+		} else {
+			//If not, attach to the root node
+			pivotNode->mParent = root;
 		}
+
+		//Set the node and the pivot node transformation
+		itapcNodes->second->mTransformation.a4 = -nodeLayer->mPivot.x;
+		itapcNodes->second->mTransformation.b4 = -nodeLayer->mPivot.y;
+		itapcNodes->second->mTransformation.c4 = -nodeLayer->mPivot.z;
+		pivotNode->mTransformation.a4 = nodeLayer->mPivot.x;
+		pivotNode->mTransformation.b4 = nodeLayer->mPivot.y;
+		pivotNode->mTransformation.c4 = nodeLayer->mPivot.z;
 	}
-}
 
-// ------------------------------------------------------------------------------------------------
-void LWOImporter::GenerateNodeGraph(std::vector<aiNode*>& apcNodes)
-{
-	// now generate the final nodegraph - generate a root node and attach children
-	aiNode* root = pScene->mRootNode = new aiNode();
-	root->mName.Set("<LWORoot>");
-	AddChildren(root,0,apcNodes);
-
-	// check whether we added all layers with meshes assigned to the output graph.
-	// if not, add them to the root node
-	unsigned int extra = 0;
-	for (std::vector<aiNode*>::iterator it = apcNodes.begin(); it != apcNodes.end(); ++it) {
-		if ((*it) && (*it)->mNumMeshes) 
-			++extra;
+	//Merge pivot map into node map
+	std::cout << "Merge pivot map into node map" << std::endl;
+	for (std::map<uint16_t, aiNode*>::iterator itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end(); ++itMapPivot) {
+		apcNodes[itMapPivot->first] = itMapPivot->second;
 	}
 
-	if (extra)	{
-		const unsigned int newSize = extra + pScene->mRootNode->mNumChildren;
-		aiNode** const apcNewNodes = new aiNode*[newSize];
-		if((extra = root->mNumChildren))
-			::memcpy(apcNewNodes,root->mChildren,extra*sizeof(void*));
-
-		aiNode** cc = apcNewNodes+extra;
-		for (std::vector<aiNode*>::iterator it = apcNodes.begin(); it != apcNodes.end(); ++it) {
-			if ((*it) && (*it)->mNumMeshes) {
-				aiNode* nd = *cc++ = *it;
-				nd->mParent = pScene->mRootNode;
-
-				// recursively add more children
-				(*it) = NULL;
-				AddChildren(nd,((LWO::Layer*)nd->mParent)->mIndex,apcNodes);
+	//Set children of all parents
+	apcNodes[-1] = root;
+	for (std::map<uint16_t,aiNode*>::iterator itMapParentNodes = apcNodes.begin(); itMapParentNodes != apcNodes.end(); ++itMapParentNodes) {
+		for (std::map<uint16_t,aiNode*>::iterator itMapChildNodes = apcNodes.begin(); itMapChildNodes != apcNodes.end(); ++itMapChildNodes) {
+			if ((itMapParentNodes->first != itMapChildNodes->first) && (itMapParentNodes->second == itMapChildNodes->second->mParent)) {
+				++(itMapParentNodes->second->mNumChildren);
+			}
+		}
+		if (itMapParentNodes->second->mNumChildren) {
+			itMapParentNodes->second->mChildren = new aiNode* [ itMapParentNodes->second->mNumChildren ];
+			uint16_t p = 0;
+			for (std::map<uint16_t,aiNode*>::iterator itMapChildNodes = apcNodes.begin(); itMapChildNodes != apcNodes.end(); ++itMapChildNodes) {
+				if ((itMapParentNodes->first != itMapChildNodes->first) && (itMapParentNodes->second == itMapChildNodes->second->mParent)) {
+					itMapParentNodes->second->mChildren[p++] = itMapChildNodes->second;
+				}
 			}
 		}
-		delete[] root->mChildren;
-		root->mChildren = apcNewNodes;
-		root->mNumChildren = newSize;
 	}
+
 	if (!pScene->mRootNode->mNumChildren)
 		throw DeadlyImportError("LWO: Unable to build a valid node graph");
 
@@ -1285,17 +1283,15 @@ void LWOImporter::LoadLWO2File()
 
 				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,LAYR,16);
 
+				// layer index.
+				layer.mIndex = GetU2();
+
 				// Continue loading this layer or ignore it? Check the layer index property
-				// NOTE: The first layer is the default layer, so the layer index is one-based now
-				if (UINT_MAX != configLayerIndex && configLayerIndex != mLayers->size()-1)	{
+				if (UINT_MAX != configLayerIndex && (configLayerIndex-1) != layer.mIndex)	{
 					skip = true;
 				}
 				else skip = false;
 
-				// layer index. that's just for internal parenting, from the scope of a LWS file
-				// all layers are numbered in the oder in which they appear in the file
-				layer.mIndex = GetU2();
-
 				// pivot point
 				mFileBuffer += 2; /* unknown */
 				mCurLayer->mPivot.x = GetF4();
@@ -1319,6 +1315,7 @@ void LWOImporter::LoadLWO2File()
 				// optional: parent of this layer
 				if (mFileBuffer + 2 <= next)
 					layer.mParent = GetU2();
+				else layer.mParent = -1;
 
 				// Set layer skip parameter
 				layer.skip = skip;

+ 1 - 1
code/LWOLoader.h

@@ -303,7 +303,7 @@ private:
 	 *  Unused nodes are deleted.
 	 *  @param apcNodes Flat list of nodes
 	*/
-	void GenerateNodeGraph(std::vector<aiNode*>& apcNodes);
+	void GenerateNodeGraph(std::map<uint16_t,aiNode*>& apcNodes);
 
 	// -------------------------------------------------------------------
 	/** Add children to a node

+ 66 - 51
code/LWSLoader.cpp

@@ -295,8 +295,9 @@ void LWSImporter::SetupNodeName(aiNode* nd, LWS::NodeDesc& src)
 			if (s == std::string::npos)
 				s = 0;
 			else ++s;
-
-			nd->mName.length = ::sprintf(nd->mName.data,"%s_(%08X)",src.path.substr(s).c_str(),combined);
+            std::string::size_type t = src.path.substr(s).find_last_of(".");
+			
+			nd->mName.length = ::sprintf(nd->mName.data,"%s_(%08X)",src.path.substr(s).substr(0,t).c_str(),combined);
 			return;
 		}
 	}
@@ -313,18 +314,62 @@ void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vector<Attachm
 {
 	// Setup a very cryptic name for the node, we want the user to be happy
 	SetupNodeName(nd,src);
-
-	// If this is an object from an external file - get the scene and setup proper attachment tags
-	aiScene* obj = NULL;
-	if (src.type == LWS::NodeDesc::OBJECT && src.path.length() ) {
-		obj = batch.GetImport(src.id);
-		if (!obj) {
-			DefaultLogger::get()->error("LWS: Failed to read external file " + src.path);
-		}
-		else {
-			attach.push_back(AttachmentInfo(obj,nd));
-		}
-	}
+    aiNode* ndAnim = nd;
+
+	// If the node is an object
+	if (src.type == LWS::NodeDesc::OBJECT) {
+
+		// If the object is from an external file, get it
+		aiScene* obj = NULL;
+        if (src.path.length() ) {
+            obj = batch.GetImport(src.id);
+            if (!obj) {
+                DefaultLogger::get()->error("LWS: Failed to read external file " + src.path);
+            }
+            else {
+                if (obj->mRootNode->mNumChildren == 1) {
+					
+                    //If the pivot is not set for this layer, get it from the external object
+                    if (!src.isPivotSet) {
+                        src.pivotPos.x = +obj->mRootNode->mTransformation.a4;
+                        src.pivotPos.y = +obj->mRootNode->mTransformation.b4;
+                        src.pivotPos.z = -obj->mRootNode->mTransformation.c4; //The sign is the RH to LH back conversion
+                    }
+					
+                    //Remove first node from obj (the old pivot), reset transform of second node (the mesh node)
+                    aiNode* newRootNode = obj->mRootNode->mChildren[0];
+                    free(obj->mRootNode->mChildren);
+                    free(obj->mRootNode);
+                    obj->mRootNode = newRootNode;
+                    obj->mRootNode->mTransformation.a4 = 0.0;
+                    obj->mRootNode->mTransformation.b4 = 0.0;
+                    obj->mRootNode->mTransformation.c4 = 0.0;
+                }
+            }
+        }
+		
+		//Setup the pivot node (also the animation node), the one we received
+        nd->mName = std::string("Pivot:") + nd->mName.data;
+		ndAnim = nd;
+		
+        //Add the attachment node to it
+        nd->mNumChildren = 1;
+        nd->mChildren = new aiNode*[1];
+        nd->mChildren[0] = new aiNode();
+        nd->mChildren[0]->mParent = nd;
+        nd->mChildren[0]->mTransformation.a4 = -src.pivotPos.x;
+        nd->mChildren[0]->mTransformation.b4 = -src.pivotPos.y;
+        nd->mChildren[0]->mTransformation.c4 = -src.pivotPos.z;
+		SetupNodeName(nd->mChildren[0], src);
+		
+		//Update the attachment node
+		nd = nd->mChildren[0];
+		
+        //Push attachment, if the object came from an external file
+        if (obj) {
+            attach.push_back(AttachmentInfo(obj,nd));
+        }
+    }
 
 	// If object is a light source - setup a corresponding ai structure
 	else if (src.type == LWS::NodeDesc::LIGHT) {
@@ -368,7 +413,7 @@ void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vector<Attachm
 
 	// Get the node transformation from the LWO key
 	LWO::AnimResolver resolver(src.channels,fps);
-	resolver.ExtractBindPose(nd->mTransformation);
+	resolver.ExtractBindPose(ndAnim->mTransformation);
 
 	// .. and construct animation channels
 	aiNodeAnim* anim = NULL;
@@ -377,44 +422,11 @@ void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vector<Attachm
 		resolver.SetAnimationRange(first,last);
 		resolver.ExtractAnimChannel(&anim,AI_LWO_ANIM_FLAG_SAMPLE_ANIMS|AI_LWO_ANIM_FLAG_START_AT_ZERO);
 		if (anim) {
-			anim->mNodeName = nd->mName;
+			anim->mNodeName = ndAnim->mName;
 			animOut.push_back(anim);
 		}
 	}
 
-	// process pivot point, if any
-	if (src.pivotPos != aiVector3D()) {
-		aiMatrix4x4 tmp;
-		aiMatrix4x4::Translation(-src.pivotPos,tmp);
-
-		if (anim) {
-		
-			// We have an animation channel for this node. Problem: to combine the pivot
-			// point with the node anims, we'd need to interpolate *all* keys, get 
-			// transformation matrices from them, apply the translation and decompose
-			// the resulting matrices again in order to reconstruct the keys. This 
-			// solution here is *much* easier ... we're just inserting an extra node
-			// in the hierarchy.
-			// Maybe the final optimization here will be done during postprocessing.
-
-			aiNode* pivot = new aiNode();
-			pivot->mName.length = sprintf( pivot->mName.data, "$Pivot_%s",nd->mName.data);
-			pivot->mTransformation = tmp;
-
-			pivot->mChildren = new aiNode*[pivot->mNumChildren = 1];
-			pivot->mChildren[0] = nd;
-
-			pivot->mParent = nd->mParent;
-			nd->mParent    = pivot;
-			
-			// swap children and hope the parents wont see a huge difference
-			pivot->mParent->mChildren[pivot->mParent->mNumChildren-1] = pivot;
-		}
-		else {
-			nd->mTransformation = tmp*nd->mTransformation;
-		}
-	}
-
 	// Add children
 	if (src.children.size()) {
 		nd->mChildren = new aiNode*[src.children.size()];
@@ -585,11 +597,12 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
 			// add node to list
 			LWS::NodeDesc d;
 			d.type = LWS::NodeDesc::OBJECT;
-			d.name = c;
 			if (version >= 4) { // handle LWSC 4 explicit ID
 				d.number = strtoul16(c,&c) & AI_LWS_MASK;
+				SkipSpaces(&c);
 			}
 			else d.number = cur_object++;
+            d.name = c;
 			nodes.push_back(d);
 
 			num_object++;
@@ -780,6 +793,8 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
 				c = fast_atof_move(c, (float&) nodes.back().pivotPos.y );
 				SkipSpaces(&c);
 				c = fast_atof_move(c, (float&) nodes.back().pivotPos.z );
+                // Mark pivotPos as set
+                nodes.back().isPivotSet = true;
 			}
 		}
 	}
@@ -866,7 +881,7 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
 
 	// .. ccw
 	FlipWindingOrderProcess flipper;
-	flipper.Execute(pScene);
+	flipper.Execute(master);
 
 	// OK ... finally build the output graph
 	SceneCombiner::MergeScenes(&pScene,master,attach,

+ 2 - 0
code/LWSLoader.h

@@ -81,6 +81,7 @@ struct NodeDesc
 		:	number	(0)
 		,	parent	(0)
 		,	name	("")
+		,	isPivotSet (false)
 		,	lightColor (1.f,1.f,1.f)
 		,	lightIntensity (1.f)
 		,	lightType (0)
@@ -115,6 +116,7 @@ struct NodeDesc
 
 	// position of pivot point
 	aiVector3D pivotPos;
+	bool isPivotSet;