From 5957e9996bea83ccaec444658f385b7b19a1300e Mon Sep 17 00:00:00 2001 From: aramis_acg Date: Sun, 11 Dec 2011 23:54:04 +0000 Subject: [PATCH 1/3] merge https://github.com/gellule/assimp.git git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@1096 67173fc5-114c-0410-ac8e-9d2fd5bffc1f --- code/LWOAnimation.cpp | 18 +++--- code/LWOLoader.cpp | 141 +++++++++++++++++++++--------------------- code/LWOLoader.h | 2 +- code/LWSLoader.cpp | 115 +++++++++++++++++++--------------- code/LWSLoader.h | 2 + 5 files changed, 148 insertions(+), 130 deletions(-) diff --git a/code/LWOAnimation.cpp b/code/LWOAnimation.cpp index 9e2079cc0..96535976e 100644 --- a/code/LWOAnimation.cpp +++ b/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); } } diff --git a/code/LWOLoader.cpp b/code/LWOLoader.cpp index ee5cc61cc..7ea1caf99 100644 --- a/code/LWOLoader.cpp +++ b/code/LWOLoader.cpp @@ -142,6 +142,7 @@ void LWOImporter::InternReadFile( const std::string& pFile, mLayers->push_back(Layer()); mCurLayer = &mLayers->back(); mCurLayer->mName = ""; + 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::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 apcMeshes; - std::vector apcNodes; - apcNodes. reserve(mLayers->size()); + std::map 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 != "" || 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& } // ------------------------------------------------------------------------------------------------ -void LWOImporter::AddChildren(aiNode* node, uint16_t parent, std::vector& apcNodes) -{ - for (std::vector::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; - } - } - - if (node->mNumChildren) { - unsigned int p = 0; - - node->mChildren = new aiNode* [ node->mNumChildren ]; - for (std::vector::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); - } - } - } - } -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::GenerateNodeGraph(std::vector& apcNodes) +void LWOImporter::GenerateNodeGraph(std::map& apcNodes) { // now generate the final nodegraph - generate a root node and attach children aiNode* root = pScene->mRootNode = new aiNode(); root->mName.Set(""); - 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::iterator it = apcNodes.begin(); it != apcNodes.end(); ++it) { - if ((*it) && (*it)->mNumMeshes) - ++extra; + //Set parent of all children, inserting pivots + std::cout << "Set parent of all children" << std::endl; + std::map mapPivot; + for (std::map::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; } - 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*)); + //Merge pivot map into node map + std::cout << "Merge pivot map into node map" << std::endl; + for (std::map::iterator itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end(); ++itMapPivot) { + apcNodes[itMapPivot->first] = itMapPivot->second; + } - aiNode** cc = apcNewNodes+extra; - for (std::vector::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::iterator itMapParentNodes = apcNodes.begin(); itMapParentNodes != apcNodes.end(); ++itMapParentNodes) { + for (std::map::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::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; diff --git a/code/LWOLoader.h b/code/LWOLoader.h index 156b3680c..71d0de463 100644 --- a/code/LWOLoader.h +++ b/code/LWOLoader.h @@ -303,7 +303,7 @@ private: * Unused nodes are deleted. * @param apcNodes Flat list of nodes */ - void GenerateNodeGraph(std::vector& apcNodes); + void GenerateNodeGraph(std::map& apcNodes); // ------------------------------------------------------------------- /** Add children to a node diff --git a/code/LWSLoader.cpp b/code/LWSLoader.cpp index 5c5336fdd..ee1114a1f 100644 --- a/code/LWSLoader.cpp +++ b/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::vectorerror("LWS: Failed to read external file " + src.path); - } - else { - attach.push_back(AttachmentInfo(obj,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::vectormTransformation); + resolver.ExtractBindPose(ndAnim->mTransformation); // .. and construct animation channels aiNodeAnim* anim = NULL; @@ -377,44 +422,11 @@ void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vectormNodeName = 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, diff --git a/code/LWSLoader.h b/code/LWSLoader.h index 1c1b0730d..9917a0d1b 100644 --- a/code/LWSLoader.h +++ b/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; From d9f7df6bcdcdb82c44e4f72328de72a2fc4073f0 Mon Sep 17 00:00:00 2001 From: aramis_acg Date: Mon, 12 Dec 2011 00:04:58 +0000 Subject: [PATCH 2/3] - LWSLoader: don't use free(). git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@1097 67173fc5-114c-0410-ac8e-9d2fd5bffc1f --- code/LWSLoader.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/code/LWSLoader.cpp b/code/LWSLoader.cpp index ee1114a1f..6519805e8 100644 --- a/code/LWSLoader.cpp +++ b/code/LWSLoader.cpp @@ -338,8 +338,9 @@ void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vectormRootNode->mChildren[0]; - free(obj->mRootNode->mChildren); - free(obj->mRootNode); + obj->mRootNode->mChildren[0] = NULL; + delete obj->mRootNode; + obj->mRootNode = newRootNode; obj->mRootNode->mTransformation.a4 = 0.0; obj->mRootNode->mTransformation.b4 = 0.0; From 3aad6f8b6d75e924c1959da12dd9491ec5951f4e Mon Sep 17 00:00:00 2001 From: aramis_acg Date: Mon, 12 Dec 2011 00:05:23 +0000 Subject: [PATCH 3/3] - add M3 loader to vc9 workspace. git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@1098 67173fc5-114c-0410-ac8e-9d2fd5bffc1f --- workspaces/vc9/assimp.vcproj | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/workspaces/vc9/assimp.vcproj b/workspaces/vc9/assimp.vcproj index a63561ed5..0010c1203 100644 --- a/workspaces/vc9/assimp.vcproj +++ b/workspaces/vc9/assimp.vcproj @@ -2008,6 +2008,18 @@ > + + + + + +