diff --git a/code/3DSConverter.cpp b/code/3DSConverter.cpp index 5ff756469..9c93c3b70 100644 --- a/code/3DSConverter.cpp +++ b/code/3DSConverter.cpp @@ -774,20 +774,13 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut) AddNodeToGraph(pcOut, pcOut->mRootNode, mRootNode,m); } - // We used the first vertex color set to store some - // temporary values so we need to cleanup here + // We used the first vertex color set to store some emporary values so we need to cleanup here for (unsigned int a = 0; a < pcOut->mNumMeshes;++a) pcOut->mMeshes[a]->mColors[0] = NULL; - // if the root node has only one child ... set the child as root node - if (1 == pcOut->mRootNode->mNumChildren) - { - aiNode* pcOld = pcOut->mRootNode; - pcOut->mRootNode = pcOut->mRootNode->mChildren[0]; - pcOut->mRootNode->mParent = NULL; - pcOld->mChildren[0] = NULL; - delete pcOld; - } + // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system + pcOut->mRootNode->mTransformation = aiMatrix4x4(1.f,0.f,0.f,0.f, + 0.f,0.f,1.f,0.f,0.f,-1.f,0.f,0.f,0.f,0.f,0.f,1.f) * pcOut->mRootNode->mTransformation; // If the root node is unnamed name it "<3DSRoot>" if (::strstr( pcOut->mRootNode->mName.data, "UNNAMED" ) || diff --git a/code/ASELoader.cpp b/code/ASELoader.cpp index c3d25959b..a98a13963 100644 --- a/code/ASELoader.cpp +++ b/code/ASELoader.cpp @@ -76,7 +76,7 @@ bool ASEImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool // check file extension const std::string extension = GetExtension(pFile); - if( extension == "ase" || extension == "ask") + if( extension == "ase" || extension == "ask" || extension == "asc") return true; if ((!extension.length() || cs) && pIOHandler) { @@ -89,7 +89,7 @@ bool ASEImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool // ------------------------------------------------------------------------------------------------ void ASEImporter::GetExtensionList(std::string& append) { - append.append("*.ase;*.ask"); + append.append("*.ase;*.ask;*.asc"); } // ------------------------------------------------------------------------------------------------ @@ -124,11 +124,11 @@ void ASEImporter::InternReadFile( const std::string& pFile, this->mBuffer = &mBuffer2[0]; this->pcScene = pScene; - // ***************************************************************** + // ------------------------------------------------------------------ // Guess the file format by looking at the extension // ASC is considered to be the older format 110, // ASE is the actual version 200 (that is currently written by max) - // ***************************************************************** + // ------------------------------------------------------------------ unsigned int defaultFormat; std::string::size_type s = pFile.length()-1; switch (pFile.c_str()[s]) @@ -146,10 +146,10 @@ void ASEImporter::InternReadFile( const std::string& pFile, mParser = &parser; mParser->Parse(); - // ***************************************************************** - // Check whether we loaded at least one mesh. If we did - generate + //------------------------------------------------------------------ + // Check whether we god at least one mesh. If we did - generate // materials and copy meshes. - // ***************************************************************** + // ------------------------------------------------------------------ if ( !mParser->m_vMeshes.empty()) { // If absolutely no material has been loaded from the file @@ -160,16 +160,9 @@ void ASEImporter::InternReadFile( const std::string& pFile, bool tookNormals = false; std::vector avOutMeshes; avOutMeshes.reserve(mParser->m_vMeshes.size()*2); - for (std::vector::iterator - i = mParser->m_vMeshes.begin();i != mParser->m_vMeshes.end();++i) - { + for (std::vector::iterator i = mParser->m_vMeshes.begin();i != mParser->m_vMeshes.end();++i) { if ((*i).bSkip)continue; - - // First of all - we need to build an unique mesh representation - // that we can recompute the normal vectors easily. This is - // also a prerequisite for the second code path in ConvertMeshes() - // so it's difficult to optimize it away. TODO! - BuildUniqueRepresentation(*i); + BuildUniqueRepresentation(*i); // Need to generate proper vertex normals if necessary if(GenerateNormals(*i)) @@ -178,20 +171,16 @@ void ASEImporter::InternReadFile( const std::string& pFile, // Convert all meshes to aiMesh objects ConvertMeshes(*i,avOutMeshes); } - if (tookNormals) - { + if (tookNormals) { DefaultLogger::get()->debug("ASE: Taking normals from the file. Use " - "the AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS option if you " + "the AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS setting if you " "experience problems"); } // Now build the output mesh list. Remove dummies pScene->mNumMeshes = (unsigned int)avOutMeshes.size(); aiMesh** pp = pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; - for (std::vector::const_iterator - i = avOutMeshes.begin(); - i != avOutMeshes.end();++i) - { + for (std::vector::const_iterator i = avOutMeshes.begin();i != avOutMeshes.end();++i) { if (!(*i)->mNumFaces)continue; *pp++ = *i; } @@ -202,25 +191,22 @@ void ASEImporter::InternReadFile( const std::string& pFile, BuildMaterialIndices(); } - // ***************************************************************** + // ------------------------------------------------------------------ // Copy all scene graph nodes - lights, cameras, dummies and meshes - // into one large array - // ***************************************************************** + // into one large array. FIXME: do this during parsing ... + //------------------------------------------------------------------ nodes.reserve(mParser->m_vMeshes.size() +mParser->m_vLights.size() + mParser->m_vCameras.size() + mParser->m_vDummies.size()); // Lights for (std::vector::iterator it = mParser->m_vLights.begin(), end = mParser->m_vLights.end();it != end; ++it)nodes.push_back(&(*it)); - // Cameras for (std::vector::iterator it = mParser->m_vCameras.begin(), end = mParser->m_vCameras.end();it != end; ++it)nodes.push_back(&(*it)); - // Meshes for (std::vector::iterator it = mParser->m_vMeshes.begin(), end = mParser->m_vMeshes.end();it != end; ++it)nodes.push_back(&(*it)); - // Dummies for (std::vector::iterator it = mParser->m_vDummies.begin(), end = mParser->m_vDummies.end();it != end; ++it)nodes.push_back(&(*it)); @@ -237,14 +223,12 @@ void ASEImporter::InternReadFile( const std::string& pFile, // build output lights BuildLights(); - // TODO: STRANGE RESULTS ATM - - // ***************************************************************** + // ------------------------------------------------------------------ // If we have no meshes use the SkeletonMeshBuilder helper class // to build a mesh for the animation skeleton - // ***************************************************************** - if (!pScene->mNumMeshes) - { + // FIXME: very strange results + // ------------------------------------------------------------------ + if (!pScene->mNumMeshes) { pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; SkeletonMeshBuilder skeleton(pScene); } @@ -255,19 +239,14 @@ void ASEImporter::GenerateDefaultMaterial() ai_assert(NULL != mParser); bool bHas = false; - for (std::vector::iterator - i = mParser->m_vMeshes.begin(); - i != mParser->m_vMeshes.end();++i) - { + for (std::vector::iterator i = mParser->m_vMeshes.begin();i != mParser->m_vMeshes.end();++i) { if ((*i).bSkip)continue; - if (ASE::Face::DEFAULT_MATINDEX == (*i).iMaterialIndex) - { + if (ASE::Face::DEFAULT_MATINDEX == (*i).iMaterialIndex) { (*i).iMaterialIndex = (unsigned int)mParser->m_vMaterials.size(); bHas = true; } } - if (bHas || mParser->m_vMaterials.empty()) - { + if (bHas || mParser->m_vMaterials.empty()) { // add a simple material without submaterials to the parser's list mParser->m_vMaterials.push_back ( ASE::Material() ); ASE::Material& mat = mParser->m_vMaterials.back(); @@ -286,21 +265,18 @@ void ASEImporter::BuildAnimations() // check whether we have at least one mesh which has animations std::vector::iterator i = nodes.begin(); unsigned int iNum = 0; - for (;i != nodes.end();++i) - { + for (;i != nodes.end();++i) { + // TODO: Implement Bezier & TCB support - if ((*i)->mAnim.mPositionType != ASE::Animation::TRACK) - { + if ((*i)->mAnim.mPositionType != ASE::Animation::TRACK) { DefaultLogger::get()->warn("ASE: Position controller uses Bezier/TCB keys. " "This is not supported."); } - if ((*i)->mAnim.mRotationType != ASE::Animation::TRACK) - { + if ((*i)->mAnim.mRotationType != ASE::Animation::TRACK) { DefaultLogger::get()->warn("ASE: Rotation controller uses Bezier/TCB keys. " "This is not supported."); } - if ((*i)->mAnim.mScalingType != ASE::Animation::TRACK) - { + if ((*i)->mAnim.mScalingType != ASE::Animation::TRACK) { DefaultLogger::get()->warn("ASE: Position controller uses Bezier/TCB keys. " "This is not supported."); } @@ -308,21 +284,14 @@ void ASEImporter::BuildAnimations() // We compare against 1 here - firstly one key is not // really an animation and secondly MAX writes dummies // that represent the node transformation. - if ((*i)->mAnim.akeyPositions.size() > 1 || - (*i)->mAnim.akeyRotations.size() > 1 || - (*i)->mAnim.akeyScaling.size() > 1) - { + if ((*i)->mAnim.akeyPositions.size()>1 || (*i)->mAnim.akeyRotations.size()>1 || (*i)->mAnim.akeyScaling.size()>1){ ++iNum; } - - if ((*i)->mTargetAnim.akeyPositions.size() > 1 - && is_not_qnan( (*i)->mTargetPosition.x )) - { + if ((*i)->mTargetAnim.akeyPositions.size() > 1 && is_not_qnan( (*i)->mTargetPosition.x )) { ++iNum; } } - if (iNum) - { + if (iNum) { // Generate a new animation channel and setup everything for it pcScene->mNumAnimations = 1; pcScene->mAnimations = new aiAnimation*[1]; @@ -334,12 +303,10 @@ void ASEImporter::BuildAnimations() iNum = 0; // Now iterate through all meshes and collect all data we can find - for (i = nodes.begin();i != nodes.end();++i) - { + for (i = nodes.begin();i != nodes.end();++i) { + ASE::BaseNode* me = *i; - if ( me->mTargetAnim.akeyPositions.size() > 1 - && is_not_qnan( me->mTargetPosition.x )) - { + if ( me->mTargetAnim.akeyPositions.size() > 1 && is_not_qnan( me->mTargetPosition.x )) { // Generate an extra channel for the camera/light target. // BuildNodes() does also generate an extra node, named // .Target. @@ -369,9 +336,7 @@ void ASEImporter::BuildAnimations() nd->mNumPositionKeys * sizeof(aiVectorKey)); } - if (me->mAnim.akeyPositions.size() > 1 || me->mAnim.akeyRotations.size() > 1 || - me->mAnim.akeyScaling.size() > 1) - { + if (me->mAnim.akeyPositions.size() > 1 || me->mAnim.akeyRotations.size() > 1 || me->mAnim.akeyScaling.size() > 1) { // Begin a new node animation channel for this node aiNodeAnim* nd = pcAnim->mChannels[iNum++] = new aiNodeAnim(); nd->mNodeName.Set(me->mName); @@ -387,29 +352,25 @@ void ASEImporter::BuildAnimations() nd->mNumPositionKeys * sizeof(aiVectorKey)); } // copy rotation keys - if (me->mAnim.akeyRotations.size() > 1 ) - { + if (me->mAnim.akeyRotations.size() > 1 ) { // Allocate the key array and fill it nd->mNumRotationKeys = (unsigned int) me->mAnim.akeyRotations.size(); nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys]; - // ************************************************************** + // -------------------------------------------------------------------- // Rotation keys are offsets to the previous keys. // We have the quaternion representations of all // of them, so we just need to concatenate all // (unit-length) quaternions to get the absolute // rotations. - // FIX: Rotation keys are ABSOLUTE for the older - // file format 110 (ASC) - // ************************************************************** + // Rotation keys are ABSOLUTE for older files + // -------------------------------------------------------------------- aiQuaternion cur; - for (unsigned int a = 0; a < nd->mNumRotationKeys;++a) - { + for (unsigned int a = 0; a < nd->mNumRotationKeys;++a) { aiQuatKey q = me->mAnim.akeyRotations[a]; - if (mParser->iFileFormat > 110) - { + if (mParser->iFileFormat > 110) { cur = (a ? cur*q.mValue : q.mValue); q.mValue = cur.Normalize(); } @@ -417,8 +378,7 @@ void ASEImporter::BuildAnimations() } } // copy scaling keys - if (me->mAnim.akeyScaling.size() > 1 ) - { + if (me->mAnim.akeyScaling.size() > 1 ) { // Allocate the key array and fill it nd->mNumScalingKeys = (unsigned int) me->mAnim.akeyScaling.size(); nd->mScalingKeys = new aiVectorKey[nd->mNumScalingKeys]; @@ -432,15 +392,14 @@ void ASEImporter::BuildAnimations() } // ------------------------------------------------------------------------------------------------ +// Build output cameras void ASEImporter::BuildCameras() { - if (!mParser->m_vCameras.empty()) - { + if (!mParser->m_vCameras.empty()) { pcScene->mNumCameras = (unsigned int)mParser->m_vCameras.size(); pcScene->mCameras = new aiCamera*[pcScene->mNumCameras]; - for (unsigned int i = 0; i < pcScene->mNumCameras;++i) - { + for (unsigned int i = 0; i < pcScene->mNumCameras;++i) { aiCamera* out = pcScene->mCameras[i] = new aiCamera(); ASE::Camera& in = mParser->m_vCameras[i]; @@ -455,10 +414,10 @@ void ASEImporter::BuildCameras() } // ------------------------------------------------------------------------------------------------ +// Build output lights void ASEImporter::BuildLights() { - if (!mParser->m_vLights.empty()) - { + if (!mParser->m_vLights.empty()) { pcScene->mNumLights = (unsigned int)mParser->m_vLights.size(); pcScene->mLights = new aiLight*[pcScene->mNumLights]; @@ -467,10 +426,9 @@ void ASEImporter::BuildLights() aiLight* out = pcScene->mLights[i] = new aiLight(); ASE::Light& in = mParser->m_vLights[i]; - // The direction is encoded in the transformation - // matrix of the node. In 3DS MAX the light source - // points in negative Z direction if the node - // transformation is the identity. + // The direction is encoded in the transformation matrix of the node. + // In 3DS MAX the light source points into negative Z direction if + // the node transformation is the identity. out->mDirection = aiVector3D(0.f,0.f,-1.f); out->mName.Set(in.mName); @@ -479,12 +437,10 @@ void ASEImporter::BuildLights() case ASE::Light::TARGET: out->mType = aiLightSource_SPOT; out->mAngleInnerCone = AI_DEG_TO_RAD(in.mAngle); - out->mAngleOuterCone = (in.mFalloff ? AI_DEG_TO_RAD(in.mFalloff) - : out->mAngleInnerCone); + out->mAngleOuterCone = (in.mFalloff ? AI_DEG_TO_RAD(in.mFalloff) : out->mAngleInnerCone); break; case ASE::Light::DIRECTIONAL: - out->mType = aiLightSource_DIRECTIONAL; break; @@ -507,27 +463,26 @@ void ASEImporter::AddNodes(std::vector& nodes, } // ------------------------------------------------------------------------------------------------ +// Add meshes to a given node void ASEImporter::AddMeshes(const ASE::BaseNode* snode,aiNode* node) { - for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) - { - // Get the name of the mesh (the mesh instance has been temporarily - // stored in the third vertex color) + for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) { + // Get the name of the mesh (the mesh instance has been temporarily stored in the third vertex color) const aiMesh* pcMesh = pcScene->mMeshes[i]; const ASE::Mesh* mesh = (const ASE::Mesh*)pcMesh->mColors[2]; - if (mesh == snode)++node->mNumMeshes; + if (mesh == snode) { + ++node->mNumMeshes; + } } - if(node->mNumMeshes) - { + if(node->mNumMeshes) { node->mMeshes = new unsigned int[node->mNumMeshes]; - for (unsigned int i = 0, p = 0; i < pcScene->mNumMeshes;++i) - { + for (unsigned int i = 0, p = 0; i < pcScene->mNumMeshes;++i) { + const aiMesh* pcMesh = pcScene->mMeshes[i]; const ASE::Mesh* mesh = (const ASE::Mesh*)pcMesh->mColors[2]; - if (mesh == snode) - { + if (mesh == snode) { node->mMeshes[p++] = i; // Transform all vertices of the mesh back into their local space -> @@ -537,24 +492,20 @@ void ASEImporter::AddMeshes(const ASE::BaseNode* snode,aiNode* node) aiVector3D* pvCurPtr = pcMesh->mVertices; const aiVector3D* pvEndPtr = pvCurPtr + pcMesh->mNumVertices; - while (pvCurPtr != pvEndPtr) - { + while (pvCurPtr != pvEndPtr) { *pvCurPtr = m * (*pvCurPtr); pvCurPtr++; } - // Do the same for the normal vectors if we have them - // Here we need to use the (Inverse)Transpose of a 3x3 - // matrix without the translational component. - if (pcMesh->mNormals) - { + // Do the same for the normal vectors, if we have them. + // As always, inverse transpose. + if (pcMesh->mNormals) { aiMatrix3x3 m3 = aiMatrix3x3( mesh->mTransform ); m3.Transpose(); pvCurPtr = pcMesh->mNormals; pvEndPtr = pvCurPtr + pcMesh->mNumVertices; - while (pvCurPtr != pvEndPtr) - { + while (pvCurPtr != pvEndPtr) { *pvCurPtr = m3 * (*pvCurPtr); pvCurPtr++; } @@ -565,6 +516,7 @@ void ASEImporter::AddMeshes(const ASE::BaseNode* snode,aiNode* node) } // ------------------------------------------------------------------------------------------------ +// Add child nodes to a given parent node void ASEImporter::AddNodes (std::vector& nodes, aiNode* pcParent, const char* szName, const aiMatrix4x4& mat) @@ -577,12 +529,9 @@ void ASEImporter::AddNodes (std::vector& nodes, // Now iterate through all nodes in the scene and search for one // which has *us* as parent. - for (std::vector::const_iterator it = nodes.begin(), end = nodes.end(); - it != end; ++it) - { + for (std::vector::const_iterator it = nodes.begin(), end = nodes.end(); it != end; ++it) { const BaseNode* snode = *it; - if (szName) - { + if (szName) { if (len != snode->mParent.length() || ::strcmp(szName,snode->mParent.c_str())) continue; } @@ -603,15 +552,13 @@ void ASEImporter::AddNodes (std::vector& nodes, mParentAdjust.Inverse(); node->mTransformation = mParentAdjust*snode->mTransform; - // Add sub nodes - prevent stack overflow - if (node->mName != node->mParent->mName) - { + // Add sub nodes - prevent stack overflow due to recursive parenting + if (node->mName != node->mParent->mName) { AddNodes(nodes,node,node->mName.data,snode->mTransform); } // Further processing depends on the type of the node - if (snode->mType == ASE::BaseNode::Mesh) - { + if (snode->mType == ASE::BaseNode::Mesh) { // If the type of this node is "Mesh" we need to search // the list of output meshes in the data structure for // all those that belonged to this node once. This is @@ -619,15 +566,13 @@ void ASEImporter::AddNodes (std::vector& nodes, // be used when this code is refactored next. AddMeshes(snode,node); } - else if (is_not_qnan( snode->mTargetPosition.x )) - { + else if (is_not_qnan( snode->mTargetPosition.x )) { // If this is a target camera or light we generate a small // child node which marks the position of the camera // target (the direction information is contained in *this* // node's animation track but the exact target position // would be lost otherwise) - if (!node->mNumChildren) - { + if (!node->mNumChildren) { node->mChildren = new aiNode*[1]; } @@ -656,8 +601,7 @@ void ASEImporter::AddNodes (std::vector& nodes, // Allocate enough space for the child nodes // We allocate one slot more in case this is a target camera/light pcParent->mNumChildren = (unsigned int)apcNodes.size(); - if (pcParent->mNumChildren) - { + if (pcParent->mNumChildren) { pcParent->mChildren = new aiNode*[apcNodes.size()+1 /* PLUS ONE !!! */]; // now build all nodes for our nice new children @@ -668,66 +612,59 @@ void ASEImporter::AddNodes (std::vector& nodes, } // ------------------------------------------------------------------------------------------------ -void ASEImporter::BuildNodes() -{ +// Build the output node graph +void ASEImporter::BuildNodes() { ai_assert(NULL != pcScene); // allocate the one and only root node - pcScene->mRootNode = new aiNode(); - pcScene->mRootNode->mNumMeshes = 0; - pcScene->mRootNode->mMeshes = 0; - pcScene->mRootNode->mName.Set(""); + aiNode* root = pcScene->mRootNode = new aiNode(); + root->mName.Set(""); // Setup the coordinate system transformation - //pcScene->mRootNode->mTransformation.c3 *= -1.f; pcScene->mRootNode->mNumChildren = 1; pcScene->mRootNode->mChildren = new aiNode*[1]; - pcScene->mRootNode->mChildren[0] = new aiNode(); + aiNode* ch = pcScene->mRootNode->mChildren[0] = new aiNode(); + ch->mParent = root; // Change the transformation matrix of all nodes - for (std::vector::iterator it = nodes.begin(), end = nodes.end(); - it != end; ++it) - { + for (std::vector::iterator it = nodes.begin(), end = nodes.end();it != end; ++it) { aiMatrix4x4& m = (*it)->mTransform; m.Transpose(); // row-order vs column-order } // add all nodes - AddNodes(nodes,pcScene->mRootNode->mChildren[0],NULL); + AddNodes(nodes,ch,NULL); // now iterate through al nodes and find those that have not yet // been added to the nodegraph (= their parent could not be recognized) std::vector aiList; - for (std::vector::iterator it = nodes.begin(), end = nodes.end(); - it != end; ++it) - { - if ((*it)->mProcessed)continue; + for (std::vector::iterator it = nodes.begin(), end = nodes.end();it != end; ++it) { + if ((*it)->mProcessed) { + continue; + } // check whether our parent is known bool bKnowParent = false; - // research the list, beginning from now and try to find out whether + // search the list another time, starting *here* and try to find out whether // there is a node that references *us* as a parent - for (std::vector::const_iterator it2 = nodes.begin(); - it2 != end; ++it2) - { - if (it2 == it)continue; + for (std::vector::const_iterator it2 = nodes.begin();it2 != end; ++it2) { + if (it2 == it) { + continue; + } - if ((*it2)->mName == (*it)->mParent) - { + if ((*it2)->mName == (*it)->mParent) { bKnowParent = true; break; } } - if (!bKnowParent) - { + if (!bKnowParent) { aiList.push_back(*it); } } // Are there ane orphaned nodes? - if (!aiList.empty()) - { + if (!aiList.empty()) { std::vector apcNodes; apcNodes.reserve(aiList.size() + pcScene->mRootNode->mNumChildren); @@ -735,10 +672,7 @@ void ASEImporter::BuildNodes() apcNodes.push_back(pcScene->mRootNode->mChildren[i]); delete[] pcScene->mRootNode->mChildren; - for (std::vector::/*const_*/iterator - i = aiList.begin(); - i != aiList.end();++i) - { + for (std::vector::/*const_*/iterator i = aiList.begin();i != aiList.end();++i) { const ASE::BaseNode* src = *i; // The parent is not known, so we can assume that we must add @@ -759,40 +693,23 @@ void ASEImporter::BuildNodes() pcScene->mRootNode->mNumChildren = (unsigned int)apcNodes.size(); } - // Reset the third color set to NULL - we used this field to - // store a temporary pointer + // Reset the third color set to NULL - we used this field to store a temporary pointer for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) pcScene->mMeshes[i]->mColors[2] = NULL; - // If there is only one subnode, set it as root node - // FIX: The sub node may not have animations assigned - if (1 == pcScene->mRootNode->mNumChildren && !pcScene->mNumAnimations) - { - aiNode* cc = pcScene->mRootNode->mChildren[0]; - aiNode* pc = pcScene->mRootNode; - - if (!cc->mName.length) - cc->mName = pc->mName; - - pcScene->mRootNode = cc; - cc->mParent = NULL; - - // make sure the destructor won't delete us ... - delete[] pc->mChildren; - pc->mChildren = NULL; - pc->mNumChildren = 0; - delete pc; + // The root node should not have at least one child or the file is valid + if (!pcScene->mRootNode->mNumChildren) { + throw new ImportErrorException("ASE: No nodes loaded. The file is either empty or corrupt"); } - // The root node should not have at least one child or the file is invalid - else if (!pcScene->mRootNode->mNumChildren) { - throw new ImportErrorException("No nodes loaded. The ASE/ASK file is either empty or corrupt"); - } - return; + + // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system + pcScene->mRootNode->mTransformation = aiMatrix4x4(1.f,0.f,0.f,0.f, + 0.f,0.f,1.f,0.f,0.f,-1.f,0.f,0.f,0.f,0.f,0.f,1.f); } // ------------------------------------------------------------------------------------------------ -void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh) -{ +// Convert the imported data to the internal verbose representation +void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh) { // allocate output storage std::vector mPositions; std::vector amTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS]; @@ -804,67 +721,54 @@ void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh) mPositions.resize(iSize); // optional texture coordinates - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i) - { - if (!mesh.amTexCoords[i].empty()) - { + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i) { + if (!mesh.amTexCoords[i].empty()) { amTexCoords[i].resize(iSize); } } // optional vertex colors - if (!mesh.mVertexColors.empty()) - { + if (!mesh.mVertexColors.empty()) { mVertexColors.resize(iSize); } // optional vertex normals (vertex normals can simply be copied) - if (!mesh.mNormals.empty()) - { + if (!mesh.mNormals.empty()) { mNormals.resize(iSize); } // bone vertices. There is no need to change the bone list - if (!mesh.mBoneVertices.empty()) - { + if (!mesh.mBoneVertices.empty()) { mBoneVertices.resize(iSize); } // iterate through all faces in the mesh unsigned int iCurrent = 0, fi = 0; - for (std::vector::iterator - i = mesh.mFaces.begin(); - i != mesh.mFaces.end();++i,++fi) - { + for (std::vector::iterator i = mesh.mFaces.begin();i != mesh.mFaces.end();++i,++fi) { for (unsigned int n = 0; n < 3;++n,++iCurrent) { mPositions[iCurrent] = mesh.mPositions[(*i).mIndices[n]]; // add texture coordinates - for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) - { + for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { if (mesh.amTexCoords[c].empty())break; amTexCoords[c][iCurrent] = mesh.amTexCoords[c][(*i).amUVIndices[c][n]]; } // add vertex colors - if (!mesh.mVertexColors.empty()) - { + if (!mesh.mVertexColors.empty()) { mVertexColors[iCurrent] = mesh.mVertexColors[(*i).mColorIndices[n]]; } // add normal vectors - if (!mesh.mNormals.empty()) - { + if (!mesh.mNormals.empty()) { mNormals[iCurrent] = mesh.mNormals[fi*3+n]; mNormals[iCurrent].Normalize(); } // handle bone vertices - if ((*i).mIndices[n] < mesh.mBoneVertices.size()) - { + if ((*i).mIndices[n] < mesh.mBoneVertices.size()) { // (sometimes this will cause bone verts to be duplicated // however, I' quite sure Schrompf' JoinVerticesStep // will fix that again ...) mBoneVertices[iCurrent] = mesh.mBoneVertices[(*i).mIndices[n]]; } - (*i).mIndices[n] = iCurrent; } } @@ -879,6 +783,7 @@ void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh) } // ------------------------------------------------------------------------------------------------ +// Copy a texture from the ASE structs to the output material void CopyASETexture(MaterialHelper& mat, ASE::Texture& texture, aiTextureType type) { // Setup the texture name @@ -895,6 +800,7 @@ void CopyASETexture(MaterialHelper& mat, ASE::Texture& texture, aiTextureType ty } // ------------------------------------------------------------------------------------------------ +// Convert from ASE material to output material void ASEImporter::ConvertMaterial(ASE::Material& mat) { // LARGE TODO: Much code her is copied from 3DS ... join them maybe? @@ -997,54 +903,46 @@ void ASEImporter::ConvertMaterial(ASE::Material& mat) CopyASETexture(*mat.pcInstance,mat.sTexShininess, aiTextureType_SHININESS); // store the name of the material itself, too - if( mat.mName.length() > 0) - { - aiString tex; - tex.Set( mat.mName); + if( mat.mName.length() > 0) { + aiString tex;tex.Set( mat.mName); mat.pcInstance->AddProperty( &tex, AI_MATKEY_NAME); } return; } // ------------------------------------------------------------------------------------------------ +// Build output meshes void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMeshes) { // validate the material index of the mesh - if (mesh.iMaterialIndex >= mParser->m_vMaterials.size()) - { + if (mesh.iMaterialIndex >= mParser->m_vMaterials.size()) { mesh.iMaterialIndex = (unsigned int)mParser->m_vMaterials.size()-1; DefaultLogger::get()->warn("Material index is out of range"); } - // if the material the mesh is assigned to is consisting of submeshes - // we'll need to split it ... Quak. - if (!mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials.empty()) - { + // If the material the mesh is assigned to is consisting of submeshes, split it + if (!mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials.empty()) { std::vector vSubMaterials = mParser-> m_vMaterials[mesh.iMaterialIndex].avSubMaterials; - std::vector* aiSplit = new std::vector[ - vSubMaterials.size()]; + std::vector* aiSplit = new std::vector[vSubMaterials.size()]; // build a list of all faces per submaterial - for (unsigned int i = 0; i < mesh.mFaces.size();++i) - { + for (unsigned int i = 0; i < mesh.mFaces.size();++i) { // check range - if (mesh.mFaces[i].iMaterial >= vSubMaterials.size()) - { - DefaultLogger::get()->warn("Submaterial index is out of range"); + if (mesh.mFaces[i].iMaterial >= vSubMaterials.size()) { + DefaultLogger::get()->warn("Submaterial index is out of range"); - // use the last material instead - aiSplit[vSubMaterials.size()-1].push_back(i); - } + // use the last material instead + aiSplit[vSubMaterials.size()-1].push_back(i); + } else aiSplit[mesh.mFaces[i].iMaterial].push_back(i); } // now generate submeshes - for (unsigned int p = 0; p < vSubMaterials.size();++p) - { - if (!aiSplit[p].empty()) - { + for (unsigned int p = 0; p < vSubMaterials.size();++p) { + if (!aiSplit[p].empty()) { + aiMesh* p_pcOut = new aiMesh(); p_pcOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; @@ -1067,8 +965,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh // receive output vertex weights std::vector >* avOutputBones; - if (!mesh.mBones.empty()) - { + if (!mesh.mBones.empty()) { avOutputBones = new std::vector >[mesh.mBones.size()]; } @@ -1076,35 +973,31 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh p_pcOut->mFaces = new aiFace[p_pcOut->mNumFaces]; unsigned int iBase = 0,iIndex; - if (p_pcOut->mNumVertices) - { + if (p_pcOut->mNumVertices) { p_pcOut->mVertices = new aiVector3D[p_pcOut->mNumVertices]; p_pcOut->mNormals = new aiVector3D[p_pcOut->mNumVertices]; - for (unsigned int q = 0; q < aiSplit[p].size();++q) - { + for (unsigned int q = 0; q < aiSplit[p].size();++q) { + iIndex = aiSplit[p][q]; p_pcOut->mFaces[q].mIndices = new unsigned int[3]; p_pcOut->mFaces[q].mNumIndices = 3; - for (unsigned int t = 0; t < 3;++t, ++iBase) - { + for (unsigned int t = 0; t < 3;++t, ++iBase) { const uint32_t iIndex2 = mesh.mFaces[iIndex].mIndices[t]; p_pcOut->mVertices[iBase] = mesh.mPositions [iIndex2]; p_pcOut->mNormals [iBase] = mesh.mNormals [iIndex2]; // convert bones, if existing - if (!mesh.mBones.empty()) - { - // check whether there is a vertex weight that is using - // this vertex index ... - if (iIndex2 < mesh.mBoneVertices.size()) - { + if (!mesh.mBones.empty()) { + // check whether there is a vertex weight for this vertex index + if (iIndex2 < mesh.mBoneVertices.size()) { + for (std::vector >::const_iterator blubb = mesh.mBoneVertices[iIndex2].mBoneWeights.begin(); - blubb != mesh.mBoneVertices[iIndex2].mBoneWeights.end();++blubb) - { + blubb != mesh.mBoneVertices[iIndex2].mBoneWeights.end();++blubb) { + // NOTE: illegal cases have already been filtered out avOutputBones[(*blubb).first].push_back(std::pair( iBase,(*blubb).second)); @@ -1116,17 +1009,14 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh } } // convert texture coordinates (up to AI_MAX_NUMBER_OF_TEXTURECOORDS sets supported) - for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) - { + for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { if (!mesh.amTexCoords[c].empty()) { p_pcOut->mTextureCoords[c] = new aiVector3D[p_pcOut->mNumVertices]; iBase = 0; - for (unsigned int q = 0; q < aiSplit[p].size();++q) - { + for (unsigned int q = 0; q < aiSplit[p].size();++q) { iIndex = aiSplit[p][q]; - for (unsigned int t = 0; t < 3;++t) - { + for (unsigned int t = 0; t < 3;++t) { p_pcOut->mTextureCoords[c][iBase++] = mesh.amTexCoords[c][mesh.mFaces[iIndex].mIndices[t]]; } } @@ -1136,22 +1026,18 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh } // Convert vertex colors (only one set supported) - if (!mesh.mVertexColors.empty()) - { + if (!mesh.mVertexColors.empty()){ p_pcOut->mColors[0] = new aiColor4D[p_pcOut->mNumVertices]; iBase = 0; - for (unsigned int q = 0; q < aiSplit[p].size();++q) - { + for (unsigned int q = 0; q < aiSplit[p].size();++q) { iIndex = aiSplit[p][q]; - for (unsigned int t = 0; t < 3;++t) - { + for (unsigned int t = 0; t < 3;++t) { p_pcOut->mColors[0][iBase++] = mesh.mVertexColors[mesh.mFaces[iIndex].mIndices[t]]; } } } // Copy bones - if (!mesh.mBones.empty()) - { + if (!mesh.mBones.empty()) { p_pcOut->mNumBones = 0; for (unsigned int mrspock = 0; mrspock < mesh.mBones.size();++mrspock) if (!avOutputBones[mrspock].empty())p_pcOut->mNumBones++; @@ -1160,8 +1046,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh aiBone** pcBone = p_pcOut->mBones; for (unsigned int mrspock = 0; mrspock < mesh.mBones.size();++mrspock) { - if (!avOutputBones[mrspock].empty()) - { + if (!avOutputBones[mrspock].empty()) { // we will need this bone. add it to the output mesh and // add all per-vertex weights aiBone* pc = *pcBone = new aiBone(); @@ -1211,8 +1096,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh // If the mesh hasn't faces or vertices, there are two cases // possible: 1. the model is invalid. 2. This is a dummy // helper object which we are going to remove later ... - if (mesh.mFaces.empty() || mesh.mPositions.empty()) - { + if (mesh.mFaces.empty() || mesh.mPositions.empty()) { return; } @@ -1234,10 +1118,8 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh mesh.mNormals.size() * sizeof(aiVector3D)); // copy texture coordinates - for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) - { - if (!mesh.amTexCoords[c].empty()) - { + for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { + if (!mesh.amTexCoords[c].empty()) { p_pcOut->mTextureCoords[c] = new aiVector3D[mesh.amTexCoords[c].size()]; memcpy(p_pcOut->mTextureCoords[c],&mesh.amTexCoords[c][0], mesh.amTexCoords[c].size() * sizeof(aiVector3D)); @@ -1248,16 +1130,14 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh } // copy vertex colors - if (!mesh.mVertexColors.empty()) - { + if (!mesh.mVertexColors.empty()) { p_pcOut->mColors[0] = new aiColor4D[mesh.mVertexColors.size()]; memcpy(p_pcOut->mColors[0],&mesh.mVertexColors[0], mesh.mVertexColors.size() * sizeof(aiColor4D)); } // copy faces - for (unsigned int iFace = 0; iFace < p_pcOut->mNumFaces;++iFace) - { + for (unsigned int iFace = 0; iFace < p_pcOut->mNumFaces;++iFace) { p_pcOut->mFaces[iFace].mNumIndices = 3; p_pcOut->mFaces[iFace].mIndices = new unsigned int[3]; @@ -1268,17 +1148,14 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh } // copy vertex bones - if (!mesh.mBones.empty() && !mesh.mBoneVertices.empty()) - { - std::vector* avBonesOut = new - std::vector[mesh.mBones.size()]; + if (!mesh.mBones.empty() && !mesh.mBoneVertices.empty()) { + std::vector* avBonesOut = new std::vector[mesh.mBones.size()]; // find all vertex weights for this bone unsigned int quak = 0; - for (std::vector::const_iterator - harrypotter = mesh.mBoneVertices.begin(); - harrypotter != mesh.mBoneVertices.end();++harrypotter,++quak) - { + for (std::vector::const_iterator harrypotter = mesh.mBoneVertices.begin(); + harrypotter != mesh.mBoneVertices.end();++harrypotter,++quak) { + for (std::vector >::const_iterator ronaldweasley = (*harrypotter).mBoneWeights.begin(); ronaldweasley != (*harrypotter).mBoneWeights.end();++ronaldweasley) @@ -1297,10 +1174,8 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh p_pcOut->mBones = new aiBone*[p_pcOut->mNumBones]; aiBone** pcBone = p_pcOut->mBones; - for (unsigned int jfkennedy = 0; jfkennedy < mesh.mBones.size();++jfkennedy) - { - if (!avBonesOut[jfkennedy].empty()) - { + for (unsigned int jfkennedy = 0; jfkennedy < mesh.mBones.size();++jfkennedy) { + if (!avBonesOut[jfkennedy].empty()) { aiBone* pc = *pcBone = new aiBone(); pc->mName.Set(mesh.mBones[jfkennedy].mName); pc->mNumWeights = (unsigned int)avBonesOut[jfkennedy].size(); @@ -1318,6 +1193,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh } // ------------------------------------------------------------------------------------------------ +// Setup proper material indices and build output materials void ASEImporter::BuildMaterialIndices() { ai_assert(NULL != pcScene); @@ -1326,8 +1202,7 @@ void ASEImporter::BuildMaterialIndices() for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat) { ASE::Material& mat = mParser->m_vMaterials[iMat]; - if (mat.bNeed) - { + if (mat.bNeed) { // Convert it to the aiMaterial layout ConvertMaterial(mat); ++pcScene->mNumMaterials; @@ -1335,8 +1210,7 @@ void ASEImporter::BuildMaterialIndices() for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size();++iSubMat) { ASE::Material& submat = mat.avSubMaterials[iSubMat]; - if (submat.bNeed) - { + if (submat.bNeed) { // Convert it to the aiMaterial layout ConvertMaterial(submat); ++pcScene->mNumMaterials; @@ -1349,8 +1223,7 @@ void ASEImporter::BuildMaterialIndices() D3DS::Material** pcIntMaterials = new D3DS::Material*[pcScene->mNumMaterials]; unsigned int iNum = 0; - for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat) - { + for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat) { ASE::Material& mat = mParser->m_vMaterials[iMat]; if (mat.bNeed) { @@ -1374,11 +1247,9 @@ void ASEImporter::BuildMaterialIndices() } iNum++; } - for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size();++iSubMat) - { + for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size();++iSubMat) { ASE::Material& submat = mat.avSubMaterials[iSubMat]; - if (submat.bNeed) - { + if (submat.bNeed) { ai_assert(NULL != submat.pcInstance); pcScene->mMaterials[iNum] = submat.pcInstance; @@ -1387,11 +1258,10 @@ void ASEImporter::BuildMaterialIndices() // Iterate through all meshes and search for one which is using // this sub-level material index - for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh) - { + for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh) { aiMesh* mesh = pcScene->mMeshes[iMesh]; - if (iSubMat == mesh->mMaterialIndex && iMat == (uintptr_t)mesh->mColors[3]) - { + + if (iSubMat == mesh->mMaterialIndex && iMat == (uintptr_t)mesh->mColors[3]) { mesh->mMaterialIndex = iNum; mesh->mColors[3] = NULL; } @@ -1407,24 +1277,20 @@ void ASEImporter::BuildMaterialIndices() // ------------------------------------------------------------------------------------------------ // Generate normal vectors basing on smoothing groups -bool ASEImporter::GenerateNormals(ASE::Mesh& mesh) -{ +bool ASEImporter::GenerateNormals(ASE::Mesh& mesh) { + if (!mesh.mNormals.empty() && !configRecomputeNormals) { - // check whether there are only uninitialized normals. If there are + // Check whether there are only uninitialized normals. If there are // some, skip all normals from the file and compute them on our own - for (std::vector::const_iterator - qq = mesh.mNormals.begin(); - qq != mesh.mNormals.end();++qq) - { + for (std::vector::const_iterator qq = mesh.mNormals.begin();qq != mesh.mNormals.end();++qq) { if ((*qq).x || (*qq).y || (*qq).z) { return true; } } } - - // The array will be reused + // The array ís reused ComputeNormalsWithSmoothingsGroups(mesh); return false; } diff --git a/code/ASEParser.cpp b/code/ASEParser.cpp index bbc036f8b..e4f5ae31f 100644 --- a/code/ASEParser.cpp +++ b/code/ASEParser.cpp @@ -1889,18 +1889,20 @@ void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh& sMesh) sMesh.mNormals.resize(sMesh.mFaces.size()*3,aiVector3D( 0.f, 0.f, 0.f )); unsigned int index, faceIdx = 0xffffffff; + // FIXME: rewrite this and find out how to interpret the normals + // correctly. This is crap. + // Smooth the vertex and face normals together. The result // will be edgy then, but otherwise everything would be soft ... - while (true) - { - if ('*' == *filePtr) - { + while (true) { + if ('*' == *filePtr) { ++filePtr; - if (faceIdx != 0xffffffff && TokenMatch(filePtr,"MESH_VERTEXNORMAL",17)) - { + if (faceIdx != 0xffffffff && TokenMatch(filePtr,"MESH_VERTEXNORMAL",17)) { aiVector3D vNormal; ParseLV4MeshFloatTriple(&vNormal.x,index); - + if (faceIdx >= sMesh.mFaces.size()) + continue; + // Make sure we assign it to the correct face const ASE::Face& face = sMesh.mFaces[faceIdx]; if (index == face.mIndices[0]) @@ -1909,29 +1911,27 @@ void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh& sMesh) index = 1; else if (index == face.mIndices[2]) index = 2; - else - { + else { DefaultLogger::get()->error("ASE: Invalid vertex index in MESH_VERTEXNORMAL section"); continue; } - // We'll renormalize later sMesh.mNormals[faceIdx*3+index] += vNormal; continue; } - if (TokenMatch(filePtr,"MESH_FACENORMAL",15)) - { + if (TokenMatch(filePtr,"MESH_FACENORMAL",15)) { aiVector3D vNormal; ParseLV4MeshFloatTriple(&vNormal.x,faceIdx); - if (faceIdx >= sMesh.mFaces.size()) - { + if (faceIdx >= sMesh.mFaces.size()) { DefaultLogger::get()->error("ASE: Invalid vertex index in MESH_FACENORMAL section"); continue; } // We'll renormalize later sMesh.mNormals[faceIdx*3] += vNormal; + sMesh.mNormals[faceIdx*3+1] += vNormal; + sMesh.mNormals[faceIdx*3+2] += vNormal; continue; } } diff --git a/code/B3DImporter.cpp b/code/B3DImporter.cpp index cbc95e49a..b6679d190 100644 --- a/code/B3DImporter.cpp +++ b/code/B3DImporter.cpp @@ -49,6 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // internal headers #include "B3DImporter.h" #include "TextureTransform.h" +#include "ConvertToLHProcess.h" using namespace Assimp; using namespace std; @@ -119,11 +120,6 @@ void B3DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS //create root node aiNode *node=new aiNode( "root" ); - node->mTransformation=aiMatrix4x4( - 1,0,0,0, - 0,0,1,0, - 0,1,0,0, - 0,0,0,1 ); node->mNumMeshes=_meshes.size(); node->mMeshes=new unsigned[_meshes.size()]; @@ -131,6 +127,10 @@ void B3DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS node->mMeshes[i]=i; } pScene->mRootNode=node; + + // convert to RH + MakeLeftHandedProcess monster_maker; + monster_maker.Execute(pScene); } // ------------------------------------------------------------------------------------------------ @@ -348,8 +348,8 @@ void B3DImporter::ReadTRIS(){ unsigned *ip=face->mIndices=new unsigned[3]; int v[3]; v[0]=ReadInt(); - v[2]=ReadInt(); v[1]=ReadInt(); + v[2]=ReadInt(); for( unsigned j=0;j<3;++j ){ int k=v[j]; const Vertex &v=_vertices[k]; diff --git a/code/ConvertToLHProcess.cpp b/code/ConvertToLHProcess.cpp index 969b702f1..9b82863d1 100644 --- a/code/ConvertToLHProcess.cpp +++ b/code/ConvertToLHProcess.cpp @@ -39,136 +39,220 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -/** @file Implementation of the post processing step to convert all imported data - * to a left-handed coordinate system. +/** @file MakeLeftHandedProcess.cpp + * @brief Implementation of the post processing step to convert all + * imported data to a left-handed coordinate system. + * + * Face order & UV flip are also implemented here, for the sake of a + * better location. */ #include "AssimpPCH.h" #include "ConvertToLHProcess.h" - using namespace Assimp; -// The transformation matrix to convert from DirectX coordinates to OpenGL coordinates. -const aiMatrix3x3 Assimp::ConvertToLHProcess::sToOGLTransform( - 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f - ); -// The transformation matrix to convert from OpenGL coordinates to DirectX coordinates. -const aiMatrix3x3 Assimp::ConvertToLHProcess::sToDXTransform( - 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f - ); +#ifndef ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer -ConvertToLHProcess::ConvertToLHProcess() -{ - bTransformVertices = false; -} +MakeLeftHandedProcess::MakeLeftHandedProcess() +{} // ------------------------------------------------------------------------------------------------ // Destructor, private as well -ConvertToLHProcess::~ConvertToLHProcess() -{ - // nothing to do here -} +MakeLeftHandedProcess::~MakeLeftHandedProcess() +{} // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. -bool ConvertToLHProcess::IsActive( unsigned int pFlags) const +bool MakeLeftHandedProcess::IsActive( unsigned int pFlags) const { - if (pFlags & aiProcess_ConvertToLeftHanded) - { - bTransformVertices = (0 != (pFlags & aiProcess_PreTransformVertices) ? true : false); - return true; - } - return false; + return 0 != (pFlags & aiProcess_MakeLeftHanded); } // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. -void ConvertToLHProcess::Execute( aiScene* pScene) +void MakeLeftHandedProcess::Execute( aiScene* pScene) { // Check for an existent root node to proceed - if (NULL == pScene->mRootNode) - { - DefaultLogger::get()->error("ConvertToLHProcess fails, there is no root node"); - return; - } + ai_assert(pScene->mRootNode != NULL); + DefaultLogger::get()->debug("MakeLeftHandedProcess begin"); - DefaultLogger::get()->debug("ConvertToLHProcess begin"); + // recursively convert all the nodes + ProcessNode( pScene->mRootNode, aiMatrix4x4()); - // transform vertex by vertex or change the root transform? - // We can't do the coordinate system transformation earlier - // in the pipeline - most steps assume that we're in OGL - // space. So we need to transform all vertices a second time - // here. - if (bTransformVertices) - { - aiMatrix4x4 mTransform; - ConvertToDX(mTransform); - for (unsigned int i = 0; i < pScene->mNumMeshes;++i) - { - aiMesh* pcMesh = pScene->mMeshes[i]; - - // transform all vertices - for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) - pcMesh->mVertices[n] = mTransform * pcMesh->mVertices[n]; - - // transform all normals - if (pcMesh->HasNormals()) - { - for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) - pcMesh->mNormals[n] = mTransform * pcMesh->mNormals[n]; - } - // transform all tangents and all bitangents - if (pcMesh->HasTangentsAndBitangents()) - { - for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) - { - pcMesh->mTangents[n] = mTransform * pcMesh->mTangents[n]; - pcMesh->mBitangents[n] = mTransform * pcMesh->mBitangents[n]; - } - } - } - } - else - { - // transform the root node of the scene, the other nodes will follow then - ConvertToDX( pScene->mRootNode->mTransformation); - } - - // transform all meshes accordingly - for( unsigned int a = 0; a < pScene->mNumMeshes; a++) + // process the meshes accordingly + for( unsigned int a = 0; a < pScene->mNumMeshes; ++a) ProcessMesh( pScene->mMeshes[a]); - // process all materials - we need to adjust UV transformations - for( unsigned int a = 0; a < pScene->mNumMaterials; a++) + // process the materials accordingly + for( unsigned int a = 0; a < pScene->mNumMaterials; ++a) ProcessMaterial( pScene->mMaterials[a]); - // transform all animation channels affecting the root node as well + // transform all animation channels as well for( unsigned int a = 0; a < pScene->mNumAnimations; a++) { aiAnimation* anim = pScene->mAnimations[a]; for( unsigned int b = 0; b < anim->mNumChannels; b++) { aiNodeAnim* nodeAnim = anim->mChannels[b]; - if( strcmp( nodeAnim->mNodeName.data, pScene->mRootNode->mName.data) == 0) - ProcessAnimation( nodeAnim); + ProcessAnimation( nodeAnim); } } - DefaultLogger::get()->debug("ConvertToLHProcess finished"); + + // flipping a single vector component means inverting face order ... + FlipWindingOrderProcess flipper; + flipper.Execute(pScene); + + DefaultLogger::get()->debug("MakeLeftHandedProcess finished"); +} + +// ------------------------------------------------------------------------------------------------ +// Recursively converts a node, all of its children and all of its meshes +void MakeLeftHandedProcess::ProcessNode( aiNode* pNode, const aiMatrix4x4& pParentGlobalRotation) +{ + // mirror all base vectors at the local Z axis + pNode->mTransformation.c1 = -pNode->mTransformation.c1; + pNode->mTransformation.c2 = -pNode->mTransformation.c2; + pNode->mTransformation.c3 = -pNode->mTransformation.c3; + pNode->mTransformation.c4 = -pNode->mTransformation.c4; + + // now invert the Z axis again to keep the matrix determinant positive. + // The local meshes will be inverted accordingly so that the result should look just fine again. + pNode->mTransformation.a3 = -pNode->mTransformation.a3; + pNode->mTransformation.b3 = -pNode->mTransformation.b3; + pNode->mTransformation.c3 = -pNode->mTransformation.c3; + pNode->mTransformation.d3 = -pNode->mTransformation.d3; // useless, but anyways... + + // continue for all children + for( size_t a = 0; a < pNode->mNumChildren; ++a) + ProcessNode( pNode->mChildren[a], pParentGlobalRotation * pNode->mTransformation); +} + +// ------------------------------------------------------------------------------------------------ +// Converts a single mesh to left handed coordinates. +void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh) +{ + // mirror positions, normals and stuff along the Z axis + for( size_t a = 0; a < pMesh->mNumVertices; ++a) + { + pMesh->mVertices[a].z *= -1.0f; + if( pMesh->HasNormals()) + pMesh->mNormals[a].z *= -1.0f; + if( pMesh->HasTangentsAndBitangents()) + { + pMesh->mTangents[a].z *= -1.0f; + pMesh->mBitangents[a].z *= -1.0f; + } + } + + // mirror offset matrices of all bones + for( size_t a = 0; a < pMesh->mNumBones; ++a) + { + aiBone* bone = pMesh->mBones[a]; + bone->mOffsetMatrix.a3 = -bone->mOffsetMatrix.a3; + bone->mOffsetMatrix.b3 = -bone->mOffsetMatrix.b3; + bone->mOffsetMatrix.d3 = -bone->mOffsetMatrix.d3; + bone->mOffsetMatrix.c1 = -bone->mOffsetMatrix.c1; + bone->mOffsetMatrix.c2 = -bone->mOffsetMatrix.c2; + bone->mOffsetMatrix.c4 = -bone->mOffsetMatrix.c4; + } + + // mirror bitangents as well as they're derived from the texture coords + if( pMesh->HasTangentsAndBitangents()) + { + for( unsigned int a = 0; a < pMesh->mNumVertices; a++) + pMesh->mBitangents[a] *= -1.0f; + } } // ------------------------------------------------------------------------------------------------ // Converts a single material to left handed coordinates. -void ConvertToLHProcess::ProcessMaterial (aiMaterial* mat) +void MakeLeftHandedProcess::ProcessMaterial( aiMaterial* _mat) { - for (unsigned int a = 0; a < mat->mNumProperties;++a) - { + MaterialHelper* mat = (MaterialHelper*)_mat; + for (unsigned int a = 0; a < mat->mNumProperties;++a) { aiMaterialProperty* prop = mat->mProperties[a]; - if (!::strcmp( prop->mKey.data, "$tex.uvtrafo")) - { - ai_assert( prop->mDataLength >= sizeof(aiUVTransform)); + + // Mapping axis for UV mappings? + if (!::strcmp( prop->mKey.data, "$tex.mapaxis")) { + ai_assert( prop->mDataLength >= sizeof(aiVector3D)); /* something is wrong with the validation if we end up here */ + aiVector3D* pff = (aiVector3D*)prop->mData; + + pff->z *= -1.f; + } + } +} + +// ------------------------------------------------------------------------------------------------ +// Converts the given animation to LH coordinates. +void MakeLeftHandedProcess::ProcessAnimation( aiNodeAnim* pAnim) +{ + // position keys + for( unsigned int a = 0; a < pAnim->mNumPositionKeys; a++) + pAnim->mPositionKeys[a].mValue.z *= -1.0f; + + // rotation keys + for( unsigned int a = 0; a < pAnim->mNumRotationKeys; a++) + { + /* That's the safe version, but the float errors add up. So we try the short version instead + aiMatrix3x3 rotmat = pAnim->mRotationKeys[a].mValue.GetMatrix(); + rotmat.a3 = -rotmat.a3; rotmat.b3 = -rotmat.b3; + rotmat.c1 = -rotmat.c1; rotmat.c2 = -rotmat.c2; + aiQuaternion rotquat( rotmat); + pAnim->mRotationKeys[a].mValue = rotquat; + */ + pAnim->mRotationKeys[a].mValue.x *= -1.0f; + pAnim->mRotationKeys[a].mValue.y *= -1.0f; + } +} + +#endif // !! ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS +#ifndef ASSIMP_BUILD_NO_FLIPUVS_PROCESS +// # FlipUVsProcess + +// ------------------------------------------------------------------------------------------------ +// Constructor to be privately used by Importer +FlipUVsProcess::FlipUVsProcess() +{} + +// ------------------------------------------------------------------------------------------------ +// Destructor, private as well +FlipUVsProcess::~FlipUVsProcess() +{} + +// ------------------------------------------------------------------------------------------------ +// Returns whether the processing step is present in the given flag field. +bool FlipUVsProcess::IsActive( unsigned int pFlags) const +{ + return 0 != (pFlags & aiProcess_FlipUVs); +} + +// ------------------------------------------------------------------------------------------------ +// Executes the post processing step on the given imported data. +void FlipUVsProcess::Execute( aiScene* pScene) +{ + DefaultLogger::get()->debug("FlipUVsProcess begin"); + for (unsigned int i = 0; i < pScene->mNumMeshes;++i) + ProcessMesh(pScene->mMeshes[i]); + + for (unsigned int i = 0; i < pScene->mNumMaterials;++i) + ProcessMaterial(pScene->mMaterials[i]); + DefaultLogger::get()->debug("FlipUVsProcess finished"); +} + +// ------------------------------------------------------------------------------------------------ +// Converts a single material +void FlipUVsProcess::ProcessMaterial (aiMaterial* _mat) +{ + MaterialHelper* mat = (MaterialHelper*)_mat; + for (unsigned int a = 0; a < mat->mNumProperties;++a) { + aiMaterialProperty* prop = mat->mProperties[a]; + + // UV transformation key? + if (!::strcmp( prop->mKey.data, "$tex.uvtrafo")) { + ai_assert( prop->mDataLength >= sizeof(aiUVTransform)); /* something is wrong with the validation if we end up here */ aiUVTransform* uv = (aiUVTransform*)prop->mData; // just flip it, that's everything @@ -179,8 +263,53 @@ void ConvertToLHProcess::ProcessMaterial (aiMaterial* mat) } // ------------------------------------------------------------------------------------------------ -// Converts a single mesh to left handed coordinates. -void ConvertToLHProcess::ProcessMesh( aiMesh* pMesh) +// Converts a single mesh +void FlipUVsProcess::ProcessMesh( aiMesh* pMesh) +{ + // mirror texture y coordinate + for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++) { + if( !pMesh->HasTextureCoords( a)) + break; + + for( unsigned int b = 0; b < pMesh->mNumVertices; b++) + pMesh->mTextureCoords[a][b].y = 1.0f - pMesh->mTextureCoords[a][b].y; + } +} + +#endif // !ASSIMP_BUILD_NO_FLIPUVS_PROCESS +#ifndef ASSIMP_BUILD_NO_FLIPWINDING_PROCESS +// # FlipWindingOrderProcess + +// ------------------------------------------------------------------------------------------------ +// Constructor to be privately used by Importer +FlipWindingOrderProcess::FlipWindingOrderProcess() +{} + +// ------------------------------------------------------------------------------------------------ +// Destructor, private as well +FlipWindingOrderProcess::~FlipWindingOrderProcess() +{} + +// ------------------------------------------------------------------------------------------------ +// Returns whether the processing step is present in the given flag field. +bool FlipWindingOrderProcess::IsActive( unsigned int pFlags) const +{ + return 0 != (pFlags & aiProcess_FlipWindingOrder); +} + +// ------------------------------------------------------------------------------------------------ +// Executes the post processing step on the given imported data. +void FlipWindingOrderProcess::Execute( aiScene* pScene) +{ + DefaultLogger::get()->debug("FlipWindingOrderProcess begin"); + for (unsigned int i = 0; i < pScene->mNumMeshes;++i) + ProcessMesh(pScene->mMeshes[i]); + DefaultLogger::get()->debug("FlipWindingOrderProcess finished"); +} + +// ------------------------------------------------------------------------------------------------ +// Converts a single mesh +void FlipWindingOrderProcess::ProcessMesh( aiMesh* pMesh) { // invert the order of all faces in this mesh for( unsigned int a = 0; a < pMesh->mNumFaces; a++) @@ -189,77 +318,6 @@ void ConvertToLHProcess::ProcessMesh( aiMesh* pMesh) for( unsigned int b = 0; b < face.mNumIndices / 2; b++) std::swap( face.mIndices[b], face.mIndices[ face.mNumIndices - 1 - b]); } - - // mirror texture y coordinate - for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++) - { - if( pMesh->HasTextureCoords( a)) - { - for( unsigned int b = 0; b < pMesh->mNumVertices; b++) - pMesh->mTextureCoords[a][b].y = 1.0f - pMesh->mTextureCoords[a][b].y; - } - } - - // mirror bitangents as well as they're derived from the texture coords - if( pMesh->HasTangentsAndBitangents()) - { - for( unsigned int a = 0; a < pMesh->mNumVertices; a++) - pMesh->mBitangents[a] = -pMesh->mBitangents[a]; - } } -// ------------------------------------------------------------------------------------------------ -// Converts the given animation to LH coordinates. -void ConvertToLHProcess::ProcessAnimation( aiNodeAnim* pAnim) -{ - // position keys - for( unsigned int a = 0; a < pAnim->mNumPositionKeys; a++) - ConvertToDX( pAnim->mPositionKeys[a].mValue); - - return; - // rotation keys - for( unsigned int a = 0; a < pAnim->mNumRotationKeys; a++) - { - aiMatrix3x3 rotmat = pAnim->mRotationKeys[a].mValue.GetMatrix(); - ConvertToDX( rotmat); - pAnim->mRotationKeys[a].mValue = aiQuaternion( rotmat); - } -} - -// ------------------------------------------------------------------------------------------------ -// Static helper function to convert a vector/matrix from DX to OGL coords -void ConvertToLHProcess::ConvertToOGL( aiVector3D& poVector) -{ - poVector = sToOGLTransform * poVector; -} - -// ------------------------------------------------------------------------------------------------ -void ConvertToLHProcess::ConvertToOGL( aiMatrix3x3& poMatrix) -{ - poMatrix = sToOGLTransform * poMatrix; -} - -// ------------------------------------------------------------------------------------------------ -void ConvertToLHProcess::ConvertToOGL( aiMatrix4x4& poMatrix) -{ - poMatrix = aiMatrix4x4( sToOGLTransform) * poMatrix; -} - -// ------------------------------------------------------------------------------------------------ -// Static helper function to convert a vector/matrix from OGL back to DX coords -void ConvertToLHProcess::ConvertToDX( aiVector3D& poVector) -{ - poVector = sToDXTransform * poVector; -} - -// ------------------------------------------------------------------------------------------------ -void ConvertToLHProcess::ConvertToDX( aiMatrix3x3& poMatrix) -{ - poMatrix = sToDXTransform * poMatrix; -} - -// ------------------------------------------------------------------------------------------------ -void ConvertToLHProcess::ConvertToDX( aiMatrix4x4& poMatrix) -{ - poMatrix = aiMatrix4x4(sToDXTransform) * poMatrix; -} +#endif // !! ASSIMP_BUILD_NO_FLIPWINDING_PROCESS \ No newline at end of file diff --git a/code/ConvertToLHProcess.h b/code/ConvertToLHProcess.h index 1f8fca2bd..53b7ec0f5 100644 --- a/code/ConvertToLHProcess.h +++ b/code/ConvertToLHProcess.h @@ -38,7 +38,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file Defines a post processing step to convert all data to a left-handed coordinate system.*/ +/** @file MakeLeftHandedProcess.h + * @brief Defines a bunch of post-processing steps to handle + * coordinate system conversions. + * + * - LH to RH + * - UV origin upper-left to lower-left + * - face order cw to ccw + */ #ifndef AI_CONVERTTOLHPROCESS_H_INC #define AI_CONVERTTOLHPROCESS_H_INC @@ -48,72 +55,55 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. struct aiMesh; struct aiNodeAnim; -namespace Assimp -{ +namespace Assimp { -// --------------------------------------------------------------------------- -/** The ConvertToLHProcess converts all imported data to a left-handed coordinate - * system. This implies inverting the Z axis for all transformation matrices - * invert the orientation of all faces, and adapting skinning and animation - * data in a similar way. +// ----------------------------------------------------------------------------------- +/** @brief The MakeLeftHandedProcess converts all imported data to a left-handed + * coordinate system. + * + * This implies a mirroring of the Z axis of the coordinate system. But to keep + * transformation matrices free from reflections we shift the reflection to other + * places. We mirror the meshes and adapt the rotations. + * + * @note RH-LH and LH-RH is the same, so this class can be used for both */ -class ASSIMP_API ConvertToLHProcess : public BaseProcess +class ASSIMP_API MakeLeftHandedProcess : public BaseProcess { friend class Importer; -protected: +public: /** Constructor to be privately used by Importer */ - ConvertToLHProcess(); + MakeLeftHandedProcess(); /** Destructor, private as well */ - ~ConvertToLHProcess(); + ~MakeLeftHandedProcess(); -public: // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag field. - * @param pFlags The processing flags the importer was called with. A bitwise - * combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, false if not. - */ bool IsActive( unsigned int pFlags) const; // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ void Execute( aiScene* pScene); - // ------------------------------------------------------------------- - /** Static helper function to convert a vector/matrix from DX coords to OGL coords. - * @param poMatrix The matrix to convert. - */ - static void ConvertToOGL( aiVector3D& poVector); - static void ConvertToOGL( aiMatrix3x3& poMatrix); - static void ConvertToOGL( aiMatrix4x4& poMatrix); - - // ------------------------------------------------------------------- - /** Static helper function to convert a vector/matrix from OGL coords back to DX coords. - * @param poMatrix The matrix to convert. - */ - static void ConvertToDX( aiVector3D& poVector); - static void ConvertToDX( aiMatrix3x3& poMatrix); - static void ConvertToDX( aiMatrix4x4& poMatrix); - protected: + + // ------------------------------------------------------------------- + /** Recursively converts a node and all of its children + */ + void ProcessNode( aiNode* pNode, const aiMatrix4x4& pParentGlobalRotation); + // ------------------------------------------------------------------- /** Converts a single mesh to left handed coordinates. - * This simply means the order of all faces is inverted. + * This means that positions, normals and tangents are mirrored at + * the local Z axis and the order of all faces are inverted. * @param pMesh The mesh to convert. */ void ProcessMesh( aiMesh* pMesh); // ------------------------------------------------------------------- - /** Converts a single material to left handed coordinates. - * This simply means all UV offsets are inverted. - * @param mat The material to convert. + /** Converts a single material to left-handed coordinates + * @param pMat Material to convert */ - void ProcessMaterial (aiMaterial* mat); + void ProcessMaterial( aiMaterial* pMat); // ------------------------------------------------------------------- /** Converts the given animation to LH coordinates. @@ -122,16 +112,56 @@ protected: * @param pAnim The bone animation to transform */ void ProcessAnimation( aiNodeAnim* pAnim); +}; - //! true if the transformation matrix for the OGL-to-DX is - //! directly used to transform all vertices. - mutable bool bTransformVertices; + +// --------------------------------------------------------------------------- +/** Postprocessing step to flip the face order of the imported data + */ +class ASSIMP_API FlipWindingOrderProcess : public BaseProcess +{ + friend class Importer; public: - /** The transformation matrix to convert from DirectX coordinates to OpenGL coordinates. */ - static const aiMatrix3x3 sToOGLTransform; - /** The transformation matrix to convert from OpenGL coordinates to DirectX coordinates. */ - static const aiMatrix3x3 sToDXTransform; + /** Constructor to be privately used by Importer */ + FlipWindingOrderProcess(); + + /** Destructor, private as well */ + ~FlipWindingOrderProcess(); + + // ------------------------------------------------------------------- + bool IsActive( unsigned int pFlags) const; + + // ------------------------------------------------------------------- + void Execute( aiScene* pScene); + +protected: + void ProcessMesh( aiMesh* pMesh); +}; + +// --------------------------------------------------------------------------- +/** Postprocessing step to flip the UV coordinate system of the import data + */ +class ASSIMP_API FlipUVsProcess : public BaseProcess +{ + friend class Importer; + +public: + /** Constructor to be privately used by Importer */ + FlipUVsProcess(); + + /** Destructor, private as well */ + ~FlipUVsProcess(); + + // ------------------------------------------------------------------- + bool IsActive( unsigned int pFlags) const; + + // ------------------------------------------------------------------- + void Execute( aiScene* pScene); + +protected: + void ProcessMesh( aiMesh* pMesh); + void ProcessMaterial( aiMaterial* mat); }; } // end of namespace Assimp diff --git a/code/DXFLoader.cpp b/code/DXFLoader.cpp index c7fe9b803..58dec4b09 100644 --- a/code/DXFLoader.cpp +++ b/code/DXFLoader.cpp @@ -84,16 +84,12 @@ aiColor4D g_clrInvalid = aiColor4D(get_qnan(),0.f,0.f,1.f); // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer DXFImporter::DXFImporter() -{ - // nothing to do here -} +{} // ------------------------------------------------------------------------------------------------ // Destructor, private as well DXFImporter::~DXFImporter() -{ - // nothing to do here -} +{} // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. @@ -103,6 +99,7 @@ bool DXFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool } // ------------------------------------------------------------------------------------------------ +// Get a list of all supported file extensions void DXFImporter::GetExtensionList(std::string& append) { append.append("*.dxf"); @@ -115,8 +112,7 @@ bool DXFImporter::GetNextLine() if(!SkipLine(&buffer)) return false; if(!SkipSpaces(&buffer))return GetNextLine(); - else if (*buffer == '{') - { + else if (*buffer == '{') { // some strange meta data ... while (true) { @@ -135,8 +131,7 @@ bool DXFImporter::GetNextLine() // Get the next token in the file bool DXFImporter::GetNextToken() { - if (bRepeat) - { + if (bRepeat) { bRepeat = false; return true; } @@ -181,26 +176,23 @@ void DXFImporter::InternReadFile( const std::string& pFile, throw new ImportErrorException("DXF: Binary files are not supported at the moment"); // now get all lines of the file - while (GetNextToken()) - { - if (2 == groupCode) - { + while (GetNextToken()) { + + if (2 == groupCode) { + // ENTITIES and BLOCKS sections - skip the whole rest, no need to waste our time with them if (!::strcmp(cursor,"ENTITIES") || !::strcmp(cursor,"BLOCKS")) if (!ParseEntities())break; else bRepeat = true; // other sections - skip them to make sure there will be no name conflicts - else - { - while (GetNextToken()) - { + else { + while (GetNextToken()) { if (!groupCode && !::strcmp(cursor,"ENDSEC"))break; } } } // print comment strings - else if (999 == groupCode) - { + else if (999 == groupCode) { DefaultLogger::get()->info(std::string( cursor )); } else if (!groupCode && !::strcmp(cursor,"EOF")) @@ -208,9 +200,7 @@ void DXFImporter::InternReadFile( const std::string& pFile, } // find out how many valud layers we have - for (std::vector::const_iterator it = mLayers.begin(),end = mLayers.end(); - it != end;++it) - { + for (std::vector::const_iterator it = mLayers.begin(),end = mLayers.end(); it != end;++it) { if (!(*it).vPositions.empty())++pScene->mNumMeshes; } @@ -219,11 +209,10 @@ void DXFImporter::InternReadFile( const std::string& pFile, pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes ]; m = 0; - for (std::vector::const_iterator it = mLayers.begin(),end = mLayers.end(); - it != end;++it) - { - if ((*it).vPositions.empty())continue; - + for (std::vector::const_iterator it = mLayers.begin(),end = mLayers.end();it != end;++it) { + if ((*it).vPositions.empty()) { + continue; + } // generate the output mesh aiMesh* pMesh = pScene->mMeshes[m++] = new aiMesh(); const std::vector& vPositions = (*it).vPositions; @@ -232,11 +221,9 @@ void DXFImporter::InternReadFile( const std::string& pFile, // check whether we need vertex colors here aiColor4D* clrOut = NULL; const aiColor4D* clr = NULL; - for (std::vector::const_iterator it2 = (*it).vColors.begin(), end2 = (*it).vColors.end(); - it2 != end2; ++it2) - { - if ((*it2).r == (*it2).r) // check against qnan - { + for (std::vector::const_iterator it2 = (*it).vColors.begin(), end2 = (*it).vColors.end();it2 != end2; ++it2) { + + if ((*it2).r == (*it2).r) /* qnan? */ { clrOut = pMesh->mColors[0] = new aiColor4D[vPositions.size()]; for (unsigned int i = 0; i < vPositions.size();++i) clrOut[i] = aiColor4D(0.6f,0.6f,0.6f,1.0f); @@ -252,30 +239,25 @@ void DXFImporter::InternReadFile( const std::string& pFile, aiVector3D* vpOut = pMesh->mVertices = new aiVector3D[vPositions.size()]; const aiVector3D* vp = &vPositions[0]; - for (unsigned int i = 0; i < pMesh->mNumFaces;++i) - { + for (unsigned int i = 0; i < pMesh->mNumFaces;++i) { aiFace& face = pMesh->mFaces[i]; // check whether we need four, three or two indices here - if (vp[1] == vp[2]) - { + if (vp[1] == vp[2]) { face.mNumIndices = 2; } - else if (vp[3] == vp[2]) - { + else if (vp[3] == vp[2]) { face.mNumIndices = 3; } else face.mNumIndices = 4; face.mIndices = new unsigned int[face.mNumIndices]; - for (unsigned int a = 0; a < face.mNumIndices;++a) - { + for (unsigned int a = 0; a < face.mNumIndices;++a) { *vpOut++ = vp[a]; - if (clr) - { - if (is_not_qnan( clr[a].r )) + if (clr) { + if (is_not_qnan( clr[a].r )) { *clrOut = clr[a]; - + } ++clrOut; } face.mIndices[a] = pMesh->mNumVertices++; @@ -288,16 +270,14 @@ void DXFImporter::InternReadFile( const std::string& pFile, pScene->mRootNode = new aiNode(); pScene->mRootNode->mName.Set(""); - if (1 == pScene->mNumMeshes) - { + if (1 == pScene->mNumMeshes) { pScene->mRootNode->mMeshes = new unsigned int[ pScene->mRootNode->mNumMeshes = 1 ]; pScene->mRootNode->mMeshes[0] = 0; } else { pScene->mRootNode->mChildren = new aiNode*[ pScene->mRootNode->mNumChildren = pScene->mNumMeshes ]; - for (m = 0; m < pScene->mRootNode->mNumChildren;++m) - { + for (m = 0; m < pScene->mRootNode->mNumChildren;++m) { aiNode* p = pScene->mRootNode->mChildren[m] = new aiNode(); p->mName.length = ::strlen( mLayers[m].name ); ::strcpy(p->mName.data, mLayers[m].name); @@ -333,10 +313,8 @@ void DXFImporter::InternReadFile( const std::string& pFile, // ------------------------------------------------------------------------------------------------ bool DXFImporter::ParseEntities() { - while (GetNextToken()) - { - if (!groupCode) - { + while (GetNextToken()) { + if (!groupCode) { if (!::strcmp(cursor,"3DFACE") || !::strcmp(cursor,"LINE") || !::strcmp(cursor,"3DLINE")) if (!Parse3DFace()) return false; else bRepeat = true; @@ -353,17 +331,13 @@ bool DXFImporter::ParseEntities() // ------------------------------------------------------------------------------------------------ void DXFImporter::SetLayer(LayerInfo*& out) { - for (std::vector::iterator it = mLayers.begin(),end = mLayers.end(); - it != end;++it) - { - if (!::strcmp( (*it).name, cursor )) - { + for (std::vector::iterator it = mLayers.begin(),end = mLayers.end();it != end;++it) { + if (!::strcmp( (*it).name, cursor )) { out = &(*it); break; } } - if (!out) - { + if (!out) { // we don't have this layer yet mLayers.push_back(LayerInfo()); out = &mLayers.back(); @@ -374,8 +348,7 @@ void DXFImporter::SetLayer(LayerInfo*& out) // ------------------------------------------------------------------------------------------------ void DXFImporter::SetDefaultLayer(LayerInfo*& out) { - if (!mDefaultLayer) - { + if (!mDefaultLayer) { mLayers.push_back(LayerInfo()); mDefaultLayer = &mLayers.back(); } @@ -393,27 +366,22 @@ bool DXFImporter::ParsePolyLine() std::vector indices; unsigned int flags = 0; - while (GetNextToken()) - { + while (GetNextToken()) { switch (groupCode) { case 0: { - if (!::strcmp(cursor,"VERTEX")) - { + if (!::strcmp(cursor,"VERTEX")) { aiVector3D v;aiColor4D clr(g_clrInvalid); unsigned int idx[4] = {0xffffffff,0xffffffff,0xffffffff,0xffffffff}; ParsePolyLineVertex(v, clr, idx); - if (0xffffffff == idx[0]) - { + if (0xffffffff == idx[0]) { positions.push_back(v); colors.push_back(clr); } - else - { + else { // check whether we have a fourth coordinate - if (0xffffffff == idx[3]) - { + if (0xffffffff == idx[3]) { idx[3] = idx[2]; } @@ -423,8 +391,7 @@ bool DXFImporter::ParsePolyLine() } bRepeat = true; } - else if (!::strcmp(cursor,"ENDSEQ")) - { + else if (!::strcmp(cursor,"ENDSEQ")) { ret = true; } break; @@ -433,8 +400,7 @@ bool DXFImporter::ParsePolyLine() // flags --- important that we know whether it is a polyface mesh case 70: { - if (!flags) - { + if (!flags) { flags = strtol10(cursor); } break; @@ -462,32 +428,29 @@ bool DXFImporter::ParsePolyLine() } } } - if (!(flags & 64)) - { + if (!(flags & 64)) { DefaultLogger::get()->warn("DXF: Only polyface meshes are currently supported"); return ret; } - if (positions.size() < 3 || indices.size() < 3) - { + if (positions.size() < 3 || indices.size() < 3) { DefaultLogger::get()->warn("DXF: Unable to parse POLYLINE element - not enough vertices"); return ret; } // use a default layer if necessary - if (!out)SetDefaultLayer(out); + if (!out) { + SetDefaultLayer(out); + } flags = (unsigned int)(out->vPositions.size()+indices.size()); out->vPositions.reserve(flags); out->vColors.reserve(flags); // generate unique vertices - for (std::vector::const_iterator it = indices.begin(), end = indices.end(); - it != end; ++it) - { + for (std::vector::const_iterator it = indices.begin(), end = indices.end();it != end; ++it) { unsigned int idx = *it; - if (idx > positions.size() || !idx) - { + if (idx > positions.size() || !idx) { DefaultLogger::get()->error("DXF: Polyface mesh index os out of range"); idx = (unsigned int) positions.size(); } @@ -502,11 +465,11 @@ bool DXFImporter::ParsePolyLine() bool DXFImporter::ParsePolyLineVertex(aiVector3D& out,aiColor4D& clr, unsigned int* outIdx) { bool ret = false; - while (GetNextToken()) - { + while (GetNextToken()) { switch (groupCode) { - case 0: ret = true;break; + case 0: ret = true; + break; // todo - handle the correct layer for the vertex // At the moment it is assumed that all vertices of @@ -530,7 +493,9 @@ bool DXFImporter::ParsePolyLineVertex(aiVector3D& out,aiColor4D& clr, unsigned i // color case 62: clr = g_aclrDxfIndexColors[strtol10(cursor) % AI_DXF_NUM_INDEX_COLORS]; break; }; - if (ret)break; + if (ret) { + break; + } } return ret; } @@ -547,15 +512,12 @@ bool DXFImporter::Parse3DFace() // this is also used for for parsing line entities bool bThird = false; - while (GetNextToken()) - { - switch (groupCode) - { + while (GetNextToken()) { + switch (groupCode) { case 0: ret = true;break; // 8 specifies the layer - case 8: - { + case 8: { SetLayer(out); break; } @@ -611,8 +573,9 @@ bool DXFImporter::Parse3DFace() if (!bThird)vip[2] = vip[1]; // use a default layer if necessary - if (!out)SetDefaultLayer(out); - + if (!out) { + SetDefaultLayer(out); + } // add the faces to the face list for this layer out->vPositions.push_back(vip[0]); out->vPositions.push_back(vip[1]); diff --git a/code/IRRLoader.cpp b/code/IRRLoader.cpp index 8cccc04ac..f0fa8a87a 100644 --- a/code/IRRLoader.cpp +++ b/code/IRRLoader.cpp @@ -70,16 +70,12 @@ using namespace boost::math; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer IRRImporter::IRRImporter() -{ - // nothing to do here -} +{} // ------------------------------------------------------------------------------------------------ // Destructor, private as well IRRImporter::~IRRImporter() -{ - // nothing to do here -} +{} // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. @@ -174,17 +170,14 @@ aiMesh* IRRImporter::BuildSingleQuadMesh(const SkyboxVertex& v1, *vec++ = v2.uv; *vec++ = v3.uv; *vec = v4.uv; - return out; } // ------------------------------------------------------------------------------------------------ void IRRImporter::BuildSkybox(std::vector& meshes, std::vector materials) { - // Update the material of the skybox - replace the name - // and disable shading for skyboxes. - for (unsigned int i = 0; i < 6;++i) - { + // Update the material of the skybox - replace the name and disable shading for skyboxes. + for (unsigned int i = 0; i < 6;++i) { MaterialHelper* out = ( MaterialHelper* ) (*(materials.end()-(6-i))); aiString s; @@ -256,8 +249,7 @@ void IRRImporter::CopyMaterial(std::vector& materials, unsigned int& defMatIdx, aiMesh* mesh) { - if (inmaterials.empty()) - { + if (inmaterials.empty()) { // Do we have a default material? If not we need to create one if (0xffffffff == defMatIdx) { @@ -274,8 +266,7 @@ void IRRImporter::CopyMaterial(std::vector& materials, mesh->mMaterialIndex = defMatIdx; return; } - else if (inmaterials.size() > 1) - { + else if (inmaterials.size() > 1) { DefaultLogger::get()->info("IRR: Skipping additional materials"); } @@ -307,24 +298,20 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vectoranimators.empty())return; -// const aiMatrix4x4& transform = real->mTransformation; - + if (root->animators.empty()) { + return; + } unsigned int total = 0; - for (std::list::iterator it = root->animators.begin(); - it != root->animators.end(); ++it) - { - if ((*it).type == Animator::UNKNOWN || (*it).type == Animator::OTHER) - { + for (std::list::iterator it = root->animators.begin();it != root->animators.end(); ++it) { + if ((*it).type == Animator::UNKNOWN || (*it).type == Animator::OTHER) { DefaultLogger::get()->warn("IRR: Skipping unknown or unsupported animator"); continue; } ++total; } if (!total)return; - else if (1 == total) - { - DefaultLogger::get()->warn("IRR: Generating dummy nodes to simulate multiple animators"); + else if (1 == total) { + DefaultLogger::get()->warn("IRR: Adding dummy nodes to simulate multiple animators"); } // NOTE: 1 tick == i millisecond @@ -338,8 +325,7 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vectormNodeName.length = ::sprintf(anim->mNodeName.data, @@ -367,8 +353,7 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vectormNodeName.Set(root->name); ++cur; - switch (in.type) - { + switch (in.type) { case Animator::ROTATION: { // ----------------------------------------------------- @@ -463,8 +448,7 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vectormNumPositionKeys;++i) - { + for (unsigned int i = 0; i < anim->mNumPositionKeys;++i) { aiVectorKey& key = anim->mPositionKeys[i]; key.mTime = i * tdelta; @@ -502,8 +485,7 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vectormNumPositionKeys;++i) - { + for (unsigned int i = 0; i < anim->mNumPositionKeys;++i) { aiVectorKey& key = anim->mPositionKeys[i]; key.mTime = i * tdelta; key.mValue = in.circleCenter + diff * float(timeFactor * key.mTime); @@ -516,16 +498,14 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vectormPostState = anim->mPreState = aiAnimBehaviour_REPEAT; const int size = (int)in.splineKeys.size(); - if (!size) - { + if (!size) { // We have no point in the spline. That's bad. Really bad. DefaultLogger::get()->warn("IRR: Spline animators with no points defined"); delete anim;anim = NULL; break; } - else if (size == 1) - { + else if (size == 1) { // We have just one point in the spline so we don't need the full calculation anim->mNumPositionKeys = 1; anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys]; @@ -576,8 +556,7 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vectormNumProperties;++i) { aiMaterialProperty* prop = mat->mProperties[i]; - if (!::strcmp( prop->mKey.data, "$tex.file")) - { + if (!::strcmp( prop->mKey.data, "$tex.file")) { // Setup the mapping key aiMaterialProperty* m = new aiMaterialProperty(); m->mKey.Set("$tex.mapping"); @@ -615,9 +593,7 @@ void SetupMapping (MaterialHelper* mat, aiTextureMapping mode, const aiVector3D& p.push_back(m); // Setup the mapping axis - if (mode == aiTextureMapping_CYLINDER || mode == aiTextureMapping_PLANE || - mode == aiTextureMapping_SPHERE) - { + if (mode == aiTextureMapping_CYLINDER || mode == aiTextureMapping_PLANE || mode == aiTextureMapping_SPHERE) { m = new aiMaterialProperty(); m->mKey.Set("$tex.mapaxis"); m->mIndex = prop->mIndex; @@ -674,63 +650,24 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene, // the list of all scenes to be attached to the // graph we're currently building aiScene* scene = batch.GetImport(root->id); - if (!scene) - { - DefaultLogger::get()->error("IRR: Unable to load external file: " - + root->meshPath); + if (!scene) { + DefaultLogger::get()->error("IRR: Unable to load external file: " + root->meshPath); break; } attach.push_back(AttachmentInfo(scene,rootOut)); -#if 0 /* currently unused */ - meshTrafoAssign = 1; - - // If the root node of the scene is animated - and *this* node - // is animated, too, we need to insert a dummy node into the - // hierarchy in order to avoid interferences with animations - for (unsigned int i = 0; i < scene->mNumAnimations;++i) - { - aiAnimation* anim = scene->mAnimations[i]; - for (unsigned int a = 0; a < anim->mNumChannels;++a) { - if (scene->mRootNode->mName == anim->mChannels[a]->mNodeName) { - if (root->animators.empty()) { - meshTrafoAssign = 2; - } - else { - meshTrafoAssign = 3; - aiNode* dummy = new aiNode(); - dummy->mName.Set("$CSpaceSeam$"); - dummy->mNumChildren = 1; - dummy->mChildren = new aiNode*[1]; - dummy->mChildren[0] = scene->mRootNode; - - scene->mRootNode->mParent = dummy; - scene->mRootNode = dummy; - scene->mRootNode->mTransformation = AI_TO_IRR_MATRIX; - } - break; - } - } - } -#endif - // if (1 == meshTrafoAssign) - // scene->mRootNode->mTransformation = AI_TO_IRR_MATRIX * scene->mRootNode->mTransformation; - - // Now combine the material we've loaded for this mesh // with the real materials we got from the file. As we // don't execute any pp-steps on the file, the numbers // should be equal. If they are not, we can impossibly // do this ... - if (root->materials.size() != (unsigned int)scene->mNumMaterials) - { + if (root->materials.size() != (unsigned int)scene->mNumMaterials) { DefaultLogger::get()->warn("IRR: Failed to match imported materials " "with the materials found in the IRR scene file"); break; } - for (unsigned int i = 0; i < scene->mNumMaterials;++i) - { + for (unsigned int i = 0; i < scene->mNumMaterials;++i) { // Delete the old material, we don't need it anymore delete scene->mMaterials[i]; @@ -741,8 +678,7 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene, // NOTE: Each mesh should have exactly one material assigned, // but we do it in a separate loop if this behaviour changes // in future. - for (unsigned int i = 0; i < scene->mNumMeshes;++i) - { + for (unsigned int i = 0; i < scene->mNumMeshes;++i) { // Process material flags aiMesh* mesh = scene->mMeshes[i]; @@ -751,25 +687,21 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene, // and check whether they have a common alpha value. This is quite // often the case so we can simply extract it to a shared oacity // value. - std::pair& src = root->materials[ - mesh->mMaterialIndex]; - + std::pair& src = root->materials[mesh->mMaterialIndex]; MaterialHelper* mat = (MaterialHelper*)src.first; + if (mesh->HasVertexColors(0) && src.second & AI_IRRMESH_MAT_trans_vertex_alpha) { bool bdo = true; - for (unsigned int a = 1; a < mesh->mNumVertices;++a) - { - if (mesh->mColors[0][a].a != mesh->mColors[0][a-1].a) - { + for (unsigned int a = 1; a < mesh->mNumVertices;++a) { + + if (mesh->mColors[0][a].a != mesh->mColors[0][a-1].a) { bdo = false; break; } } - if (bdo) - { - DefaultLogger::get()->info("IRR: Replacing mesh vertex " - "alpha with common opacity"); + if (bdo) { + DefaultLogger::get()->info("IRR: Replacing mesh vertex alpha with common opacity"); for (unsigned int a = 0; a < mesh->mNumVertices;++a) mesh->mColors[0][a].a = 1.f; @@ -782,8 +714,8 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene, // (either lightmap, normalmap, 2layered material) we need to // setup the correct UV index for it. The texture can either // be diffuse (lightmap & 2layer) or a normal map (normal & parallax) - if (mesh->HasTextureCoords(1)) - { + if (mesh->HasTextureCoords(1)) { + int idx = 1; if (src.second & (AI_IRRMESH_MAT_solid_2layer | AI_IRRMESH_MAT_lightmap)) { mat->AddProperty(&idx,1,AI_MATKEY_UVWSRC_DIFFUSE(0)); @@ -852,11 +784,8 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene, case Node::SKYBOX: { // A skybox is defined by six materials - if (root->materials.size() < 6) - { - DefaultLogger::get()->error("IRR: There should be six materials " - "for a skybox"); - + if (root->materials.size() < 6) { + DefaultLogger::get()->error("IRR: There should be six materials for a skybox"); break; } @@ -888,8 +817,8 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene, // Check whether we added a mesh (or more than one ...). In this case // we'll also need to attach it to the node - if (oldMeshSize != (unsigned int) meshes.size()) - { + if (oldMeshSize != (unsigned int) meshes.size()) { + rootOut->mNumMeshes = (unsigned int)meshes.size() - oldMeshSize; rootOut->mMeshes = new unsigned int[rootOut->mNumMeshes]; @@ -904,7 +833,7 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene, // Now compute the final local transformation matrix of the // node from the given translation, rotation and scaling values. // (the rotation is given in Euler angles, XYZ order) - std::swap((float&)root->rotation.z,(float&)root->rotation.y); + //std::swap((float&)root->rotation.z,(float&)root->rotation.y); rootOut->mTransformation.FromEulerAnglesXYZ(AI_DEG_TO_RAD(root->rotation) ); // apply scaling @@ -912,20 +841,17 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene, mat.a1 *= root->scaling.x; mat.b1 *= root->scaling.x; mat.c1 *= root->scaling.x; - mat.a2 *= root->scaling.z; - mat.b2 *= root->scaling.z; - mat.c2 *= root->scaling.z; - mat.a3 *= root->scaling.y; - mat.b3 *= root->scaling.y; - mat.c3 *= root->scaling.y; + mat.a2 *= root->scaling.y; + mat.b2 *= root->scaling.y; + mat.c2 *= root->scaling.y; + mat.a3 *= root->scaling.z; + mat.b3 *= root->scaling.z; + mat.c3 *= root->scaling.z; // apply translation mat.a4 += root->position.x; - mat.b4 += root->position.z; - mat.c4 += root->position.y; - - //if (meshTrafoAssign == 2) - // mat *= AI_TO_IRR_MATRIX; + mat.b4 += root->position.y; + mat.c4 += root->position.z; // now compute animations for the node ComputeAnimations(root,rootOut, anims); @@ -933,11 +859,11 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene, // Add all children recursively. First allocate enough storage // for them, then call us again rootOut->mNumChildren = (unsigned int)root->children.size(); - if (rootOut->mNumChildren) - { + if (rootOut->mNumChildren) { + rootOut->mChildren = new aiNode*[rootOut->mNumChildren]; - for (unsigned int i = 0; i < rootOut->mNumChildren;++i) - { + for (unsigned int i = 0; i < rootOut->mNumChildren;++i) { + aiNode* node = rootOut->mChildren[i] = new aiNode(); node->mParent = rootOut; GenerateGraph(root->children[i],node,scene,batch,meshes, @@ -989,14 +915,11 @@ void IRRImporter::InternReadFile( const std::string& pFile, unsigned int guessedAnimCnt = 0, guessedMeshCnt = 0, guessedMatCnt = 0; // Parse the XML file - while (reader->read()) - { - switch (reader->getNodeType()) - { + while (reader->read()) { + switch (reader->getNodeType()) { case EXN_ELEMENT: - if (!ASSIMP_stricmp(reader->getNodeName(),"node")) - { + if (!ASSIMP_stricmp(reader->getNodeName(),"node")) { // *********************************************************************** /* What we're going to do with the node depends * on its type: @@ -1019,24 +942,20 @@ void IRRImporter::InternReadFile( const std::string& pFile, // *********************************************************************** const char* sz = reader->getAttributeValueSafe("type"); Node* nd; - if (!ASSIMP_stricmp(sz,"mesh") || !ASSIMP_stricmp(sz,"octTree")) - { + if (!ASSIMP_stricmp(sz,"mesh") || !ASSIMP_stricmp(sz,"octTree")) { // OctTree's and meshes are treated equally nd = new Node(Node::MESH); } - else if (!ASSIMP_stricmp(sz,"cube")) - { + else if (!ASSIMP_stricmp(sz,"cube")) { nd = new Node(Node::CUBE); ++guessedMeshCnt; // meshes.push_back(StandardShapes::MakeMesh(&StandardShapes::MakeHexahedron)); } - else if (!ASSIMP_stricmp(sz,"skybox")) - { + else if (!ASSIMP_stricmp(sz,"skybox")) { nd = new Node(Node::SKYBOX); guessedMeshCnt += 6; } - else if (!ASSIMP_stricmp(sz,"camera")) - { + else if (!ASSIMP_stricmp(sz,"camera")) { nd = new Node(Node::CAMERA); // Setup a temporary name for the camera @@ -1044,8 +963,7 @@ void IRRImporter::InternReadFile( const std::string& pFile, cam->mName.Set( nd->name ); cameras.push_back(cam); } - else if (!ASSIMP_stricmp(sz,"light")) - { + else if (!ASSIMP_stricmp(sz,"light")) { nd = new Node(Node::LIGHT); // Setup a temporary name for the light @@ -1053,31 +971,25 @@ void IRRImporter::InternReadFile( const std::string& pFile, cam->mName.Set( nd->name ); lights.push_back(cam); } - else if (!ASSIMP_stricmp(sz,"sphere")) - { + else if (!ASSIMP_stricmp(sz,"sphere")) { nd = new Node(Node::SPHERE); ++guessedMeshCnt; } - else if (!ASSIMP_stricmp(sz,"animatedMesh")) - { + else if (!ASSIMP_stricmp(sz,"animatedMesh")) { nd = new Node(Node::ANIMMESH); } - else if (!ASSIMP_stricmp(sz,"empty")) - { + else if (!ASSIMP_stricmp(sz,"empty")) { nd = new Node(Node::DUMMY); } - else if (!ASSIMP_stricmp(sz,"terrain")) - { + else if (!ASSIMP_stricmp(sz,"terrain")) { nd = new Node(Node::TERRAIN); } - else if (!ASSIMP_stricmp(sz,"billBoard")) - { + else if (!ASSIMP_stricmp(sz,"billBoard")) { // We don't support billboards, so ignore them DefaultLogger::get()->error("IRR: Billboards are not supported by Assimp"); nd = new Node(Node::DUMMY); } - else - { + else { DefaultLogger::get()->warn("IRR: Found unknown node: " + std::string(sz)); /* We skip the contents of nodes we don't know. @@ -1093,21 +1005,17 @@ void IRRImporter::InternReadFile( const std::string& pFile, nd->parent = curParent; curParent->children.push_back(nd); } - else if (!ASSIMP_stricmp(reader->getNodeName(),"materials")) - { + else if (!ASSIMP_stricmp(reader->getNodeName(),"materials")) { inMaterials = true; } - else if (!ASSIMP_stricmp(reader->getNodeName(),"animators")) - { + else if (!ASSIMP_stricmp(reader->getNodeName(),"animators")) { inAnimator = true; } - else if (!ASSIMP_stricmp(reader->getNodeName(),"attributes")) - { + else if (!ASSIMP_stricmp(reader->getNodeName(),"attributes")) { /* We should have a valid node here * FIX: no ... the scene root node is also contained in an attributes block */ - if (!curNode) - { + if (!curNode) { #if 0 DefaultLogger::get()->error("IRR: Encountered element, but " "there is no node active"); @@ -1118,8 +1026,7 @@ void IRRImporter::InternReadFile( const std::string& pFile, Animator* curAnim = NULL; // Materials can occur for nearly any type of node - if (inMaterials && curNode->type != Node::DUMMY) - { + if (inMaterials && curNode->type != Node::DUMMY) { /* This is a material description - parse it! */ curNode->materials.push_back(std::pair< aiMaterial*, unsigned int > () ); @@ -1130,8 +1037,7 @@ void IRRImporter::InternReadFile( const std::string& pFile, ++guessedMatCnt; continue; } - else if (inAnimator) - { + else if (inAnimator) { /* This is an animation path - add a new animator * to the list. */ @@ -1144,28 +1050,21 @@ void IRRImporter::InternReadFile( const std::string& pFile, /* Parse all elements in the attributes block * and process them. */ - while (reader->read()) - { - if (reader->getNodeType() == EXN_ELEMENT) - { - if (!ASSIMP_stricmp(reader->getNodeName(),"vector3d")) - { + while (reader->read()) { + if (reader->getNodeType() == EXN_ELEMENT) { + if (!ASSIMP_stricmp(reader->getNodeName(),"vector3d")) { VectorProperty prop; ReadVectorProperty(prop); - if (inAnimator) - { - if (curAnim->type == Animator::ROTATION && prop.name == "Rotation") - { + if (inAnimator) { + if (curAnim->type == Animator::ROTATION && prop.name == "Rotation") { // We store the rotation euler angles in 'direction' curAnim->direction = prop.value; } - else if (curAnim->type == Animator::FOLLOW_SPLINE) - { + else if (curAnim->type == Animator::FOLLOW_SPLINE) { // Check whether the vector follows the PointN naming scheme, // here N is the ONE-based index of the point - if (prop.name.length() >= 6 && prop.name.substr(0,5) == "Point") - { + if (prop.name.length() >= 6 && prop.name.substr(0,5) == "Point") { // Add a new key to the list curAnim->splineKeys.push_back(aiVectorKey()); aiVectorKey& key = curAnim->splineKeys.back(); @@ -1175,203 +1074,158 @@ void IRRImporter::InternReadFile( const std::string& pFile, key.mTime = strtol10(&prop.name[5]); } } - else if (curAnim->type == Animator::FLY_CIRCLE) - { - if (prop.name == "Center") - { + else if (curAnim->type == Animator::FLY_CIRCLE) { + if (prop.name == "Center") { curAnim->circleCenter = prop.value; } - else if (prop.name == "Direction") - { + else if (prop.name == "Direction") { curAnim->direction = prop.value; - // From Irrlicht source - a workaround for backward - // compatibility with Irrlicht 1.1 - if (curAnim->direction == aiVector3D()) - { + // From Irrlicht's source - a workaround for backward compatibility with Irrlicht 1.1 + if (curAnim->direction == aiVector3D()) { curAnim->direction = aiVector3D(0.f,1.f,0.f); } else curAnim->direction.Normalize(); } } - else if (curAnim->type == Animator::FLY_STRAIGHT) - { - if (prop.name == "Start") - { + else if (curAnim->type == Animator::FLY_STRAIGHT) { + if (prop.name == "Start") { // We reuse the field here curAnim->circleCenter = prop.value; } - else if (prop.name == "End") - { + else if (prop.name == "End") { // We reuse the field here curAnim->direction = prop.value; } } } - else - { - if (prop.name == "Position") - { + else { + if (prop.name == "Position") { curNode->position = prop.value; } - else if (prop.name == "Rotation") - { + else if (prop.name == "Rotation") { curNode->rotation = prop.value; } - else if (prop.name == "Scale") - { + else if (prop.name == "Scale") { curNode->scaling = prop.value; } else if (Node::CAMERA == curNode->type) { aiCamera* cam = cameras.back(); - if (prop.name == "Target") - { + if (prop.name == "Target") { cam->mLookAt = prop.value; } - else if (prop.name == "UpVector") - { + else if (prop.name == "UpVector") { cam->mUp = prop.value; } } } } - else if (!ASSIMP_stricmp(reader->getNodeName(),"bool")) - { + else if (!ASSIMP_stricmp(reader->getNodeName(),"bool")) { BoolProperty prop; ReadBoolProperty(prop); - if (inAnimator && curAnim->type == Animator::FLY_CIRCLE && prop.name == "Loop") - { + if (inAnimator && curAnim->type == Animator::FLY_CIRCLE && prop.name == "Loop") { curAnim->loop = prop.value; } } - else if (!ASSIMP_stricmp(reader->getNodeName(),"float")) - { + else if (!ASSIMP_stricmp(reader->getNodeName(),"float")) { FloatProperty prop; ReadFloatProperty(prop); - if (inAnimator) - { + if (inAnimator) { // The speed property exists for several animators - if (prop.name == "Speed") - { + if (prop.name == "Speed") { curAnim->speed = prop.value; } - else if (curAnim->type == Animator::FLY_CIRCLE && prop.name == "Radius") - { + else if (curAnim->type == Animator::FLY_CIRCLE && prop.name == "Radius") { curAnim->circleRadius = prop.value; } - else if (curAnim->type == Animator::FOLLOW_SPLINE && prop.name == "Tightness") - { + else if (curAnim->type == Animator::FOLLOW_SPLINE && prop.name == "Tightness") { curAnim->tightness = prop.value; } } - else - { - if (prop.name == "FramesPerSecond" && - Node::ANIMMESH == curNode->type) - { + else { + if (prop.name == "FramesPerSecond" && Node::ANIMMESH == curNode->type) { curNode->framesPerSecond = prop.value; } - else if (Node::CAMERA == curNode->type) - { + else if (Node::CAMERA == curNode->type) { /* This is the vertical, not the horizontal FOV. * We need to compute the right FOV from the * screen aspect which we don't know yet. */ - if (prop.name == "Fovy") - { + if (prop.name == "Fovy") { cameras.back()->mHorizontalFOV = prop.value; } - else if (prop.name == "Aspect") - { + else if (prop.name == "Aspect") { cameras.back()->mAspect = prop.value; } - else if (prop.name == "ZNear") - { + else if (prop.name == "ZNear") { cameras.back()->mClipPlaneNear = prop.value; } - else if (prop.name == "ZFar") - { + else if (prop.name == "ZFar") { cameras.back()->mClipPlaneFar = prop.value; } } - else if (Node::LIGHT == curNode->type) - { + else if (Node::LIGHT == curNode->type) { /* Additional light information */ - if (prop.name == "Attenuation") - { + if (prop.name == "Attenuation") { lights.back()->mAttenuationLinear = prop.value; } - else if (prop.name == "OuterCone") - { + else if (prop.name == "OuterCone") { lights.back()->mAngleOuterCone = AI_DEG_TO_RAD( prop.value ); } - else if (prop.name == "InnerCone") - { + else if (prop.name == "InnerCone") { lights.back()->mAngleInnerCone = AI_DEG_TO_RAD( prop.value ); } } // radius of the sphere to be generated - // or alternatively, size of the cube - else if (Node::SPHERE == curNode->type && prop.name == "Radius" || - Node::CUBE == curNode->type && prop.name == "Size" ) - { - curNode->sphereRadius = prop.value; + else if (Node::SPHERE == curNode->type && prop.name == "Radius" + || Node::CUBE == curNode->type && prop.name == "Size" ) { + + curNode->sphereRadius = prop.value; } } } - else if (!ASSIMP_stricmp(reader->getNodeName(),"int")) - { + else if (!ASSIMP_stricmp(reader->getNodeName(),"int")) { IntProperty prop; ReadIntProperty(prop); - if (inAnimator) - { - if (curAnim->type == Animator::FLY_STRAIGHT && prop.name == "TimeForWay") - { + if (inAnimator) { + if (curAnim->type == Animator::FLY_STRAIGHT && prop.name == "TimeForWay") { curAnim->timeForWay = prop.value; } } - else - { + else { // sphere polgon numbers in each direction - if (Node::SPHERE == curNode->type) - { - if (prop.name == "PolyCountX") - { + if (Node::SPHERE == curNode->type) { + + if (prop.name == "PolyCountX") { curNode->spherePolyCountX = prop.value; } - else if (prop.name == "PolyCountY") - { + else if (prop.name == "PolyCountY") { curNode->spherePolyCountY = prop.value; } } } } - else if (!ASSIMP_stricmp(reader->getNodeName(),"string") || - !ASSIMP_stricmp(reader->getNodeName(),"enum")) - { + else if (!ASSIMP_stricmp(reader->getNodeName(),"string") ||!ASSIMP_stricmp(reader->getNodeName(),"enum")) { StringProperty prop; ReadStringProperty(prop); - if (prop.value.length()) - { - if (prop.name == "Name") - { + if (prop.value.length()) { + if (prop.name == "Name") { curNode->name = prop.value; /* If we're either a camera or a light source * we need to update the name in the aiLight/ * aiCamera structure, too. */ - if (Node::CAMERA == curNode->type) - { + if (Node::CAMERA == curNode->type) { cameras.back()->mName.Set(prop.value); } - else if (Node::LIGHT == curNode->type) - { + else if (Node::LIGHT == curNode->type) { lights.back()->mName.Set(prop.value); } } @@ -1404,10 +1258,9 @@ void IRRImporter::InternReadFile( const std::string& pFile, unsigned int pp = 0; BatchLoader::PropertyMap map; - /* If the mesh is a static one remove all animations + /* If the mesh is a static one remove all animations from the impor data */ - if (Node::ANIMMESH != curNode->type) - { + if (Node::ANIMMESH != curNode->type) { pp |= aiProcess_RemoveComponent; SetGenericProperty(map.ints,AI_CONFIG_PP_RVC_FLAGS, aiComponent_ANIMATIONS | aiComponent_BONEWEIGHTS); @@ -1419,51 +1272,33 @@ void IRRImporter::InternReadFile( const std::string& pFile, * file referencing each other *could* cause the system to * recurse forever. */ - std::string::size_type pos = prop.value.find_last_of('.'); - // no file extension - can't read, so we don't need to try it - if( pos == std::string::npos) - { - DefaultLogger::get()->error("IRR: Can't load files without a file extension"); + const std::string extension = GetExtension(prop.value); + if ("irr" == extension) { + DefaultLogger::get()->error("IRR: Can't load another IRR file recursively"); } else { - std::string extension = prop.value.substr( pos); - for (std::string::iterator i = extension.begin(); i != extension.end();++i) - *i = ::tolower(*i); - - if (".irr" == prop.value) - { - DefaultLogger::get()->error("IRR: Can't load another IRR file recursively"); - } - else - { - curNode->id = batch.AddLoadRequest(prop.value,pp,&map); - curNode->meshPath = prop.value; - } + curNode->id = batch.AddLoadRequest(prop.value,pp,&map); + curNode->meshPath = prop.value; } } else if (inAnimator && prop.name == "Type") { // type of the animator - if (prop.value == "rotation") - { + if (prop.value == "rotation") { curAnim->type = Animator::ROTATION; } - else if (prop.value == "flyCircle") - { + else if (prop.value == "flyCircle") { curAnim->type = Animator::FLY_CIRCLE; } - else if (prop.value == "flyStraight") - { + else if (prop.value == "flyStraight") { curAnim->type = Animator::FLY_CIRCLE; } - else if (prop.value == "followSpline") - { + else if (prop.value == "followSpline") { curAnim->type = Animator::FOLLOW_SPLINE; } - else - { + else { DefaultLogger::get()->warn("IRR: Ignoring unknown animator: " + prop.value); @@ -1473,9 +1308,7 @@ void IRRImporter::InternReadFile( const std::string& pFile, } } } - else if (reader->getNodeType() == EXN_ELEMENT_END && - !ASSIMP_stricmp(reader->getNodeName(),"attributes")) - { + else if (reader->getNodeType() == EXN_ELEMENT_END && !ASSIMP_stricmp(reader->getNodeName(),"attributes")) { break; } } @@ -1485,14 +1318,11 @@ void IRRImporter::InternReadFile( const std::string& pFile, case EXN_ELEMENT_END: // If we reached the end of a node, we need to continue processing its parent - if (!ASSIMP_stricmp(reader->getNodeName(),"node")) - { - if (!curNode) - { + if (!ASSIMP_stricmp(reader->getNodeName(),"node")) { + if (!curNode) { // currently is no node set. We need to go // back in the node hierarchy - if (!curParent) - { + if (!curParent) { curParent = root; DefaultLogger::get()->error("IRR: Too many closing elements"); } @@ -1501,12 +1331,10 @@ void IRRImporter::InternReadFile( const std::string& pFile, else curNode = NULL; } // clear all flags - else if (!ASSIMP_stricmp(reader->getNodeName(),"materials")) - { + else if (!ASSIMP_stricmp(reader->getNodeName(),"materials")) { inMaterials = false; } - else if (!ASSIMP_stricmp(reader->getNodeName(),"animators")) - { + else if (!ASSIMP_stricmp(reader->getNodeName(),"animators")) { inAnimator = false; } break; @@ -1519,11 +1347,11 @@ void IRRImporter::InternReadFile( const std::string& pFile, /* Now iterate through all cameras and compute their final (horizontal) FOV */ - for (std::vector::iterator it = cameras.begin(), end = cameras.end(); - it != end; ++it) { + for (std::vector::iterator it = cameras.begin(), end = cameras.end();it != end; ++it) { aiCamera* cam = *it; - if (cam->mAspect) // screen aspect could be missing - { + + // screen aspect could be missing + if (cam->mAspect) { cam->mHorizontalFOV *= cam->mAspect; } else DefaultLogger::get()->warn("IRR: Camera aspect is not given, can't compute horizontal FOV"); @@ -1539,8 +1367,7 @@ void IRRImporter::InternReadFile( const std::string& pFile, /* Copy the cameras to the output array */ - if (!cameras.empty()) - { + if (!cameras.empty()) { tempScene->mNumCameras = (unsigned int)cameras.size(); tempScene->mCameras = new aiCamera*[tempScene->mNumCameras]; ::memcpy(tempScene->mCameras,&cameras[0],sizeof(void*)*tempScene->mNumCameras); @@ -1548,8 +1375,7 @@ void IRRImporter::InternReadFile( const std::string& pFile, /* Copy the light sources to the output array */ - if (!lights.empty()) - { + if (!lights.empty()) { tempScene->mNumLights = (unsigned int)lights.size(); tempScene->mLights = new aiLight*[tempScene->mNumLights]; ::memcpy(tempScene->mLights,&lights[0],sizeof(void*)*tempScene->mNumLights); @@ -1593,8 +1419,7 @@ void IRRImporter::InternReadFile( const std::string& pFile, an->mChannels = new aiNodeAnim*[an->mNumChannels]; ::memcpy(an->mChannels, & anims [0], sizeof(void*)*an->mNumChannels); } - if (!meshes.empty()) - { + if (!meshes.empty()) { // copy all meshes to the temporary scene tempScene->mNumMeshes = (unsigned int)meshes.size(); tempScene->mMeshes = new aiMesh*[tempScene->mNumMeshes]; @@ -1604,8 +1429,7 @@ void IRRImporter::InternReadFile( const std::string& pFile, /* Copy all materials to the output array */ - if (!materials.empty()) - { + if (!materials.empty()) { tempScene->mNumMaterials = (unsigned int)materials.size(); tempScene->mMaterials = new aiMaterial*[tempScene->mNumMaterials]; ::memcpy(tempScene->mMaterials,&materials[0],sizeof(void*)* @@ -1624,8 +1448,7 @@ void IRRImporter::InternReadFile( const std::string& pFile, * scene flag. This is necessary if we failed to load all * models from external files */ - if (!pScene->mNumMeshes || !pScene->mNumMaterials) - { + if (!pScene->mNumMeshes || !pScene->mNumMaterials) { DefaultLogger::get()->warn("IRR: No meshes loaded, setting AI_SCENE_FLAGS_INCOMPLETE"); pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; } diff --git a/code/IRRMeshLoader.cpp b/code/IRRMeshLoader.cpp index 8c1051172..4bf77597a 100644 --- a/code/IRRMeshLoader.cpp +++ b/code/IRRMeshLoader.cpp @@ -54,16 +54,12 @@ using namespace irr::io; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer IRRMeshImporter::IRRMeshImporter() -{ - // nothing to do here -} +{} // ------------------------------------------------------------------------------------------------ // Destructor, private as well IRRMeshImporter::~IRRMeshImporter() -{ - // nothing to do here -} +{} // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. @@ -134,23 +130,18 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile, bool useColors = false; // Parse the XML file - while (reader->read()) - { - switch (reader->getNodeType()) - { + while (reader->read()) { + switch (reader->getNodeType()) { case EXN_ELEMENT: - if (!ASSIMP_stricmp(reader->getNodeName(),"buffer") && (curMat || curMesh)) - { + if (!ASSIMP_stricmp(reader->getNodeName(),"buffer") && (curMat || curMesh)) { // end of previous buffer. A material and a mesh should be there - if ( !curMat || !curMesh) - { + if ( !curMat || !curMesh) { DefaultLogger::get()->error("IRRMESH: A buffer must contain a mesh and a material"); delete curMat; delete curMesh; } - else - { + else { materials.push_back(curMat); meshes.push_back(curMesh); } @@ -167,10 +158,8 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile, } - if (!ASSIMP_stricmp(reader->getNodeName(),"material")) - { - if (curMat) - { + if (!ASSIMP_stricmp(reader->getNodeName(),"material")) { + if (curMat) { DefaultLogger::get()->warn("IRRMESH: Only one material description per buffer, please"); delete curMat;curMat = NULL; } @@ -180,11 +169,8 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile, { int num = reader->getAttributeValueAsInt("vertexCount"); - if (!num) - { - // This is possible ... remove the mesh from the list - // and skip further reading - + if (!num) { + // This is possible ... remove the mesh from the list and skip further reading DefaultLogger::get()->warn("IRRMESH: Found mesh with zero vertices"); delete curMat;curMat = NULL; @@ -201,13 +187,11 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile, // Determine the file format const char* t = reader->getAttributeValueSafe("type"); - if (!ASSIMP_stricmp("2tcoords", t)) - { + if (!ASSIMP_stricmp("2tcoords", t)) { curUV2s.reserve (num); vertexFormat = 1; - if (curMatFlags & AI_IRRMESH_EXTRA_2ND_TEXTURE) - { + if (curMatFlags & AI_IRRMESH_EXTRA_2ND_TEXTURE) { // ********************************************************* // We have a second texture! So use this UV channel // for it. The 2nd texture can be either a normal @@ -228,24 +212,20 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile, } } } - else if (!ASSIMP_stricmp("tangents", t)) - { + else if (!ASSIMP_stricmp("tangents", t)) { curTangents.reserve (num); curBitangents.reserve (num); vertexFormat = 2; } - else if (ASSIMP_stricmp("standard", t)) - { + else if (ASSIMP_stricmp("standard", t)) { delete curMat; DefaultLogger::get()->warn("IRRMESH: Unknown vertex format"); } else vertexFormat = 0; textMeaning = 1; } - else if (!ASSIMP_stricmp(reader->getNodeName(),"indices")) - { - if (curVertices.empty() && curMat) - { + else if (!ASSIMP_stricmp(reader->getNodeName(),"indices")) { + if (curVertices.empty() && curMat) { delete curMat; throw new ImportErrorException("IRRMESH: indices must come after vertices"); } @@ -257,11 +237,8 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile, // allocate storage for all faces curMesh->mNumVertices = reader->getAttributeValueAsInt("indexCount"); - if (!curMesh->mNumVertices) - { - // This is possible ... remove the mesh from the list - // and skip further reading - + if (!curMesh->mNumVertices) { + // This is possible ... remove the mesh from the list and skip further reading DefaultLogger::get()->warn("IRRMESH: Found mesh with zero indices"); // mesh - away @@ -274,8 +251,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile, continue; } - if (curMesh->mNumVertices % 3) - { + if (curMesh->mNumVertices % 3) { DefaultLogger::get()->warn("IRRMESH: Number if indices isn't divisible by 3"); } @@ -289,28 +265,22 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile, // allocate storage for all vertices curMesh->mVertices = new aiVector3D[curMesh->mNumVertices]; - if (curNormals.size() == curVertices.size()) - { + if (curNormals.size() == curVertices.size()) { curMesh->mNormals = new aiVector3D[curMesh->mNumVertices]; } - if (curTangents.size() == curVertices.size()) - { + if (curTangents.size() == curVertices.size()) { curMesh->mTangents = new aiVector3D[curMesh->mNumVertices]; } - if (curBitangents.size() == curVertices.size()) - { + if (curBitangents.size() == curVertices.size()) { curMesh->mBitangents = new aiVector3D[curMesh->mNumVertices]; } - if (curColors.size() == curVertices.size() && useColors) - { + if (curColors.size() == curVertices.size() && useColors) { curMesh->mColors[0] = new aiColor4D[curMesh->mNumVertices]; } - if (curUVs.size() == curVertices.size()) - { + if (curUVs.size() == curVertices.size()) { curMesh->mTextureCoords[0] = new aiVector3D[curMesh->mNumVertices]; } - if (curUV2s.size() == curVertices.size()) - { + if (curUV2s.size() == curVertices.size()) { curMesh->mTextureCoords[1] = new aiVector3D[curMesh->mNumVertices]; } } @@ -319,13 +289,11 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile, case EXN_TEXT: { const char* sz = reader->getNodeData(); - if (textMeaning == 1) - { + if (textMeaning == 1) { textMeaning = 0; // read vertices - do - { + do { SkipSpacesAndLineEnd(&sz); aiVector3D temp;aiColor4D c; @@ -373,8 +341,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile, curUVs.push_back(temp); // read the (optional) second UV coordinate set - if (vertexFormat == 1) - { + if (vertexFormat == 1) { sz = fast_atof_move(sz,(float&)temp.x); SkipSpaces(&sz); @@ -383,8 +350,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile, curUV2s.push_back(temp); } // read optional tangent and bitangent vectors - else if (vertexFormat == 2) - { + else if (vertexFormat == 2) { // tangents sz = fast_atof_move(sz,(float&)temp.x); SkipSpaces(&sz); @@ -418,8 +384,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile, while (SkipLine(&sz)); } - else if (textMeaning == 2) - { + else if (textMeaning == 2) { textMeaning = 0; // read indices @@ -436,22 +401,18 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile, unsigned int curIdx = 0; unsigned int total = 0; - while(SkipSpacesAndLineEnd(&sz)) - { - if (curFace >= faceEnd) - { + while(SkipSpacesAndLineEnd(&sz)) { + if (curFace >= faceEnd) { DefaultLogger::get()->error("IRRMESH: Too many indices"); break; } - if (!curIdx) - { + if (!curIdx) { curFace->mNumIndices = 3; curFace->mIndices = new unsigned int[3]; } unsigned int idx = strtol10(sz,&sz); - if (idx >= curVertices.size()) - { + if (idx >= curVertices.size()) { DefaultLogger::get()->error("IRRMESH: Index out of range"); idx = 0; } @@ -466,8 +427,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile, if (pcT0)*pcT0++ = curUVs[idx]; if (pcT1)*pcT1++ = curUV2s[idx]; - if (++curIdx == 3) - { + if (++curIdx == 3) { ++curFace; curIdx = 0; } @@ -477,8 +437,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile, DefaultLogger::get()->error("IRRMESH: Not enough indices"); // Finish processing the mesh - do some small material workarounds - if (curMatFlags & AI_IRRMESH_MAT_trans_vertex_alpha && !useColors) - { + if (curMatFlags & AI_IRRMESH_MAT_trans_vertex_alpha && !useColors) { // Take the opacity value of the current material // from the common vertex color alpha MaterialHelper* mat = (MaterialHelper*)curMat; @@ -496,16 +455,13 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile, } // End of the last buffer. A material and a mesh should be there - if (curMat || curMesh) - { - if ( !curMat || !curMesh) - { + if (curMat || curMesh) { + if ( !curMat || !curMesh) { DefaultLogger::get()->error("IRRMESH: A buffer must contain a mesh and a material"); delete curMat; delete curMesh; } - else - { + else { materials.push_back(curMat); meshes.push_back(curMesh); } @@ -518,8 +474,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile, // now generate the output scene pScene->mNumMeshes = (unsigned int)meshes.size(); pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; - for (unsigned int i = 0; i < pScene->mNumMeshes;++i) - { + for (unsigned int i = 0; i < pScene->mNumMeshes;++i) { pScene->mMeshes[i] = meshes[i]; // clean this value ... @@ -538,9 +493,6 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile, for (unsigned int i = 0; i < pScene->mNumMeshes;++i) pScene->mRootNode->mMeshes[i] = i; - // transformation matrix to convert from IRRMESH to ASSIMP coordinates - pScene->mRootNode->mTransformation *= AI_TO_IRR_MATRIX; - // clean up and return delete reader; AI_DEBUG_INVALIDATE_PTR(reader); diff --git a/code/Importer.cpp b/code/Importer.cpp index 87502b453..385236f49 100644 --- a/code/Importer.cpp +++ b/code/Importer.cpp @@ -167,7 +167,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_BUILD_NO_JOINVERTICES_PROCESS # include "JoinVerticesProcess.h" #endif -#ifndef AI_BUILD_NO_CONVERTTOLH_PROCESS +#if !(defined AI_BUILD_NO_MAKELEFTHANDED_PROCESS && defined AI_BUILD_NO_FLIPUVS_PROCESS && defined AI_BUILD_NO_FLIPWINDINGORDER_PROCESS) # include "ConvertToLHProcess.h" #endif #ifndef AI_BUILD_NO_TRIANGULATE_PROCESS @@ -436,8 +436,14 @@ Importer::Importer() #if (!defined AI_BUILD_NO_SPLITLARGEMESHES_PROCESS) mPostProcessingSteps.push_back( new SplitLargeMeshesProcess_Vertex()); #endif -#if (!defined AI_BUILD_NO_CONVERTTOLH_PROCESS) - mPostProcessingSteps.push_back( new ConvertToLHProcess()); +#if (!defined AI_BUILD_NO_MAKELEFTHANDED_PROCESS) + mPostProcessingSteps.push_back( new MakeLeftHandedProcess()); +#endif +#if (!defined AI_BUILD_NO_FLIPUVS_PROCESS) + mPostProcessingSteps.push_back( new FlipUVsProcess()); +#endif +#if (!defined AI_BUILD_NO_FLIPWINDINGORDER_PROCESS) + mPostProcessingSteps.push_back( new FlipWindingOrderProcess()); #endif #if (!defined AI_BUILD_NO_LIMITBONEWEIGHTS_PROCESS) mPostProcessingSteps.push_back( new LimitBoneWeightsProcess()); diff --git a/code/LWOAnimation.cpp b/code/LWOAnimation.cpp index f73470435..f582edd56 100644 --- a/code/LWOAnimation.cpp +++ b/code/LWOAnimation.cpp @@ -549,7 +549,7 @@ void AnimResolver::ExtractAnimChannel(aiNodeAnim** out, unsigned int flags /*= 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.y ,keys[i].mValue.z ); + qk.mValue = aiQuaternion( keys[i].mValue.x ,keys[i].mValue.z ,keys[i].mValue.y ); } } diff --git a/code/LWOLoader.cpp b/code/LWOLoader.cpp index 95a38642e..2446a6a6a 100644 --- a/code/LWOLoader.cpp +++ b/code/LWOLoader.cpp @@ -53,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "SGSpatialSort.h" #include "ByteSwap.h" #include "ProcessHelper.h" +#include "ConvertToLHProcess.h" using namespace Assimp; @@ -314,24 +315,20 @@ void LWOImporter::InternReadFile( const std::string& pFile, // now convert all faces unsigned int vert = 0; std::vector::iterator outIt = smoothingGroups.begin(); - for (it = sorted.begin(); it != end;++it,++outIt) - { + for (it = sorted.begin(); it != end;++it,++outIt) { const LWO::Face& face = layer.mFaces[*it]; *outIt = face.smoothGroup; // copy all vertices - for (unsigned int q = 0; q < face.mNumIndices;++q) - { + for (unsigned int q = 0; q < face.mNumIndices;++q,++vert) { register unsigned int idx = face.mIndices[q]; *pv = layer.mTempPoints[idx] + layer.mPivot; - pv->z *= -1.0f; // DX to OGL - //std::swap(pv->z,pv->y); pv++; // process UV coordinates - for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_TEXTURECOORDS;++w) - { - if (0xffffffff == vUVChannelIndices[w])break; + for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_TEXTURECOORDS;++w) { + if (0xffffffff == vUVChannelIndices[w]) + break; aiVector3D*& pp = pvUV[w]; const aiVector2D& src = ((aiVector2D*)&layer.mUVChannels[vUVChannelIndices[w]].rawData[0])[idx]; pp->x = src.x; @@ -345,9 +342,9 @@ void LWOImporter::InternReadFile( const std::string& pFile, } // process vertex colors - for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_COLOR_SETS;++w) - { - if (0xffffffff == vVColorIndices[w])break; + for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_COLOR_SETS;++w) { + if (0xffffffff == vVColorIndices[w]) + break; *pvVC[w] = ((aiColor4D*)&layer.mVColorChannels[vVColorIndices[w]].rawData[0])[idx]; // If a RGB color map is explicitly requested delete the @@ -364,10 +361,8 @@ void LWOImporter::InternReadFile( const std::string& pFile, { } #endif - face.mIndices[q] = vert + (face.mNumIndices-q-1); + face.mIndices[q] = vert; } - vert += face.mNumIndices; - pf->mIndices = face.mIndices; pf->mNumIndices = face.mNumIndices; unsigned int** p = (unsigned int**)&face.mIndices;*p = NULL; // make sure it won't be deleted @@ -568,8 +563,7 @@ void LWOImporter::GenerateNodeGraph(std::vector& apcNodes) for (unsigned int i = 0; i < apcNodes.size();++i) if (apcNodes[i] && apcNodes[i]->mNumMeshes)++extra; - if (extra) - { + if (extra) { // we need to add extra nodes to the root const unsigned int newSize = extra + pScene->mRootNode->mNumChildren; aiNode** const apcNewNodes = new aiNode*[newSize]; @@ -596,15 +590,17 @@ void LWOImporter::GenerateNodeGraph(std::vector& apcNodes) if (!pScene->mRootNode->mNumChildren) throw new ImportErrorException("LWO: Unable to build a valid node graph"); - // remove a single root node - // TODO: implement directly in the above loop, no need to deallocate here - if (1 == pScene->mRootNode->mNumChildren) - { + // Remove a single root node with no meshes assigned ... + if (1 == pScene->mRootNode->mNumChildren) { aiNode* pc = pScene->mRootNode->mChildren[0]; pc->mParent = pScene->mRootNode->mChildren[0] = NULL; delete pScene->mRootNode; pScene->mRootNode = pc; } + + // convert the whole stuff to RH + MakeLeftHandedProcess maker; + maker.Execute(pScene); } // ------------------------------------------------------------------------------------------------ diff --git a/code/LWOMaterial.cpp b/code/LWOMaterial.cpp index 1a82ab1b8..907c779f3 100644 --- a/code/LWOMaterial.cpp +++ b/code/LWOMaterial.cpp @@ -136,12 +136,10 @@ bool LWOImporter::HandleTextures(MaterialHelper* pcMat, const TextureList& in, a break; }; - if (mapping != aiTextureMapping_UV) - { + if (mapping != aiTextureMapping_UV) { // Setup the main axis aiVector3D v; - switch ((*it).majorAxis) - { + switch ((*it).majorAxis) { case Texture::AXIS_X: v = aiVector3D(1.f,0.f,0.f); break; @@ -156,8 +154,7 @@ bool LWOImporter::HandleTextures(MaterialHelper* pcMat, const TextureList& in, a pcMat->AddProperty(&v,1,AI_MATKEY_TEXMAP_AXIS(type,cur)); // Setup UV scalings for cylindric and spherical projections - if (mapping == aiTextureMapping_CYLINDER || mapping == aiTextureMapping_SPHERE) - { + if (mapping == aiTextureMapping_CYLINDER || mapping == aiTextureMapping_SPHERE) { aiUVTransform trafo; trafo.mScaling.x = (*it).wrapAmountW; trafo.mScaling.y = (*it).wrapAmountH; diff --git a/code/LWSLoader.cpp b/code/LWSLoader.cpp index 8bc71270b..0580a9ab8 100644 --- a/code/LWSLoader.cpp +++ b/code/LWSLoader.cpp @@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "SceneCombiner.h" #include "GenericProperty.h" #include "SkeletonMeshBuilder.h" +#include "ConvertToLHProcess.h" using namespace Assimp; @@ -858,6 +859,10 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene, std::copy(anims.begin(),anims.end(),anim->mChannels); } + // convert the master scene to RH + MakeLeftHandedProcess monster_cheat; + monster_cheat.Execute(master); + // OK ... finally build the output graph SceneCombiner::MergeScenes(&pScene,master,attach, AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES | (!configSpeedFlag ? ( @@ -872,4 +877,5 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene, SkeletonMeshBuilder builder(pScene); } } + } diff --git a/code/MD5Loader.cpp b/code/MD5Loader.cpp index 9ca1f8b45..74939fa79 100644 --- a/code/MD5Loader.cpp +++ b/code/MD5Loader.cpp @@ -144,7 +144,11 @@ void MD5Importer::InternReadFile( const std::string& pFile, // make sure we have at least one file if (!bHadMD5Mesh && !bHadMD5Anim && !bHadMD5Camera) - throw new ImportErrorException("Failed to read valid contents from this MD5 data set"); + throw new ImportErrorException("Failed to read valid contents from this MD5* file"); + + // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system + pScene->mRootNode->mTransformation = aiMatrix4x4(1.f,0.f,0.f,0.f, + 0.f,0.f,1.f,0.f,0.f,-1.f,0.f,0.f,0.f,0.f,0.f,1.f); // the output scene wouldn't pass the validation without this flag if (!bHadMD5Mesh) @@ -156,7 +160,6 @@ void MD5Importer::InternReadFile( const std::string& pFile, void MD5Importer::LoadFileIntoMemory (IOStream* file) { ai_assert(NULL != file); - fileSize = (unsigned int)file->FileSize(); // allocate storage and copy the contents of the file to a memory buffer @@ -211,6 +214,8 @@ void MD5Importer::MakeDataUnique (MD5::MeshDesc& meshSrc) } else abHad[face.mIndices[i]] = true; } + // swap face order + std::swap(face.mIndices[0],face.mIndices[2]); } } @@ -443,8 +448,7 @@ void MD5Importer::LoadMD5MeshFile () } // process bone weights - for (unsigned int jub = (*iter).mFirstWeight, w = jub; w < jub + (*iter).mNumWeights;++w) - { + for (unsigned int jub = (*iter).mFirstWeight, w = jub; w < jub + (*iter).mNumWeights;++w) { if (w >= meshSrc.mWeights.size()) throw new ImportErrorException("MD5MESH: Invalid weight index"); @@ -478,8 +482,7 @@ void MD5Importer::LoadMD5MeshFile () // (however, take care that the aiFace destructor doesn't delete the mIndices array) mesh->mNumFaces = (unsigned int)meshSrc.mFaces.size(); mesh->mFaces = new aiFace[mesh->mNumFaces]; - for (unsigned int c = 0; c < mesh->mNumFaces;++c) - { + for (unsigned int c = 0; c < mesh->mNumFaces;++c) { mesh->mFaces[c].mNumIndices = 3; mesh->mFaces[c].mIndices = meshSrc.mFaces[c].mIndices; meshSrc.mFaces[c].mIndices = NULL; @@ -621,6 +624,7 @@ void MD5Importer::LoadMD5AnimFile () if (!pScene->mRootNode) { pScene->mRootNode = new aiNode(); pScene->mRootNode->mName.Set(""); + AttachChilds_Anim(-1,pScene->mRootNode,animParser.mAnimatedBones,(const aiNodeAnim**)anim->mChannels); // Call SkeletonMeshBuilder to construct a mesh to represent the shape @@ -659,14 +663,17 @@ void MD5Importer::LoadMD5CameraFile () std::vector& cuts = cameraParser.cuts; std::vector& frames = cameraParser.frames; - // Construct output graph - a simple dummy node - aiNode* root = pScene->mRootNode = new aiNode(); - root->mName.Set(""); + // Construct output graph - a simple root with a dummy child. + // The root node performs the coordinate system conversion + aiNode* root = pScene->mRootNode = new aiNode(""); + root->mChildren = new aiNode*[root->mNumChildren = 1]; + root->mChildren[0] = new aiNode(""); + root->mChildren[0]->mParent = root; // ... but with one camera assigned to it pScene->mCameras = new aiCamera*[pScene->mNumCameras = 1]; aiCamera* cam = pScene->mCameras[0] = new aiCamera(); - cam->mName = root->mName; + cam->mName = ""; // FIXME: Fov is currently set to the first frame's value cam->mHorizontalFOV = AI_DEG_TO_RAD( frames.front().fFOV ); diff --git a/code/MDLLoader.cpp b/code/MDLLoader.cpp index dcb061b2f..92371d483 100644 --- a/code/MDLLoader.cpp +++ b/code/MDLLoader.cpp @@ -148,98 +148,79 @@ void MDLImporter::InternReadFile( const std::string& pFile, // Append a binary zero to the end of the buffer. // this is just for safety that string parsing routines // find the end of the buffer ... - mBuffer[this->iFileSize] = '\0'; - const uint32_t iMagicWord = *((uint32_t*)this->mBuffer); + mBuffer[iFileSize] = '\0'; + const uint32_t iMagicWord = *((uint32_t*)mBuffer); // Determine the file subtype and call the appropriate member function try { // Original Quake1 format - if (AI_MDL_MAGIC_NUMBER_BE == iMagicWord || - AI_MDL_MAGIC_NUMBER_LE == iMagicWord) - { + if (AI_MDL_MAGIC_NUMBER_BE == iMagicWord || AI_MDL_MAGIC_NUMBER_LE == iMagicWord) { DefaultLogger::get()->debug("MDL subtype: Quake 1, magic word is IDPO"); iGSFileVersion = 0; InternReadFile_Quake1(); } // GameStudio A MDL2 format - used by some test models that come with 3DGS - else if (AI_MDL_MAGIC_NUMBER_BE_GS3 == iMagicWord || - AI_MDL_MAGIC_NUMBER_LE_GS3 == iMagicWord) - { + else if (AI_MDL_MAGIC_NUMBER_BE_GS3 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS3 == iMagicWord) { DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A2, magic word is MDL2"); iGSFileVersion = 2; InternReadFile_Quake1(); } // GameStudio A4 MDL3 format - else if (AI_MDL_MAGIC_NUMBER_BE_GS4 == iMagicWord || - AI_MDL_MAGIC_NUMBER_LE_GS4 == iMagicWord) - { + else if (AI_MDL_MAGIC_NUMBER_BE_GS4 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS4 == iMagicWord) { DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A4, magic word is MDL3"); iGSFileVersion = 3; InternReadFile_3DGS_MDL345(); } // GameStudio A5+ MDL4 format - else if (AI_MDL_MAGIC_NUMBER_BE_GS5a == iMagicWord || - AI_MDL_MAGIC_NUMBER_LE_GS5a == iMagicWord) - { + else if (AI_MDL_MAGIC_NUMBER_BE_GS5a == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS5a == iMagicWord) { DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A4, magic word is MDL4"); iGSFileVersion = 4; InternReadFile_3DGS_MDL345(); } // GameStudio A5+ MDL5 format - else if (AI_MDL_MAGIC_NUMBER_BE_GS5b == iMagicWord || - AI_MDL_MAGIC_NUMBER_LE_GS5b == iMagicWord) - { + else if (AI_MDL_MAGIC_NUMBER_BE_GS5b == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS5b == iMagicWord) { DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A5, magic word is MDL5"); iGSFileVersion = 5; InternReadFile_3DGS_MDL345(); } // GameStudio A7 MDL7 format - else if (AI_MDL_MAGIC_NUMBER_BE_GS7 == iMagicWord || - AI_MDL_MAGIC_NUMBER_LE_GS7 == iMagicWord) - { + else if (AI_MDL_MAGIC_NUMBER_BE_GS7 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS7 == iMagicWord) { DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A7, magic word is MDL7"); iGSFileVersion = 7; InternReadFile_3DGS_MDL7(); } // IDST/IDSQ Format (CS:S/HL˛, etc ...) - else if (AI_MDL_MAGIC_NUMBER_BE_HL2a == iMagicWord || - AI_MDL_MAGIC_NUMBER_LE_HL2a == iMagicWord || - AI_MDL_MAGIC_NUMBER_BE_HL2b == iMagicWord || - AI_MDL_MAGIC_NUMBER_LE_HL2b == iMagicWord) + else if (AI_MDL_MAGIC_NUMBER_BE_HL2a == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_HL2a == iMagicWord || + AI_MDL_MAGIC_NUMBER_BE_HL2b == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_HL2b == iMagicWord) { DefaultLogger::get()->debug("MDL subtype: CS:S\\HL˛, magic word is IDST/IDSQ"); iGSFileVersion = 0; InternReadFile_HL2(); } - else - { - // print the magic word to the logger - char szBuffer[5]; - szBuffer[0] = ((char*)&iMagicWord)[0]; - szBuffer[1] = ((char*)&iMagicWord)[1]; - szBuffer[2] = ((char*)&iMagicWord)[2]; - szBuffer[3] = ((char*)&iMagicWord)[3]; - szBuffer[4] = '\0'; - - // we're definitely unable to load this file + else { + // print the magic word to the log file throw new ImportErrorException( "Unknown MDL subformat " + pFile + - ". Magic word (" + szBuffer + ") is not known"); + ". Magic word (" + std::string((char*)&iMagicWord,4) + ") is not known"); } } catch (ImportErrorException* ex) { - delete[] this->mBuffer; - AI_DEBUG_INVALIDATE_PTR(this->mBuffer); - AI_DEBUG_INVALIDATE_PTR(this->pIOHandler); - AI_DEBUG_INVALIDATE_PTR(this->pScene); + delete[] mBuffer; + AI_DEBUG_INVALIDATE_PTR(mBuffer); + AI_DEBUG_INVALIDATE_PTR(pIOHandler); + AI_DEBUG_INVALIDATE_PTR(pScene); throw ex; } + // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system + pScene->mRootNode->mTransformation = aiMatrix4x4(1.f,0.f,0.f,0.f, + 0.f,0.f,1.f,0.f,0.f,-1.f,0.f,0.f,0.f,0.f,0.f,1.f); + // delete the file buffer and cleanup - delete[] this->mBuffer; - AI_DEBUG_INVALIDATE_PTR(this->mBuffer); - AI_DEBUG_INVALIDATE_PTR(this->pIOHandler); - AI_DEBUG_INVALIDATE_PTR(this->pScene); + delete[] mBuffer; + AI_DEBUG_INVALIDATE_PTR(mBuffer); + AI_DEBUG_INVALIDATE_PTR(pIOHandler); + AI_DEBUG_INVALIDATE_PTR(pScene); } // ------------------------------------------------------------------------------------------------ @@ -482,23 +463,21 @@ void MDLImporter::InternReadFile_Quake1( ) vec.y = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1]; vec.y += pcHeader->translate[1]; - vec.y *= -1.0f; + //vec.y *= -1.0f; vec.z = (float)pcVertices[iIndex].v[2] * pcHeader->scale[2]; vec.z += pcHeader->translate[2]; // read the normal vector from the precalculated normal table MD2::LookupNormalIndex(pcVertices[iIndex].normalIndex,pcMesh->mNormals[iCurrent]); - pcMesh->mNormals[iCurrent].y *= -1.0f; + //pcMesh->mNormals[iCurrent].y *= -1.0f; // read texture coordinates float s = (float)pcTexCoords[iIndex].s; float t = (float)pcTexCoords[iIndex].t; // translate texture coordinates - if (0 == pcTriangles->facesfront && - 0 != pcTexCoords[iIndex].onseam) - { + if (0 == pcTriangles->facesfront && 0 != pcTexCoords[iIndex].onseam) { s += pcHeader->skinwidth * 0.5f; } @@ -535,14 +514,12 @@ void MDLImporter::SetupMaterialProperties_3DGS_MDL5_Quake1( ) if (0 != pcHeader->num_skins && pScene->mNumTextures) { // can we replace the texture with a single color? clr = this->ReplaceTextureWithColor(pScene->mTextures[0]); - if (is_not_qnan(clr.r)) - { + if (is_not_qnan(clr.r)) { delete pScene->mTextures[0]; delete[] pScene->mTextures; pScene->mNumTextures = 0; } - else - { + else { clr.b = clr.a = clr.g = clr.r = 1.0f; aiString szString; ::memcpy(szString.data,AI_MAKE_EMBEDDED_TEXNAME(0),3); @@ -608,14 +585,12 @@ void MDLImporter::InternReadFile_3DGS_MDL345( ) #ifdef AI_BUILD_BIG_ENDIAN - for (int i = 0; isynctype;++i) - { + for (int i = 0; isynctype;++i) { AI_SWAP2( pcTexCoords[i].u ); AI_SWAP2( pcTexCoords[i].v ); } - for (int i = 0; inum_tris;++i) - { + for (int i = 0; inum_tris;++i) { AI_SWAP2( pcTriangles[i].index_xyz[0]); AI_SWAP2( pcTriangles[i].index_xyz[1]); AI_SWAP2( pcTriangles[i].index_xyz[2]); @@ -653,8 +628,7 @@ void MDLImporter::InternReadFile_3DGS_MDL345( ) pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices]; pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices]; - if (pcHeader->synctype) - { + if (pcHeader->synctype) { pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices]; pcMesh->mNumUVComponents[0] = 2; } @@ -664,10 +638,10 @@ void MDLImporter::InternReadFile_3DGS_MDL345( ) AI_SWAP4(pcFrames->type); // byte packed vertices - // FIXME: these two snippets are nearly totally identical ... + // FIXME: these two snippets below are almost identical ... join them? ///////////////////////////////////////////////////////////////////////////////////// - if (0 == pcFrames->type || 3 >= this->iGSFileVersion) - { + if (0 == pcFrames->type || 3 >= this->iGSFileVersion) { + const MDL::SimpleFrame* pcFirstFrame = (const MDL::SimpleFrame*)(szCurrent + sizeof(uint32_t)); const MDL::Vertex* pcVertices = (const MDL::Vertex*) ((pcFirstFrame->name) + sizeof(pcFirstFrame->name)); @@ -675,18 +649,15 @@ void MDLImporter::InternReadFile_3DGS_MDL345( ) // now iterate through all triangles unsigned int iCurrent = 0; - for (unsigned int i = 0; i < (unsigned int) pcHeader->num_tris;++i) - { + for (unsigned int i = 0; i < (unsigned int) pcHeader->num_tris;++i) { pcMesh->mFaces[i].mIndices = new unsigned int[3]; pcMesh->mFaces[i].mNumIndices = 3; unsigned int iTemp = iCurrent; - for (unsigned int c = 0; c < 3;++c,++iCurrent) - { + for (unsigned int c = 0; c < 3;++c,++iCurrent) { // read vertices unsigned int iIndex = pcTriangles->index_xyz[c]; - if (iIndex >= (unsigned int)pcHeader->num_verts) - { + if (iIndex >= (unsigned int)pcHeader->num_verts) { iIndex = pcHeader->num_verts-1; DefaultLogger::get()->warn("Index overflow in MDLn vertex list"); } @@ -697,14 +668,14 @@ void MDLImporter::InternReadFile_3DGS_MDL345( ) vec.y = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1]; vec.y += pcHeader->translate[1]; - vec.y *= -1.0f; + // vec.y *= -1.0f; vec.z = (float)pcVertices[iIndex].v[2] * pcHeader->scale[2]; vec.z += pcHeader->translate[2]; // read the normal vector from the precalculated normal table MD2::LookupNormalIndex(pcVertices[iIndex].normalIndex,pcMesh->mNormals[iCurrent]); - pcMesh->mNormals[iCurrent].y *= -1.0f; + // pcMesh->mNormals[iCurrent].y *= -1.0f; // read texture coordinates if (pcHeader->synctype) { @@ -721,31 +692,27 @@ void MDLImporter::InternReadFile_3DGS_MDL345( ) } // short packed vertices ///////////////////////////////////////////////////////////////////////////////////// - else - { + else { // now get a pointer to the first frame in the file const MDL::SimpleFrame_MDLn_SP* pcFirstFrame = (const MDL::SimpleFrame_MDLn_SP*) (szCurrent + sizeof(uint32_t)); // get a pointer to the vertices - const MDL::Vertex_MDL4* pcVertices = (const MDL::Vertex_MDL4*) ((pcFirstFrame->name) + + const MDL::Vertex_MDL4* pcVertices = (const MDL::Vertex_MDL4*) ((pcFirstFrame->name) + sizeof(pcFirstFrame->name)); VALIDATE_FILE_SIZE(pcVertices + pcHeader->num_verts); // now iterate through all triangles unsigned int iCurrent = 0; - for (unsigned int i = 0; i < (unsigned int) pcHeader->num_tris;++i) - { + for (unsigned int i = 0; i < (unsigned int) pcHeader->num_tris;++i) { pcMesh->mFaces[i].mIndices = new unsigned int[3]; pcMesh->mFaces[i].mNumIndices = 3; unsigned int iTemp = iCurrent; - for (unsigned int c = 0; c < 3;++c,++iCurrent) - { + for (unsigned int c = 0; c < 3;++c,++iCurrent) { // read vertices unsigned int iIndex = pcTriangles->index_xyz[c]; - if (iIndex >= (unsigned int)pcHeader->num_verts) - { + if (iIndex >= (unsigned int)pcHeader->num_verts) { iIndex = pcHeader->num_verts-1; DefaultLogger::get()->warn("Index overflow in MDLn vertex list"); } @@ -756,14 +723,14 @@ void MDLImporter::InternReadFile_3DGS_MDL345( ) vec.y = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1]; vec.y += pcHeader->translate[1]; - vec.y *= -1.0f; + // vec.y *= -1.0f; vec.z = (float)pcVertices[iIndex].v[2] * pcHeader->scale[2]; vec.z += pcHeader->translate[2]; // read the normal vector from the precalculated normal table MD2::LookupNormalIndex(pcVertices[iIndex].normalIndex,pcMesh->mNormals[iCurrent]); - pcMesh->mNormals[iCurrent].y *= -1.0f; + // pcMesh->mNormals[iCurrent].y *= -1.0f; // read texture coordinates if (pcHeader->synctype) { @@ -780,8 +747,8 @@ void MDLImporter::InternReadFile_3DGS_MDL345( ) // For MDL5 we will need to build valid texture coordinates // basing upon the file loaded (only support one file as skin) - if (0x5 == this->iGSFileVersion) - this->CalculateUVCoordinates_MDL5(); + if (0x5 == iGSFileVersion) + CalculateUVCoordinates_MDL5(); return; } @@ -796,8 +763,7 @@ void MDLImporter::ImportUVCoordinate_3DGS_MDL345( const MDL::Header* const pcHeader = (const MDL::Header*)this->mBuffer; // validate UV indices - if (iIndex >= (unsigned int) pcHeader->synctype) - { + if (iIndex >= (unsigned int) pcHeader->synctype) { iIndex = pcHeader->synctype-1; DefaultLogger::get()->warn("Index overflow in MDLn UV coord list"); } @@ -806,7 +772,7 @@ void MDLImporter::ImportUVCoordinate_3DGS_MDL345( float t = (float)pcSrc[iIndex].v; // Scale s and t to range from 0.0 to 1.0 - if (0x5 != this->iGSFileVersion) { + if (0x5 != iGSFileVersion) { s = (s + 0.5f) / pcHeader->skinwidth; t = 1.0f-(t + 0.5f) / pcHeader->skinheight; } @@ -821,16 +787,14 @@ void MDLImporter::ImportUVCoordinate_3DGS_MDL345( void MDLImporter::CalculateUVCoordinates_MDL5() { const MDL::Header* const pcHeader = (const MDL::Header*)this->mBuffer; - if (pcHeader->num_skins && this->pScene->mNumTextures) - { + if (pcHeader->num_skins && this->pScene->mNumTextures) { const aiTexture* pcTex = this->pScene->mTextures[0]; // if the file is loaded in DDS format: get the size of the // texture from the header of the DDS file // skip three DWORDs and read first height, then the width unsigned int iWidth, iHeight; - if (!pcTex->mHeight) - { + if (!pcTex->mHeight) { const uint32_t* piPtr = (uint32_t*)pcTex->pcData; piPtr += 3; @@ -846,8 +810,7 @@ void MDLImporter::CalculateUVCoordinates_MDL5() iHeight = 1; } } - else - { + else { iWidth = pcTex->mWidth; iHeight = pcTex->mHeight; } @@ -897,7 +860,7 @@ void MDLImporter::ValidateHeader_3DGS_MDL7(const MDL::Header_MDL7* pcHeader) void MDLImporter::CalcAbsBoneMatrices_3DGS_MDL7(MDL::IntBone_MDL7** apcOutBones) { const MDL::Header_MDL7 *pcHeader = (const MDL::Header_MDL7*)this->mBuffer; - const MDL::Bone_MDL7* pcBones = (const MDL::Bone_MDL7*)(pcHeader+1); + const MDL::Bone_MDL7* pcBones = (const MDL::Bone_MDL7*)(pcHeader+1); ai_assert(NULL != apcOutBones); // first find the bone that has NO parent, calculate the @@ -905,20 +868,17 @@ void MDLImporter::CalcAbsBoneMatrices_3DGS_MDL7(MDL::IntBone_MDL7** apcOutBones) // index (0) and so on until we can't find a new node. uint16_t iParent = 0xffff; uint32_t iIterations = 0; - while (iIterations++ < pcHeader->bones_num) - { - for (uint32_t iBone = 0; iBone < pcHeader->bones_num;++iBone) - { + while (iIterations++ < pcHeader->bones_num) { + for (uint32_t iBone = 0; iBone < pcHeader->bones_num;++iBone) { BE_NCONST MDL::Bone_MDL7* pcBone = _AI_MDL7_ACCESS_PTR(pcBones,iBone, pcHeader->bone_stc_size,MDL::Bone_MDL7); - - AI_SWAP2(pcBone->parent_index); - AI_SWAP4(pcBone->x); - AI_SWAP4(pcBone->y); - AI_SWAP4(pcBone->z); - - if (iParent == pcBone->parent_index) - { + + AI_SWAP2(pcBone->parent_index); + AI_SWAP4(pcBone->x); + AI_SWAP4(pcBone->y); + AI_SWAP4(pcBone->z); + + if (iParent == pcBone->parent_index) { // MDL7 readme //////////////////////////////////////////////////////////////// /* @@ -943,8 +903,7 @@ void MDLImporter::CalcAbsBoneMatrices_3DGS_MDL7(MDL::IntBone_MDL7** apcOutBones) // store the parent index of the bone pcOutBone->iParent = pcBone->parent_index; - if (0xffff != iParent) - { + if (0xffff != iParent) { const MDL::IntBone_MDL7* pcParentBone = apcOutBones[iParent]; pcOutBone->mOffsetMatrix.a4 = -pcParentBone->vPosition.x; pcOutBone->mOffsetMatrix.b4 = -pcParentBone->vPosition.y; @@ -957,14 +916,12 @@ void MDLImporter::CalcAbsBoneMatrices_3DGS_MDL7(MDL::IntBone_MDL7** apcOutBones) pcOutBone->mOffsetMatrix.b4 -= pcBone->y; pcOutBone->mOffsetMatrix.c4 -= pcBone->z; - if (AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_NOT_THERE == pcHeader->bone_stc_size) - { + if (AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_NOT_THERE == pcHeader->bone_stc_size) { // no real name for our poor bone is specified :-( pcOutBone->mName.length = ::sprintf(pcOutBone->mName.data, "UnnamedBone_%i",iBone); } - else - { + else { // Make sure we won't run over the buffer's end if there is no // terminal 0 character (however the documentation says there // should be one) @@ -992,11 +949,10 @@ void MDLImporter::CalcAbsBoneMatrices_3DGS_MDL7(MDL::IntBone_MDL7** apcOutBones) MDL::IntBone_MDL7** MDLImporter::LoadBones_3DGS_MDL7() { const MDL::Header_MDL7 *pcHeader = (const MDL::Header_MDL7*)this->mBuffer; - if (pcHeader->bones_num) - { + if (pcHeader->bones_num) { // validate the size of the bone data structure in the file - if (AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_20_CHARS != pcHeader->bone_stc_size && - AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_32_CHARS != pcHeader->bone_stc_size && + if (AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_20_CHARS != pcHeader->bone_stc_size && + AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_32_CHARS != pcHeader->bone_stc_size && AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_NOT_THERE != pcHeader->bone_stc_size) { DefaultLogger::get()->warn("Unknown size of bone data structure"); @@ -1016,136 +972,125 @@ MDL::IntBone_MDL7** MDLImporter::LoadBones_3DGS_MDL7() // ------------------------------------------------------------------------------------------------ // read faces from a MDL7 file -void MDLImporter::ReadFaces_3DGS_MDL7( - const MDL::IntGroupInfo_MDL7& groupInfo, +void MDLImporter::ReadFaces_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInfo, MDL::IntGroupData_MDL7& groupData) { const MDL::Header_MDL7 *pcHeader = (const MDL::Header_MDL7*)this->mBuffer; - BE_NCONST MDL::Triangle_MDL7* pcGroupTris = groupInfo.pcGroupTris; + BE_NCONST MDL::Triangle_MDL7* pcGroupTris = groupInfo.pcGroupTris; // iterate through all triangles and build valid display lists - unsigned int iOutIndex = 0; - for (unsigned int iTriangle = 0; iTriangle < (unsigned int)groupInfo.pcGroup->numtris; ++iTriangle) - { - AI_SWAP2(pcGroupTris->v_index[0]); - AI_SWAP2(pcGroupTris->v_index[1]); - AI_SWAP2(pcGroupTris->v_index[2]); + unsigned int iOutIndex = 0; + for (unsigned int iTriangle = 0; iTriangle < (unsigned int)groupInfo.pcGroup->numtris; ++iTriangle) { + AI_SWAP2(pcGroupTris->v_index[0]); + AI_SWAP2(pcGroupTris->v_index[1]); + AI_SWAP2(pcGroupTris->v_index[2]); - // iterate through all indices of the current triangle - for (unsigned int c = 0; c < 3;++c,++iOutIndex) - { - // validate the vertex index - unsigned int iIndex = pcGroupTris->v_index[c]; - if(iIndex > (unsigned int)groupInfo.pcGroup->numverts) - { - // (we might need to read this section a second time - to process frame vertices correctly) - const_cast(pcGroupTris)->v_index[c] = iIndex = groupInfo.pcGroup->numverts-1; - DefaultLogger::get()->warn("Index overflow in MDL7 vertex list"); - } + // iterate through all indices of the current triangle + for (unsigned int c = 0; c < 3;++c,++iOutIndex) { - // write the output face index - groupData.pcFaces[iTriangle].mIndices[2-c] = iOutIndex; + // validate the vertex index + unsigned int iIndex = pcGroupTris->v_index[c]; + if(iIndex > (unsigned int)groupInfo.pcGroup->numverts) { + // (we might need to read this section a second time - to process frame vertices correctly) + const_cast(pcGroupTris)->v_index[c] = iIndex = groupInfo.pcGroup->numverts-1; + DefaultLogger::get()->warn("Index overflow in MDL7 vertex list"); + } - aiVector3D& vPosition = groupData.vPositions[ iOutIndex ]; - vPosition.x = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex, pcHeader->mainvertex_stc_size) .x; - vPosition.y = -1.0f*_AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .y; - vPosition.z = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .z; + // write the output face index + groupData.pcFaces[iTriangle].mIndices[2-c] = iOutIndex; - // if we have bones, save the index - if (!groupData.aiBones.empty()) - groupData.aiBones[iOutIndex] = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts, - iIndex,pcHeader->mainvertex_stc_size).vertindex; + aiVector3D& vPosition = groupData.vPositions[ iOutIndex ]; + vPosition.x = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex, pcHeader->mainvertex_stc_size) .x; + vPosition.y = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .y; + vPosition.z = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .z; - // now read the normal vector - if (AI_MDL7_FRAMEVERTEX030305_STCSIZE <= pcHeader->mainvertex_stc_size) - { - // read the full normal vector - aiVector3D& vNormal = groupData.vNormals[ iOutIndex ]; - vNormal.x = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[0]; - AI_SWAP4(vNormal.x); - vNormal.y = -1.0f*_AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[1]; - AI_SWAP4(vNormal.y); - vNormal.z = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[2]; - AI_SWAP4(vNormal.z); - } - else if (AI_MDL7_FRAMEVERTEX120503_STCSIZE <= pcHeader->mainvertex_stc_size) - { - // read the normal vector from Quake2's smart table - aiVector3D& vNormal = groupData.vNormals[ iOutIndex ]; - MD2::LookupNormalIndex(_AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex, - pcHeader->mainvertex_stc_size) .norm162index,vNormal); - vNormal.y *= -1.0f; - } - // validate and process the first uv coordinate set - if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV) - { - if (groupInfo.pcGroup->num_stpts) - { - AI_SWAP2(pcGroupTris->skinsets[0].st_index[0]); - AI_SWAP2(pcGroupTris->skinsets[0].st_index[1]); - AI_SWAP2(pcGroupTris->skinsets[0].st_index[2]); + // if we have bones, save the index + if (!groupData.aiBones.empty()) { + groupData.aiBones[iOutIndex] = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts, + iIndex,pcHeader->mainvertex_stc_size).vertindex; + } + // now read the normal vector + if (AI_MDL7_FRAMEVERTEX030305_STCSIZE <= pcHeader->mainvertex_stc_size) { + // read the full normal vector + aiVector3D& vNormal = groupData.vNormals[ iOutIndex ]; + vNormal.x = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[0]; + AI_SWAP4(vNormal.x); + vNormal.y = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[1]; + AI_SWAP4(vNormal.y); + vNormal.z = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[2]; + AI_SWAP4(vNormal.z); + } + else if (AI_MDL7_FRAMEVERTEX120503_STCSIZE <= pcHeader->mainvertex_stc_size) { + // read the normal vector from Quake2's smart table + aiVector3D& vNormal = groupData.vNormals[ iOutIndex ]; + MD2::LookupNormalIndex(_AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex, + pcHeader->mainvertex_stc_size) .norm162index,vNormal); + } + // validate and process the first uv coordinate set + if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV) { - iIndex = pcGroupTris->skinsets[0].st_index[c]; - if(iIndex > (unsigned int)groupInfo.pcGroup->num_stpts) - { - iIndex = groupInfo.pcGroup->num_stpts-1; - DefaultLogger::get()->warn("Index overflow in MDL7 UV coordinate list (#1)"); - } + if (groupInfo.pcGroup->num_stpts) { + AI_SWAP2(pcGroupTris->skinsets[0].st_index[0]); + AI_SWAP2(pcGroupTris->skinsets[0].st_index[1]); + AI_SWAP2(pcGroupTris->skinsets[0].st_index[2]); - float u = groupInfo.pcGroupUVs[iIndex].u; - float v = 1.0f-groupInfo.pcGroupUVs[iIndex].v; // DX to OGL + iIndex = pcGroupTris->skinsets[0].st_index[c]; + if(iIndex > (unsigned int)groupInfo.pcGroup->num_stpts) { + iIndex = groupInfo.pcGroup->num_stpts-1; + DefaultLogger::get()->warn("Index overflow in MDL7 UV coordinate list (#1)"); + } - groupData.vTextureCoords1[iOutIndex].x = u; - groupData.vTextureCoords1[iOutIndex].y = v; - } - // assign the material index, but only if it is existing - if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV_WITH_MATINDEX){ - AI_SWAP4(pcGroupTris->skinsets[0].material); - groupData.pcFaces[iTriangle].iMatIndex[0] = pcGroupTris->skinsets[0].material; - } - } - // validate and process the second uv coordinate set - if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_TWO_UV) - { - if (groupInfo.pcGroup->num_stpts) - { - AI_SWAP2(pcGroupTris->skinsets[1].st_index[0]); - AI_SWAP2(pcGroupTris->skinsets[1].st_index[1]); - AI_SWAP2(pcGroupTris->skinsets[1].st_index[2]); - AI_SWAP4(pcGroupTris->skinsets[1].material); + float u = groupInfo.pcGroupUVs[iIndex].u; + float v = 1.0f-groupInfo.pcGroupUVs[iIndex].v; // DX to OGL - iIndex = pcGroupTris->skinsets[1].st_index[c]; - if(iIndex > (unsigned int)groupInfo.pcGroup->num_stpts) - { - iIndex = groupInfo.pcGroup->num_stpts-1; - DefaultLogger::get()->warn("Index overflow in MDL7 UV coordinate list (#2)"); - } + groupData.vTextureCoords1[iOutIndex].x = u; + groupData.vTextureCoords1[iOutIndex].y = v; + } + // assign the material index, but only if it is existing + if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV_WITH_MATINDEX){ + AI_SWAP4(pcGroupTris->skinsets[0].material); + groupData.pcFaces[iTriangle].iMatIndex[0] = pcGroupTris->skinsets[0].material; + } + } + // validate and process the second uv coordinate set + if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_TWO_UV) { - float u = groupInfo.pcGroupUVs[ iIndex ].u; - float v = 1.0f-groupInfo.pcGroupUVs[ iIndex ].v; + if (groupInfo.pcGroup->num_stpts) { + AI_SWAP2(pcGroupTris->skinsets[1].st_index[0]); + AI_SWAP2(pcGroupTris->skinsets[1].st_index[1]); + AI_SWAP2(pcGroupTris->skinsets[1].st_index[2]); + AI_SWAP4(pcGroupTris->skinsets[1].material); - groupData.vTextureCoords2[ iOutIndex ].x = u; - groupData.vTextureCoords2[ iOutIndex ].y = v; // DX to OGL + iIndex = pcGroupTris->skinsets[1].st_index[c]; + if(iIndex > (unsigned int)groupInfo.pcGroup->num_stpts) { + iIndex = groupInfo.pcGroup->num_stpts-1; + DefaultLogger::get()->warn("Index overflow in MDL7 UV coordinate list (#2)"); + } - // check whether we do really need the second texture - // coordinate set ... wastes memory and loading time - if (0 != iIndex && (u != groupData.vTextureCoords1[ iOutIndex ].x || - v != groupData.vTextureCoords1[ iOutIndex ].y ) ) - groupData.bNeed2UV = true; + float u = groupInfo.pcGroupUVs[ iIndex ].u; + float v = 1.0f-groupInfo.pcGroupUVs[ iIndex ].v; - // if the material differs, we need a second skin, too - if (pcGroupTris->skinsets[ 1 ].material != pcGroupTris->skinsets[ 0 ].material) - groupData.bNeed2UV = true; - } - // assign the material index - groupData.pcFaces[ iTriangle ].iMatIndex[ 1 ] = pcGroupTris->skinsets[ 1 ].material; - } - } - // get the next triangle in the list - pcGroupTris = (BE_NCONST MDL::Triangle_MDL7*)((const char*)pcGroupTris + - pcHeader->triangle_stc_size); - } + groupData.vTextureCoords2[ iOutIndex ].x = u; + groupData.vTextureCoords2[ iOutIndex ].y = v; // DX to OGL + + // check whether we do really need the second texture + // coordinate set ... wastes memory and loading time + if (0 != iIndex && (u != groupData.vTextureCoords1[ iOutIndex ].x || + v != groupData.vTextureCoords1[ iOutIndex ].y ) ) + groupData.bNeed2UV = true; + + // if the material differs, we need a second skin, too + if (pcGroupTris->skinsets[ 1 ].material != pcGroupTris->skinsets[ 0 ].material) + groupData.bNeed2UV = true; + } + // assign the material index + groupData.pcFaces[ iTriangle ].iMatIndex[ 1 ] = pcGroupTris->skinsets[ 1 ].material; + } + } + // get the next triangle in the list + pcGroupTris = (BE_NCONST MDL::Triangle_MDL7*)((const char*)pcGroupTris + pcHeader->triangle_stc_size); + } } // ------------------------------------------------------------------------------------------------ @@ -1157,14 +1102,12 @@ bool MDLImporter::ProcessFrames_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInf const unsigned char** szCurrentOut) { ai_assert(NULL != szCurrent && NULL != szCurrentOut); - const MDL::Header_MDL7 *pcHeader = (const MDL::Header_MDL7*)mBuffer; // if we have no bones we can simply skip all frames, // otherwise we'll need to process them. // FIX: If we need another frame than the first we must apply frame vertex replacements ... - for(unsigned int iFrame = 0; iFrame < (unsigned int)groupInfo.pcGroup->numframes;++iFrame) - { + for(unsigned int iFrame = 0; iFrame < (unsigned int)groupInfo.pcGroup->numframes;++iFrame) { MDL::IntFrameInfo_MDL7 frame ((BE_NCONST MDL::Frame_MDL7*)szCurrent,iFrame); AI_SWAP4(frame.pcFrame->vertices_count); @@ -1184,20 +1127,15 @@ bool MDLImporter::ProcessFrames_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInf return false; } // our output frame? - if (configFrameID == iFrame) - { + if (configFrameID == iFrame) { BE_NCONST MDL::Vertex_MDL7* pcFrameVertices = (BE_NCONST MDL::Vertex_MDL7*)(szCurrent+pcHeader->frame_stc_size); - for (unsigned int qq = 0; qq < frame.pcFrame->vertices_count;++qq) - { - // I assume this are simple replacements for normal - // vertices, the bone index serving as the index of the - // vertex to be replaced. - uint16_t iIndex = _AI_MDL7_ACCESS(pcFrameVertices,qq, - pcHeader->framevertex_stc_size,MDL::Vertex_MDL7).vertindex; + for (unsigned int qq = 0; qq < frame.pcFrame->vertices_count;++qq) { + // I assume this are simple replacements for normal vertices, the bone index serving + // as the index of the vertex to be replaced. + uint16_t iIndex = _AI_MDL7_ACCESS(pcFrameVertices,qq,pcHeader->framevertex_stc_size,MDL::Vertex_MDL7).vertindex; AI_SWAP2(iIndex); - if (iIndex >= groupInfo.pcGroup->numverts) - { + if (iIndex >= groupInfo.pcGroup->numverts) { DefaultLogger::get()->warn("Invalid vertex index in frame vertex section"); continue; } @@ -1206,42 +1144,36 @@ bool MDLImporter::ProcessFrames_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInf vPosition.x = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .x; AI_SWAP4(vPosition.x); - vPosition.y = -1.0f*_AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .y; + vPosition.y = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .y; AI_SWAP4(vPosition.y); vPosition.z = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .z; AI_SWAP4(vPosition.z); // now read the normal vector - if (AI_MDL7_FRAMEVERTEX030305_STCSIZE <= pcHeader->mainvertex_stc_size) - { + if (AI_MDL7_FRAMEVERTEX030305_STCSIZE <= pcHeader->mainvertex_stc_size) { // read the full normal vector vNormal.x = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .norm[0]; AI_SWAP4(vNormal.x); - vNormal.y = -1.0f* _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .norm[1]; + vNormal.y = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .norm[1]; AI_SWAP4(vNormal.y); vNormal.z = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .norm[2]; AI_SWAP4(vNormal.z); } - else if (AI_MDL7_FRAMEVERTEX120503_STCSIZE <= pcHeader->mainvertex_stc_size) - { + else if (AI_MDL7_FRAMEVERTEX120503_STCSIZE <= pcHeader->mainvertex_stc_size) { // read the normal vector from Quake2's smart table MD2::LookupNormalIndex(_AI_MDL7_ACCESS_VERT(pcFrameVertices,qq, pcHeader->framevertex_stc_size) .norm162index,vNormal); - vNormal.y *= -1.0f; } // FIXME: O(n^2) at the moment ... BE_NCONST MDL::Triangle_MDL7* pcGroupTris = groupInfo.pcGroupTris; unsigned int iOutIndex = 0; - for (unsigned int iTriangle = 0; iTriangle < (unsigned int)groupInfo.pcGroup->numtris; ++iTriangle) - { + for (unsigned int iTriangle = 0; iTriangle < (unsigned int)groupInfo.pcGroup->numtris; ++iTriangle) { // iterate through all indices of the current triangle - for (unsigned int c = 0; c < 3;++c,++iOutIndex) - { + for (unsigned int c = 0; c < 3;++c,++iOutIndex) { // replace the vertex with the new data const unsigned int iCurIndex = pcGroupTris->v_index[c]; - if (iCurIndex == iIndex) - { + if (iCurIndex == iIndex) { groupData.vPositions[iOutIndex] = vPosition; groupData.vNormals[iOutIndex] = vNormal; } @@ -1253,7 +1185,9 @@ bool MDLImporter::ProcessFrames_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInf } } // parse bone trafo matrix keys (only if there are bones ...) - if (shared.apcOutBones)ParseBoneTrafoKeys_3DGS_MDL7(groupInfo,frame,shared); + if (shared.apcOutBones) { + ParseBoneTrafoKeys_3DGS_MDL7(groupInfo,frame,shared); + } szCurrent += iAdd; } *szCurrentOut = szCurrent; @@ -1268,8 +1202,7 @@ void MDLImporter::SortByMaterials_3DGS_MDL7( MDL::IntSplittedGroupData_MDL7& splittedGroupData) { const unsigned int iNumMaterials = (unsigned int)splittedGroupData.shared.pcMats.size(); - if (!groupData.bNeed2UV) - { + if (!groupData.bNeed2UV) { // if we don't need a second set of texture coordinates there is no reason to keep it in memory ... groupData.vTextureCoords2.clear(); @@ -1280,11 +1213,9 @@ void MDLImporter::SortByMaterials_3DGS_MDL7( splittedGroupData.aiSplit[m] = new std::vector(); // iterate through all faces and sort by material - for (unsigned int iFace = 0; iFace < (unsigned int)groupInfo.pcGroup->numtris;++iFace) - { + for (unsigned int iFace = 0; iFace < (unsigned int)groupInfo.pcGroup->numtris;++iFace) { // check range - if (groupData.pcFaces[iFace].iMatIndex[0] >= iNumMaterials) - { + if (groupData.pcFaces[iFace].iMatIndex[0] >= iNumMaterials) { // use the last material instead splittedGroupData.aiSplit[iNumMaterials-1]->push_back(iFace); @@ -1309,12 +1240,10 @@ void MDLImporter::SortByMaterials_3DGS_MDL7( aiTempSplit[m] = new std::vector(); // iterate through all faces and sort by material - for (unsigned int iFace = 0; iFace < (unsigned int)groupInfo.pcGroup->numtris;++iFace) - { + for (unsigned int iFace = 0; iFace < (unsigned int)groupInfo.pcGroup->numtris;++iFace) { // check range unsigned int iMatIndex = groupData.pcFaces[iFace].iMatIndex[0]; - if (iMatIndex >= iNumMaterials) - { + if (iMatIndex >= iNumMaterials) { // sometimes MED writes -1, but normally only if there is only // one skin assigned. No warning in this case if(0xffffffff != iMatIndex) @@ -1324,10 +1253,8 @@ void MDLImporter::SortByMaterials_3DGS_MDL7( unsigned int iMatIndex2 = groupData.pcFaces[iFace].iMatIndex[1]; unsigned int iNum = iMatIndex; - if (0xffffffff != iMatIndex2 && iMatIndex != iMatIndex2) - { - if (iMatIndex2 >= iNumMaterials) - { + if (0xffffffff != iMatIndex2 && iMatIndex != iMatIndex2) { + if (iMatIndex2 >= iNumMaterials) { // sometimes MED writes -1, but normally only if there is only // one skin assigned. No warning in this case DefaultLogger::get()->warn("Index overflow in MDL7 material list [#2]"); @@ -1337,20 +1264,14 @@ void MDLImporter::SortByMaterials_3DGS_MDL7( // do a slow seach in the list ... iNum = 0; bool bFound = false; - for (std::vector::iterator - i = avMats.begin(); - i != avMats.end();++i,++iNum) - { - if ((*i).iOldMatIndices[0] == iMatIndex && - (*i).iOldMatIndices[1] == iMatIndex2) - { + for (std::vector::iterator i = avMats.begin();i != avMats.end();++i,++iNum){ + if ((*i).iOldMatIndices[0] == iMatIndex && (*i).iOldMatIndices[1] == iMatIndex2) { // reuse this material bFound = true; break; } } - if (!bFound) - { + if (!bFound) { // build a new material ... MDL::IntMaterial_MDL7 sHelper; sHelper.pcMat = new MaterialHelper(); @@ -1364,23 +1285,21 @@ void MDLImporter::SortByMaterials_3DGS_MDL7( iNum = (unsigned int)avMats.size()-1; } // adjust the size of the file array - if (iNum == aiTempSplit.size()) + if (iNum == aiTempSplit.size()) { aiTempSplit.push_back(new std::vector()); - + } } aiTempSplit[iNum]->push_back(iFace); } // now add the newly created materials to the old list - if (0 == groupInfo.iIndex) - { + if (0 == groupInfo.iIndex) { splittedGroupData.shared.pcMats.resize(avMats.size()); for (unsigned int o = 0; o < avMats.size();++o) splittedGroupData.shared.pcMats[o] = avMats[o].pcMat; } - else - { - // TODO: This might result in redundant materials ... + else { + // This might result in redundant materials ... splittedGroupData.shared.pcMats.resize(iNumMaterials + avMats.size()); for (unsigned int o = iNumMaterials; o < avMats.size();++o) splittedGroupData.shared.pcMats[o] = avMats[o].pcMat; @@ -1444,8 +1363,7 @@ void MDLImporter::InternReadFile_3DGS_MDL7( ) char* aszGroupNameBuffer = new char[AI_MDL7_MAX_GROUPNAMESIZE*pcHeader->groups_num]; // read all groups - for (unsigned int iGroup = 0; iGroup < (unsigned int)pcHeader->groups_num;++iGroup) - { + for (unsigned int iGroup = 0; iGroup < (unsigned int)pcHeader->groups_num;++iGroup) { MDL::IntGroupInfo_MDL7 groupInfo((BE_NCONST MDL::Group_MDL7*)szCurrent,iGroup); szCurrent = (const unsigned char*)(groupInfo.pcGroup+1); @@ -1458,8 +1376,7 @@ void MDLImporter::InternReadFile_3DGS_MDL7( ) AI_SWAP4(groupInfo.pcGroup->numverts); AI_SWAP4(groupInfo.pcGroup->numframes); - if (1 != groupInfo.pcGroup->typ) - { + if (1 != groupInfo.pcGroup->typ) { // Not a triangle-based mesh DefaultLogger::get()->warn("[3DGS MDL7] Not a triangle mesh group. Continuing happily"); } @@ -1477,13 +1394,11 @@ void MDLImporter::InternReadFile_3DGS_MDL7( ) sharedData.abNeedMaterials.resize(sharedData.abNeedMaterials.size() + groupInfo.pcGroup->numskins,false); - for (unsigned int iSkin = 0; iSkin < (unsigned int)groupInfo.pcGroup->numskins;++iSkin) - { - this->ParseSkinLump_3DGS_MDL7(szCurrent,&szCurrent,sharedData.pcMats); + for (unsigned int iSkin = 0; iSkin < (unsigned int)groupInfo.pcGroup->numskins;++iSkin) { + ParseSkinLump_3DGS_MDL7(szCurrent,&szCurrent,sharedData.pcMats); } // if we have absolutely no skin loaded we need to generate a default material - if (sharedData.pcMats.empty()) - { + if (sharedData.pcMats.empty()) { const int iMode = (int)aiShadingMode_Gouraud; sharedData.pcMats.push_back(new MaterialHelper()); MaterialHelper* pcHelper = (MaterialHelper*)sharedData.pcMats[0]; @@ -1527,7 +1442,6 @@ void MDLImporter::InternReadFile_3DGS_MDL7( ) //We can not swap the normal information now as we don't know which of the two kinds it is } szCurrent += pcHeader->mainvertex_stc_size * groupInfo.pcGroup->numverts; - VALIDATE_FILE_SIZE(szCurrent); MDL::IntSplittedGroupData_MDL7 splittedGroupData(sharedData,avOutList[iGroup]); @@ -1547,8 +1461,7 @@ void MDLImporter::InternReadFile_3DGS_MDL7( ) // check whether the triangle data structure is large enough // to contain a second UV coodinate set - if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_TWO_UV) - { + if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_TWO_UV) { groupData.vTextureCoords2.resize(iNumVertices,aiVector3D()); groupData.bNeed2UV = true; } @@ -1582,14 +1495,11 @@ void MDLImporter::InternReadFile_3DGS_MDL7( ) for (uint32_t i = 0; i < pcHeader->groups_num;++i) pScene->mNumMeshes += (unsigned int)avOutList[i].size(); - this->pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; - { + pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; { unsigned int p = 0,q = 0; - for (uint32_t i = 0; i < pcHeader->groups_num;++i) - { - for (unsigned int a = 0; a < avOutList[i].size();++a) - { - this->pScene->mMeshes[p++] = avOutList[i][a]; + for (uint32_t i = 0; i < pcHeader->groups_num;++i) { + for (unsigned int a = 0; a < avOutList[i].size();++a) { + pScene->mMeshes[p++] = avOutList[i][a]; } if (!avOutList[i].empty())++pScene->mRootNode->mNumChildren; } @@ -1619,8 +1529,7 @@ void MDLImporter::InternReadFile_3DGS_MDL7( ) } // if there is only one root node with a single child we can optimize it a bit ... - if (1 == pScene->mRootNode->mNumChildren && !sharedData.apcOutBones) - { + if (1 == pScene->mRootNode->mNumChildren && !sharedData.apcOutBones) { aiNode* pcOldRoot = this->pScene->mRootNode; pScene->mRootNode = pcOldRoot->mChildren[0]; pcOldRoot->mChildren[0] = NULL; @@ -1639,8 +1548,7 @@ void MDLImporter::InternReadFile_3DGS_MDL7( ) HandleMaterialReferences_3DGS_MDL7(); // generate output bone animations and add all bones to the scenegraph - if (sharedData.apcOutBones) - { + if (sharedData.apcOutBones) { // this step adds empty dummy bones to the nodegraph // insert another dummy node to avoid name conflicts aiNode* const pc = pScene->mRootNode->mChildren[pScene->mRootNode->mNumChildren-1] = new aiNode(); @@ -1656,7 +1564,9 @@ void MDLImporter::InternReadFile_3DGS_MDL7( ) sharedData.apcOutBones); } } + // ------------------------------------------------------------------------------------------------ +// Copy materials void MDLImporter::CopyMaterials_3DGS_MDL7(MDL::IntSharedData_MDL7 &shared) { pScene->mNumMaterials = (unsigned int)shared.pcMats.size(); @@ -1665,29 +1575,27 @@ void MDLImporter::CopyMaterials_3DGS_MDL7(MDL::IntSharedData_MDL7 &shared) pScene->mMaterials[i] = shared.pcMats[i]; } + // ------------------------------------------------------------------------------------------------ +// Process material references void MDLImporter::HandleMaterialReferences_3DGS_MDL7() { // search for referrer materials - for (unsigned int i = 0; i < pScene->mNumMaterials;++i) - { + for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { int iIndex = 0; - if (AI_SUCCESS == aiGetMaterialInteger(pScene->mMaterials[i], - AI_MDL7_REFERRER_MATERIAL, &iIndex) ) - { - for (unsigned int a = 0; a < pScene->mNumMeshes;++a) - { + if (AI_SUCCESS == aiGetMaterialInteger(pScene->mMaterials[i],AI_MDL7_REFERRER_MATERIAL, &iIndex) ) { + for (unsigned int a = 0; a < pScene->mNumMeshes;++a) { aiMesh* const pcMesh = pScene->mMeshes[a]; - if (i == pcMesh->mMaterialIndex) + if (i == pcMesh->mMaterialIndex) { pcMesh->mMaterialIndex = iIndex; + } } // collapse the rest of the array delete pScene->mMaterials[i]; - for (unsigned int pp = i; pp < pScene->mNumMaterials-1;++pp) - { - this->pScene->mMaterials[pp] = pScene->mMaterials[pp+1]; - for (unsigned int a = 0; a < pScene->mNumMeshes;++a) - { + for (unsigned int pp = i; pp < pScene->mNumMaterials-1;++pp) { + + pScene->mMaterials[pp] = pScene->mMaterials[pp+1]; + for (unsigned int a = 0; a < pScene->mNumMeshes;++a) { aiMesh* const pcMesh = pScene->mMeshes[a]; if (pcMesh->mMaterialIndex > i)--pcMesh->mMaterialIndex; } @@ -1707,18 +1615,15 @@ void MDLImporter::ParseBoneTrafoKeys_3DGS_MDL7( const MDL::Header_MDL7* const pcHeader = (const MDL::Header_MDL7*)this->mBuffer; // only the first group contains bone animation keys - if (frame.pcFrame->transmatrix_count) - { - if (!groupInfo.iIndex) - { + if (frame.pcFrame->transmatrix_count) { + if (!groupInfo.iIndex) { // skip all frames vertices. We can't support them const MDL::BoneTransform_MDL7* pcBoneTransforms = (const MDL::BoneTransform_MDL7*) (((const char*)frame.pcFrame) + pcHeader->frame_stc_size + frame.pcFrame->vertices_count * pcHeader->framevertex_stc_size); // read all transformation matrices - for (unsigned int iTrafo = 0; iTrafo < frame.pcFrame->transmatrix_count;++iTrafo) - { + for (unsigned int iTrafo = 0; iTrafo < frame.pcFrame->transmatrix_count;++iTrafo) { if(pcBoneTransforms->bone_index >= pcHeader->bones_num) { DefaultLogger::get()->warn("Index overflow in frame area. " "Unable to parse this bone transformation"); @@ -1731,10 +1636,8 @@ void MDLImporter::ParseBoneTrafoKeys_3DGS_MDL7( (const char*)pcBoneTransforms + pcHeader->bonetrans_stc_size); } } - else - { - DefaultLogger::get()->warn("Found animation keyframes " - "in a group that is not the first. They will be igored"); + else { + DefaultLogger::get()->warn("Ignoring animation keyframes in groups != 0"); } } } @@ -1750,22 +1653,24 @@ void MDLImporter::AddBonesToNodeGraph_3DGS_MDL7(const MDL::IntBone_MDL7** apcBon const MDL::Header_MDL7* const pcHeader = (const MDL::Header_MDL7*)this->mBuffer; const MDL::IntBone_MDL7** apcBones2 = apcBones; - for (uint32_t i = 0; i < pcHeader->bones_num;++i) - { + for (uint32_t i = 0; i < pcHeader->bones_num;++i) { + const MDL::IntBone_MDL7* const pcBone = *apcBones2++; - if (pcBone->iParent == iParentIndex)++pcParent->mNumChildren; + if (pcBone->iParent == iParentIndex) { + ++pcParent->mNumChildren; + } } pcParent->mChildren = new aiNode*[pcParent->mNumChildren]; unsigned int qq = 0; - for (uint32_t i = 0; i < pcHeader->bones_num;++i) - { + for (uint32_t i = 0; i < pcHeader->bones_num;++i) { + const MDL::IntBone_MDL7* const pcBone = *apcBones++; if (pcBone->iParent != iParentIndex)continue; aiNode* pcNode = pcParent->mChildren[qq++] = new aiNode(); pcNode->mName = aiString( pcBone->mName ); - this->AddBonesToNodeGraph_3DGS_MDL7(apcBones,pcNode,(uint16_t)i); + AddBonesToNodeGraph_3DGS_MDL7(apcBones,pcNode,(uint16_t)i); } } @@ -1779,28 +1684,23 @@ void MDLImporter::BuildOutputAnims_3DGS_MDL7( // one animation ... aiAnimation* pcAnim = new aiAnimation(); - for (uint32_t i = 0; i < pcHeader->bones_num;++i) - { - if (!apcBonesOut[i]->pkeyPositions.empty()) - { + for (uint32_t i = 0; i < pcHeader->bones_num;++i) { + if (!apcBonesOut[i]->pkeyPositions.empty()) { + // get the last frame ... (needn't be equal to pcHeader->frames_num) - for (size_t qq = 0; qq < apcBonesOut[i]->pkeyPositions.size();++qq) - { + for (size_t qq = 0; qq < apcBonesOut[i]->pkeyPositions.size();++qq) { pcAnim->mDuration = std::max(pcAnim->mDuration, (double) apcBonesOut[i]->pkeyPositions[qq].mTime); } ++pcAnim->mNumChannels; } } - if (pcAnim->mDuration) - { + if (pcAnim->mDuration) { pcAnim->mChannels = new aiNodeAnim*[pcAnim->mNumChannels]; unsigned int iCnt = 0; - for (uint32_t i = 0; i < pcHeader->bones_num;++i) - { - if (!apcBonesOut[i]->pkeyPositions.empty()) - { + for (uint32_t i = 0; i < pcHeader->bones_num;++i) { + if (!apcBonesOut[i]->pkeyPositions.empty()) { const MDL::IntBone_MDL7* const intBone = apcBonesOut[i]; aiNodeAnim* const pcNodeAnim = pcAnim->mChannels[iCnt++] = new aiNodeAnim(); @@ -1816,8 +1716,7 @@ void MDLImporter::BuildOutputAnims_3DGS_MDL7( pcNodeAnim->mRotationKeys = new aiQuatKey[pcNodeAnim->mNumPositionKeys]; // copy all keys - for (unsigned int qq = 0; qq < pcNodeAnim->mNumPositionKeys;++qq) - { + for (unsigned int qq = 0; qq < pcNodeAnim->mNumPositionKeys;++qq) { pcNodeAnim->mPositionKeys[qq] = intBone->pkeyPositions[qq]; pcNodeAnim->mScalingKeys[qq] = intBone->pkeyScalings[qq]; pcNodeAnim->mRotationKeys[qq] = intBone->pkeyRotations[qq]; @@ -1863,8 +1762,7 @@ void MDLImporter::AddAnimationBoneTrafoKey_3DGS_MDL7(unsigned int iTrafo, aiVectorKey vScaling,vPosition; aiQuatKey qRotation; - // FIXME: Decompose will assert in debug builds if the - // matrix is invalid ... + // FIXME: Decompose will assert in debug builds if the matrix is invalid ... mTransform.Decompose(vScaling.mValue,qRotation.mValue,vPosition.mValue); // now generate keys @@ -1889,10 +1787,9 @@ void MDLImporter::GenerateOutputMeshes_3DGS_MDL7( const MDL::Header_MDL7* const pcHeader = (const MDL::Header_MDL7*)this->mBuffer; const unsigned int iNumOutBones = pcHeader->bones_num; - for (std::vector::size_type i = 0; i < shared.pcMats.size();++i) - { - if (!splittedGroupData.aiSplit[i]->empty()) - { + for (std::vector::size_type i = 0; i < shared.pcMats.size();++i) { + if (!splittedGroupData.aiSplit[i]->empty()) { + // allocate the output mesh aiMesh* pcMesh = new aiMesh(); @@ -1907,12 +1804,10 @@ void MDLImporter::GenerateOutputMeshes_3DGS_MDL7( pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices]; pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices]; - if (!groupData.vTextureCoords1.empty()) - { + if (!groupData.vTextureCoords1.empty()) { pcMesh->mNumUVComponents[0] = 2; pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices]; - if (!groupData.vTextureCoords2.empty()) - { + if (!groupData.vTextureCoords2.empty()) { pcMesh->mNumUVComponents[1] = 2; pcMesh->mTextureCoords[1] = new aiVector3D[pcMesh->mNumVertices]; } @@ -1920,8 +1815,7 @@ void MDLImporter::GenerateOutputMeshes_3DGS_MDL7( // iterate through all faces and build an unique set of vertices unsigned int iCurrent = 0; - for (unsigned int iFace = 0; iFace < pcMesh->mNumFaces;++iFace) - { + for (unsigned int iFace = 0; iFace < pcMesh->mNumFaces;++iFace) { pcMesh->mFaces[iFace].mNumIndices = 3; pcMesh->mFaces[iFace].mIndices = new unsigned int[3]; @@ -1929,17 +1823,15 @@ void MDLImporter::GenerateOutputMeshes_3DGS_MDL7( const MDL::IntFace_MDL7& oldFace = groupData.pcFaces[iSrcFace]; // iterate through all face indices - for (unsigned int c = 0; c < 3;++c) - { + for (unsigned int c = 0; c < 3;++c) { const uint32_t iIndex = oldFace.mIndices[c]; pcMesh->mVertices[iCurrent] = groupData.vPositions[iIndex]; pcMesh->mNormals[iCurrent] = groupData.vNormals[iIndex]; - if (!groupData.vTextureCoords1.empty()) - { + if (!groupData.vTextureCoords1.empty()) { + pcMesh->mTextureCoords[0][iCurrent] = groupData.vTextureCoords1[iIndex]; - if (!groupData.vTextureCoords2.empty()) - { + if (!groupData.vTextureCoords2.empty()) { pcMesh->mTextureCoords[1][iCurrent] = groupData.vTextureCoords2[iIndex]; } } @@ -1949,25 +1841,20 @@ void MDLImporter::GenerateOutputMeshes_3DGS_MDL7( // if we have bones in the mesh we'll need to generate // proper vertex weights for them - if (!groupData.aiBones.empty()) - { + if (!groupData.aiBones.empty()) { std::vector > aaiVWeightList; aaiVWeightList.resize(iNumOutBones); int iCurrent = 0; - for (unsigned int iFace = 0; iFace < pcMesh->mNumFaces;++iFace) - { + for (unsigned int iFace = 0; iFace < pcMesh->mNumFaces;++iFace) { unsigned int iSrcFace = splittedGroupData.aiSplit[i]->operator[](iFace); const MDL::IntFace_MDL7& oldFace = groupData.pcFaces[iSrcFace]; // iterate through all face indices - for (unsigned int c = 0; c < 3;++c) - { + for (unsigned int c = 0; c < 3;++c) { unsigned int iBone = groupData.aiBones[ oldFace.mIndices[c] ]; - if (0xffffffff != iBone) - { - if (iBone >= iNumOutBones) - { + if (0xffffffff != iBone) { + if (iBone >= iNumOutBones) { DefaultLogger::get()->error("Bone index overflow. " "The bone index of a vertex exceeds the allowed range. "); iBone = iNumOutBones-1; @@ -1978,19 +1865,17 @@ void MDLImporter::GenerateOutputMeshes_3DGS_MDL7( } } // now check which bones are required ... - for (std::vector >::const_iterator - kimmi = aaiVWeightList.begin(); - kimmi != aaiVWeightList.end();++kimmi) - { - if (!(*kimmi).empty())++pcMesh->mNumBones; + for (std::vector >::const_iterator k = aaiVWeightList.begin();k != aaiVWeightList.end();++k) { + if (!(*k).empty()) { + ++pcMesh->mNumBones; + } } pcMesh->mBones = new aiBone*[pcMesh->mNumBones]; iCurrent = 0; - for (std::vector >::const_iterator - kimmi = aaiVWeightList.begin(); - kimmi != aaiVWeightList.end();++kimmi,++iCurrent) + for (std::vector >::const_iterator k = aaiVWeightList.begin();k!= aaiVWeightList.end();++k,++iCurrent) { - if ((*kimmi).empty())continue; + if ((*k).empty()) + continue; // seems we'll need this node aiBone* pcBone = pcMesh->mBones[ iCurrent ] = new aiBone(); @@ -1998,12 +1883,11 @@ void MDLImporter::GenerateOutputMeshes_3DGS_MDL7( pcBone->mOffsetMatrix = shared.apcOutBones[ iCurrent ]->mOffsetMatrix; // setup vertex weights - pcBone->mNumWeights = (unsigned int)(*kimmi).size(); + pcBone->mNumWeights = (unsigned int)(*k).size(); pcBone->mWeights = new aiVertexWeight[pcBone->mNumWeights]; - for (unsigned int weight = 0; weight < pcBone->mNumWeights;++weight) - { - pcBone->mWeights[weight].mVertexId = (*kimmi)[weight]; + for (unsigned int weight = 0; weight < pcBone->mNumWeights;++weight) { + pcBone->mWeights[weight].mVertexId = (*k)[weight]; pcBone->mWeights[weight].mWeight = 1.0f; } } @@ -2032,10 +1916,8 @@ void MDLImporter::JoinSkins_3DGS_MDL7( // then extract the diffuse texture from the second skin, // setup 1 as UV source and we have it - aiString sString; - if(AI_SUCCESS == aiGetMaterialString ( pcMat2, AI_MATKEY_TEXTURE_DIFFUSE(0),&sString )) - { + if(AI_SUCCESS == aiGetMaterialString ( pcMat2, AI_MATKEY_TEXTURE_DIFFUSE(0),&sString )) { iVal = 1; pcMatOut->AddProperty(&iVal,1,AI_MATKEY_UVWSRC_DIFFUSE(1)); pcMatOut->AddProperty(&sString,AI_MATKEY_TEXTURE_DIFFUSE(1)); diff --git a/code/PlyLoader.cpp b/code/PlyLoader.cpp index cea27033c..e2cb649d9 100644 --- a/code/PlyLoader.cpp +++ b/code/PlyLoader.cpp @@ -338,23 +338,18 @@ void PLYImporter::ReplaceDefaultMaterial(std::vector* avFaces, { bool bNeedDefaultMat = false; - for (std::vector::iterator - i = avFaces->begin();i != avFaces->end();++i) - { - if (0xFFFFFFFF == (*i).iMaterialIndex) - { + for (std::vector::iterator i = avFaces->begin();i != avFaces->end();++i) { + if (0xFFFFFFFF == (*i).iMaterialIndex) { bNeedDefaultMat = true; (*i).iMaterialIndex = (unsigned int)avMaterials->size(); } - else if ((*i).iMaterialIndex >= avMaterials->size() ) - { + else if ((*i).iMaterialIndex >= avMaterials->size() ) { // clamp the index (*i).iMaterialIndex = (unsigned int)avMaterials->size()-1; } } - if (bNeedDefaultMat) - { + if (bNeedDefaultMat) { // generate a default material MaterialHelper* pcHelper = new MaterialHelper(); @@ -370,6 +365,11 @@ void PLYImporter::ReplaceDefaultMaterial(std::vector* avFaces, clr.b = clr.g = clr.r = 0.05f; pcHelper->AddProperty(&clr, 1,AI_MATKEY_COLOR_AMBIENT); + // The face order is absolutely undefined for PLY, so we have to + // use two-sided rendering to be sure it's ok. + const int two_sided = 1; + pcHelper->AddProperty(&two_sided,1,AI_MATKEY_TWOSIDED); + avMaterials->push_back(pcHelper); } } @@ -997,11 +997,8 @@ void PLYImporter::LoadMaterial(std::vector* pvOut) } } // check whether we have a valid source for the material data - if (NULL != pcList) - { - for (std::vector::const_iterator i = pcList->alInstances.begin(); - i != pcList->alInstances.end();++i) - { + if (NULL != pcList) { + for (std::vector::const_iterator i = pcList->alInstances.begin();i != pcList->alInstances.end();++i) { aiColor4D clrOut; MaterialHelper* pcHelper = new MaterialHelper(); @@ -1019,16 +1016,12 @@ void PLYImporter::LoadMaterial(std::vector* pvOut) // handle phong power and shading mode int iMode; - if (0xFFFFFFFF != iPhong) - { - float fSpec = PLY::PropertyInstance::ConvertTo( - (*i).alProperties[iPhong].avList.front(),ePhong); + if (0xFFFFFFFF != iPhong) { + float fSpec = PLY::PropertyInstance::ConvertTo((*i).alProperties[iPhong].avList.front(),ePhong); // if shininess is 0 (and the pow() calculation would therefore always - // become 1, not depending on the angle) use gouraud lighting - if (fSpec) - { - + // become 1, not depending on the angle), use gouraud lighting + if (fSpec) { // scale this with 15 ... hopefully this is correct fSpec *= 15; pcHelper->AddProperty(&fSpec, 1, AI_MATKEY_SHININESS); @@ -1041,14 +1034,16 @@ void PLYImporter::LoadMaterial(std::vector* pvOut) pcHelper->AddProperty(&iMode, 1, AI_MATKEY_SHADING_MODEL); // handle opacity - if (0xFFFFFFFF != iOpacity) - { - float fOpacity = PLY::PropertyInstance::ConvertTo( - (*i).alProperties[iPhong].avList.front(),eOpacity); - + if (0xFFFFFFFF != iOpacity) { + float fOpacity = PLY::PropertyInstance::ConvertTo((*i).alProperties[iPhong].avList.front(),eOpacity); pcHelper->AddProperty(&fOpacity, 1, AI_MATKEY_OPACITY); } + // The face order is absolutely undefined for PLY, so we have to + // use two-sided rendering to be sure it's ok. + const int two_sided = 1; + pcHelper->AddProperty(&two_sided,1,AI_MATKEY_TWOSIDED); + // add the newly created material instance to the list pvOut->push_back(pcHelper); } diff --git a/code/ScenePreprocessor.cpp b/code/ScenePreprocessor.cpp index e678cc602..9f3dad43f 100644 --- a/code/ScenePreprocessor.cpp +++ b/code/ScenePreprocessor.cpp @@ -62,8 +62,7 @@ void ScenePreprocessor::ProcessScene () ProcessAnimation(scene->mAnimations[i]); // Generate a default material if none was specified - if (!scene->mNumMaterials && scene->mNumMeshes) - { + if (!scene->mNumMaterials && scene->mNumMeshes) { scene->mMaterials = new aiMaterial*[2]; MaterialHelper* helper; @@ -76,13 +75,11 @@ void ScenePreprocessor::ProcessScene () if (scene->mMeshes[i]->mTextureCoords[0]) { if (mat0 == 0xffffffff) { - scene->mMaterials[scene->mNumMaterials] = helper = new MaterialHelper(); - // dummy texture - name.Set("texture.png"); + scene->mMaterials[scene->mNumMaterials] = helper = new MaterialHelper(); + name.Set("$texture.png"); helper->AddProperty(&name,AI_MATKEY_TEXTURE_DIFFUSE(0)); - // setup default name name.Set(AI_DEFAULT_TEXTURED_MATERIAL_NAME); helper->AddProperty(&name,AI_MATKEY_NAME); @@ -94,16 +91,11 @@ void ScenePreprocessor::ProcessScene () else { if (mat1 == 0xffffffff) { - scene->mMaterials[scene->mNumMaterials] = helper = new MaterialHelper(); - // gray + scene->mMaterials[scene->mNumMaterials] = helper = new MaterialHelper(); aiColor3D clr(0.6f,0.6f,0.6f); helper->AddProperty(&clr,1,AI_MATKEY_COLOR_DIFFUSE); - // add a small ambient color value - clr = aiColor3D(0.05f,0.05f,0.05f); - helper->AddProperty(&clr,1,AI_MATKEY_COLOR_AMBIENT); - // setup the default name name.Set(AI_DEFAULT_MATERIAL_NAME); helper->AddProperty(&name,AI_MATKEY_NAME); @@ -121,8 +113,7 @@ void ScenePreprocessor::ProcessScene () void ScenePreprocessor::ProcessMesh (aiMesh* mesh) { // If aiMesh::mNumUVComponents is *not* set assign the default value of 2 - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) - { + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { if (!mesh->mTextureCoords[i]) mesh->mNumUVComponents[i] = 0; @@ -146,10 +137,8 @@ void ScenePreprocessor::ProcessMesh (aiMesh* mesh) // If the information which primitive types are there in the // mesh is currently not available, compute it. - if (!mesh->mPrimitiveTypes) - { - for (unsigned int a = 0; a < mesh->mNumFaces; ++a) - { + if (!mesh->mPrimitiveTypes) { + for (unsigned int a = 0; a < mesh->mNumFaces; ++a) { aiFace& face = mesh->mFaces[a]; switch (face.mNumIndices) { @@ -173,8 +162,8 @@ void ScenePreprocessor::ProcessMesh (aiMesh* mesh) } // If tangents and normals are given but no bitangents compute them - if (mesh->mTangents && mesh->mNormals && !mesh->mBitangents) - { + if (mesh->mTangents && mesh->mNormals && !mesh->mBitangents) { + mesh->mBitangents = new aiVector3D[mesh->mNumVertices]; for (unsigned int i = 0; i < mesh->mNumVertices;++i) { mesh->mBitangents[i] = mesh->mNormals[i] ^ mesh->mTangents[i]; @@ -186,34 +175,30 @@ void ScenePreprocessor::ProcessMesh (aiMesh* mesh) void ScenePreprocessor::ProcessAnimation (aiAnimation* anim) { double first = 10e10, last = -10e10; - for (unsigned int i = 0; i < anim->mNumChannels;++i) - { + for (unsigned int i = 0; i < anim->mNumChannels;++i) { aiNodeAnim* channel = anim->mChannels[i]; /* If the exact duration of the animation is not given * compute it now. */ - if (anim->mDuration == -1.) - { + if (anim->mDuration == -1.) { + // Position keys - for (unsigned int i = 0; i < channel->mNumPositionKeys;++i) - { + for (unsigned int i = 0; i < channel->mNumPositionKeys;++i) { aiVectorKey& key = channel->mPositionKeys[i]; first = std::min (first, key.mTime); last = std::max (last, key.mTime); } // Scaling keys - for (unsigned int i = 0; i < channel->mNumScalingKeys;++i) - { + for (unsigned int i = 0; i < channel->mNumScalingKeys;++i) { aiVectorKey& key = channel->mScalingKeys[i]; first = std::min (first, key.mTime); last = std::max (last, key.mTime); } // Rotation keys - for (unsigned int i = 0; i < channel->mNumRotationKeys;++i) - { + for (unsigned int i = 0; i < channel->mNumRotationKeys;++i) { aiQuatKey& key = channel->mRotationKeys[i]; first = std::min (first, key.mTime); last = std::max (last, key.mTime); @@ -225,8 +210,7 @@ void ScenePreprocessor::ProcessAnimation (aiAnimation* anim) * track from the information we have in the transformation * matrix of the corresponding node. */ - if (!channel->mNumRotationKeys || !channel->mNumPositionKeys || !channel->mNumScalingKeys) - { + if (!channel->mNumRotationKeys || !channel->mNumPositionKeys || !channel->mNumScalingKeys) { // Find the node that belongs to this animation aiNode* node = scene->mRootNode->FindNode(channel->mNodeName); if (node) // ValidateDS will complain later if 'node' is NULL @@ -238,8 +222,7 @@ void ScenePreprocessor::ProcessAnimation (aiAnimation* anim) node->mTransformation.Decompose(scaling, rotation,position); // No rotation keys? Generate a dummy track - if (!channel->mNumRotationKeys) - { + if (!channel->mNumRotationKeys) { channel->mNumRotationKeys = 1; channel->mRotationKeys = new aiQuatKey[1]; aiQuatKey& q = channel->mRotationKeys[0]; @@ -251,8 +234,7 @@ void ScenePreprocessor::ProcessAnimation (aiAnimation* anim) } // No scaling keys? Generate a dummy track - if (!channel->mNumScalingKeys) - { + if (!channel->mNumScalingKeys) { channel->mNumScalingKeys = 1; channel->mScalingKeys = new aiVectorKey[1]; aiVectorKey& q = channel->mScalingKeys[0]; @@ -264,8 +246,7 @@ void ScenePreprocessor::ProcessAnimation (aiAnimation* anim) } // No position keys? Generate a dummy track - if (!channel->mNumPositionKeys) - { + if (!channel->mNumPositionKeys) { channel->mNumPositionKeys = 1; channel->mPositionKeys = new aiVectorKey[1]; aiVectorKey& q = channel->mPositionKeys[0]; @@ -278,9 +259,9 @@ void ScenePreprocessor::ProcessAnimation (aiAnimation* anim) } } } - if (anim->mDuration == -1.) - { - DefaultLogger::get()->debug("Setting animation duration"); + + if (anim->mDuration == -1.) { + DefaultLogger::get()->debug("ScenePreprocessor: Setting animation duration"); anim->mDuration = last - std::min( first, 0. ); } } diff --git a/code/UnrealLoader.cpp b/code/UnrealLoader.cpp index 760cb6a7b..6ac898fea 100644 --- a/code/UnrealLoader.cpp +++ b/code/UnrealLoader.cpp @@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "StreamReader.h" #include "ParsingUtils.h" #include "fast_atof.h" +#include "ConvertToLHProcess.h" using namespace Assimp; @@ -107,14 +108,10 @@ void UnrealImporter::InternReadFile( const std::string& pFile, // For any of the 3 files being passed get the three correct paths // First of all, determine file extension std::string::size_type pos = pFile.find_last_of('.'); - std::string extension = pFile.substr( pos); - - for( std::string::iterator it = extension.begin(); it != extension.end(); ++it) - *it = tolower( *it); + std::string extension = GetExtension(pFile); std::string d_path,a_path,uc_path; - if (extension == ".3d") - { + if (extension == "3d") { // jjjj_d.3d // jjjj_a.3d pos = pFile.find_last_of('_'); @@ -123,8 +120,7 @@ void UnrealImporter::InternReadFile( const std::string& pFile, } extension = pFile.substr(0,pos); } - else // if (extension == ".uc") - { + else { extension = pFile.substr(0,pos); } @@ -154,16 +150,13 @@ void UnrealImporter::InternReadFile( const std::string& pFile, // collect triangles std::vector triangles(numTris); - for (std::vector::iterator it = triangles.begin(), end = triangles.end(); - it != end; ++it) - { + for (std::vector::iterator it = triangles.begin(), end = triangles.end();it != end; ++it) { Unreal::Triangle& tri = *it; - for (unsigned int i = 0; i < 3;++i) - { + for (unsigned int i = 0; i < 3;++i) { + tri.mVertex[i] = d_reader.GetI2(); - if (tri.mVertex[i] >= numTris) - { + if (tri.mVertex[i] >= numTris) { DefaultLogger::get()->warn("UNREAL: vertex index out of range"); tri.mVertex[i] = 0; } @@ -208,9 +201,7 @@ void UnrealImporter::InternReadFile( const std::string& pFile, // collect vertices std::vector vertices(numVert); - for (std::vector::iterator it = vertices.begin(), end = vertices.end(); - it != end; ++it) - { + for (std::vector::iterator it = vertices.begin(), end = vertices.end(); it != end; ++it) { int32_t val = a_reader.GetI4(); Unreal::DecompressVertex(*it,val); } @@ -236,8 +227,7 @@ void UnrealImporter::InternReadFile( const std::string& pFile, std::vector< std::pair< std::string,std::string > > tempTextures; // do a quick search in the UC file for some known, usually texture-related, tags - for (;*data;++data) - { + for (;*data;++data) { if (TokenMatchI(data,"#exec",5)) { SkipSpacesAndLineEnd(&data); @@ -245,20 +235,16 @@ void UnrealImporter::InternReadFile( const std::string& pFile, if (TokenMatchI(data,"TEXTURE",7)) { SkipSpacesAndLineEnd(&data); - if (TokenMatchI(data,"IMPORT",6)) - { + if (TokenMatchI(data,"IMPORT",6)) { tempTextures.push_back(std::pair< std::string,std::string >()); std::pair< std::string,std::string >& me = tempTextures.back(); - for (;!IsLineEnd(*data);++data) - { - if (!::ASSIMP_strincmp(data,"NAME=",5)) - { + for (;!IsLineEnd(*data);++data) { + if (!::ASSIMP_strincmp(data,"NAME=",5)) { const char *d = data+=5; for (;!IsSpaceOrNewLine(*data);++data); me.first = std::string(d,(size_t)(data-d)); } - else if (!::ASSIMP_strincmp(data,"FILE=",5)) - { + else if (!::ASSIMP_strincmp(data,"FILE=",5)) { const char *d = data+=5; for (;!IsSpaceOrNewLine(*data);++data); me.second = std::string(d,(size_t)(data-d)); @@ -279,13 +265,11 @@ void UnrealImporter::InternReadFile( const std::string& pFile, std::pair& me = textures.back(); for (;!IsLineEnd(*data);++data) { - if (!::ASSIMP_strincmp(data,"NUM=",4)) - { + if (!::ASSIMP_strincmp(data,"NUM=",4)) { data += 4; me.first = strtol10(data,&data); } - else if (!::ASSIMP_strincmp(data,"TEXTURE=",8)) - { + else if (!::ASSIMP_strincmp(data,"TEXTURE=",8)) { data += 8; const char *d = data; for (;!IsSpaceOrNewLine(*data);++data); @@ -293,10 +277,8 @@ void UnrealImporter::InternReadFile( const std::string& pFile, // try to find matching path names, doesn't care if we don't find them for (std::vector< std::pair< std::string,std::string > >::const_iterator it = tempTextures.begin(); - it != tempTextures.end(); ++it) - { - if ((*it).first == me.second) - { + it != tempTextures.end(); ++it) { + if ((*it).first == me.second) { me.second = (*it).second; break; } @@ -330,9 +312,7 @@ void UnrealImporter::InternReadFile( const std::string& pFile, materials.reserve(textures.size()*2+5); // find out how many output meshes and materials we'll have and build material indices - for (std::vector::iterator it = triangles.begin(), end = triangles.end(); - it != end; ++it) - { + for (std::vector::iterator it = triangles.begin(), end = triangles.end();it != end; ++it) { Unreal::Triangle& tri = *it; Unreal::TempMat mat(tri); std::vector::iterator nt = std::find(materials.begin(),materials.end(),mat); @@ -389,8 +369,7 @@ void UnrealImporter::InternReadFile( const std::string& pFile, else ::strcat(s.data,"os_"); // make TRANS faces 90% opaque that RemRedundantMaterials won't catch us - if (materials[i].type == Unreal::MF_NORMAL_TRANS_TS) - { + if (materials[i].type == Unreal::MF_NORMAL_TRANS_TS) { const float opac = 0.9f; mat->AddProperty(&opac,1,AI_MATKEY_OPACITY); ::strcat(s.data,"tran_"); @@ -398,8 +377,7 @@ void UnrealImporter::InternReadFile( const std::string& pFile, else ::strcat(s.data,"opaq_"); // a special name for the weapon attachment point - if (materials[i].type == Unreal::MF_WEAPON_PLACEHOLDER) - { + if (materials[i].type == Unreal::MF_WEAPON_PLACEHOLDER) { s.length = ::sprintf(s.data,"$WeaponTag$"); color = aiColor3D(0.f,0.f,0.f); } @@ -411,11 +389,8 @@ void UnrealImporter::InternReadFile( const std::string& pFile, // set texture, if any const unsigned int tex = materials[i].tex; - for (std::vector< std::pair< unsigned int, std::string > >::const_iterator it = textures.begin(); - it != textures.end();++it) - { - if ((*it).first == tex) - { + for (std::vector< std::pair< unsigned int, std::string > >::const_iterator it = textures.begin();it != textures.end();++it) { + if ((*it).first == tex) { s.Set((*it).second); mat->AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0)); break; @@ -424,9 +399,7 @@ void UnrealImporter::InternReadFile( const std::string& pFile, } // fill them. - for (std::vector::iterator it = triangles.begin(), end = triangles.end(); - it != end; ++it) - { + for (std::vector::iterator it = triangles.begin(), end = triangles.end();it != end; ++it) { Unreal::Triangle& tri = *it; Unreal::TempMat mat(tri); std::vector::iterator nt = std::find(materials.begin(),materials.end(),mat); @@ -435,14 +408,17 @@ void UnrealImporter::InternReadFile( const std::string& pFile, aiFace& f = mesh->mFaces[mesh->mNumFaces++]; f.mIndices = new unsigned int[f.mNumIndices = 3]; - for (unsigned int i = 0; i < 3;++i,mesh->mNumVertices++) - { + for (unsigned int i = 0; i < 3;++i,mesh->mNumVertices++) { f.mIndices[i] = mesh->mNumVertices; mesh->mVertices[mesh->mNumVertices] = vertices[ tri.mVertex[i] ]; mesh->mTextureCoords[0][mesh->mNumVertices] = aiVector3D( tri.mTex[i][0] / 255.f, 1.f - tri.mTex[i][1] / 255.f, 0.f); } } + + // convert to RH + MakeLeftHandedProcess hero; + hero.Execute(pScene); } #endif // !! AI_BUILD_NO_3D_IMPORTER \ No newline at end of file diff --git a/code/XFileImporter.cpp b/code/XFileImporter.cpp index e634efd24..8c7b8f22b 100644 --- a/code/XFileImporter.cpp +++ b/code/XFileImporter.cpp @@ -47,7 +47,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "XFileImporter.h" #include "XFileParser.h" -#include "MaterialSystem.h" #include "ConvertToLHProcess.h" using namespace Assimp; @@ -141,9 +140,9 @@ void XFileImporter::CreateDataRepresentationFromImport( aiScene* pScene, const X CreateMeshes( pScene, pScene->mRootNode, pData->mGlobalMeshes); } - // convert the root node's transformation to OGL coords - if( pScene->mRootNode) - ConvertToLHProcess::ConvertToOGL( pScene->mRootNode->mTransformation); + // Convert everything to OpenGL space... it's the same operation as the conversion back, so we can reuse the step directly + MakeLeftHandedProcess convertProcess; + convertProcess.Execute( pScene); // finally: create a dummy material if not material was imported if( pScene->mNumMaterials == 0) @@ -305,7 +304,7 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec // collect vertex data for indices of this face for( unsigned int d = 0; d < df.mNumIndices; d++) { - df.mIndices[df.mNumIndices - 1 - d] = newIndex; // inverted face orientation for OGL + df.mIndices[d] = newIndex; orgPoints[newIndex] = pf.mIndices[d]; // Position @@ -313,6 +312,7 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec // Normal, if present if( mesh->HasNormals()) mesh->mNormals[newIndex] = sourceMesh->mNormals[sourceMesh->mNormFaces[f].mIndices[d]]; + // texture coord sets for( unsigned int e = 0; e < AI_MAX_NUMBER_OF_TEXTURECOORDS; e++) { @@ -413,9 +413,9 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData for( unsigned int a = 0; a < pData->mAnims.size(); a++) { const XFile::Animation* anim = pData->mAnims[a]; - // some exporters mock me with empty animation tags. - if( anim->mAnims.size() == 0) - continue; + // some exporters mock me with empty animation tags. + if( anim->mAnims.size() == 0) + continue; // create a new animation to hold the data aiAnimation* nanim = new aiAnimation; @@ -434,9 +434,6 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData nbone->mNodeName.Set( bone->mBoneName); nanim->mChannels[b] = nbone; - // apply the LH->RH conversion if the animation affects the root bone - bool isRootAnim = (bone->mBoneName == pScene->mRootNode->mName.data); - // keyframes are given as combined transformation matrix keys if( bone->mTrafoKeys.size() > 0) { @@ -455,8 +452,6 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData // extract position aiVector3D pos( trafo.a4, trafo.b4, trafo.c4); - if( isRootAnim) - ConvertToLHProcess::ConvertToOGL( pos); nbone->mPositionKeys[c].mTime = time; nbone->mPositionKeys[c].mValue = pos; @@ -475,9 +470,6 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData trafo.b1 / scale.x, trafo.b2 / scale.y, trafo.b3 / scale.z, trafo.c1 / scale.x, trafo.c2 / scale.y, trafo.c3 / scale.z); - if( isRootAnim) - ConvertToLHProcess::ConvertToOGL( rotmat); - // and convert it into a quaternion nbone->mRotationKeys[c].mTime = time; nbone->mRotationKeys[c].mValue = aiQuaternion( rotmat); @@ -493,8 +485,6 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData for( unsigned int c = 0; c < nbone->mNumPositionKeys; c++) { aiVector3D pos = bone->mPosKeys[c].mValue; - if( isRootAnim) - ConvertToLHProcess::ConvertToOGL( pos); nbone->mPositionKeys[c].mTime = bone->mPosKeys[c].mTime; nbone->mPositionKeys[c].mValue = pos; @@ -506,8 +496,6 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData for( unsigned int c = 0; c < nbone->mNumRotationKeys; c++) { aiMatrix3x3 rotmat = bone->mRotKeys[c].mValue.GetMatrix(); - if( isRootAnim) - ConvertToLHProcess::ConvertToOGL( rotmat); nbone->mRotationKeys[c].mTime = bone->mRotKeys[c].mTime; nbone->mRotationKeys[c].mValue = aiQuaternion( rotmat); diff --git a/doc/AssimpDoc_Html/AssimpDoc.chm b/doc/AssimpDoc_Html/AssimpDoc.chm index 5fd440f66..9fe3d427e 100644 Binary files a/doc/AssimpDoc_Html/AssimpDoc.chm and b/doc/AssimpDoc_Html/AssimpDoc.chm differ diff --git a/doc/Doxyfile b/doc/Doxyfile index cc8d47200..25c691e12 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -31,7 +31,7 @@ PROJECT_NAME = assimp # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = r281 +PROJECT_NUMBER = r350 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. diff --git a/doc/dox.h b/doc/dox.h index 180cd2088..ab9edf4c1 100644 --- a/doc/dox.h +++ b/doc/dox.h @@ -17,7 +17,7 @@ processing steps to the imported data such as conversion to indexed meshes, calc or conversion from right-handed to left-handed coordinate systems. ASSIMP currently supports the following file formats (note that some loaders lack some features of their formats because -some file formats contain data not supported by Assimp, some stuff would require so much conversion work +some file formats contain data not supported by ASSIMP, some stuff would require so much conversion work that it has not yet been implemented, and some formats have not completely been documented by their inventors):

@@ -37,7 +37,7 @@ that it has not yet been implemented, and some formats have not completely been Quake II ( *.md2 )
Quake III ( *.md3 )
RtCW ( *.mdc )
-Doom 3 ( *.md5 ) 3
+Doom 3 ( *.md5mesh;*.md5anim;*.md5camera )
DirectX X ( *.x ).
Quick3D ( *.q3o;*q3s ).
Raw Triangles ( *.raw ).
@@ -51,7 +51,7 @@ that it has not yet been implemented, and some formats have not completely been 3D GameStudio Model ( *.mdl )
3D GameStudio Terrain ( *.hmp )


-3: These formats support animations, but Assimp doesn't yet support them (or they're buggy) +3: These formats support animations, but ASSIMP doesn't yet support them (or they're buggy)

@@ -115,9 +115,9 @@ assimp-discussions. @section install_prebuilt Using the pre-built libraries with Visual C++ 8/9 If you develop at Visual Studio 2005 or 2008, you can simply use the pre-built linker libraries provided in the distribution. -Extract all files to a place of your choice. A directory called "Assimp" will be created there. Add the Assimp/include path +Extract all files to a place of your choice. A directory called "ASSIMP" will be created there. Add the ASSIMP/include path to your include paths (Menu->Extras->Options->Projects and Solutions->VC++ Directories->Include files) -and the Assimp/lib/<Compiler> path to your linker paths (Menu->Extras->Options->Projects and Solutions->VC++ Directories->Library files). +and the ASSIMP/lib/<Compiler> path to your linker paths (Menu->Extras->Options->Projects and Solutions->VC++ Directories->Library files). This is neccessary only once to setup all paths inside you IDE. To use the library in your C++ project you have to include either <assimp.hpp> or <assimp.h> plus some others starting with <aiTypes.h>. @@ -140,7 +140,7 @@ various useful debug checks. Actually they are really helpful for debugging, but so extremely slow that they can make the STL up to 100 times slower (imagine a std::vector::operator[] performing 3 or 4 single checks! scary ...). -These security enhancements are - thanks MS! - also active in release builds, rendering Assimp several times +These security enhancements are - thanks MS! - also active in release builds, rendering ASSIMP several times slower. However, it is possible to disable them by defining @code @@ -149,14 +149,14 @@ _SECURE_SCL=0 @endcode in the preprocessor options (or alternatively in the source code, just before the STL is included for the first time). -Assimp's vc8 and vc9 configs enable these flags by default. +ASSIMP's vc8 and vc9 configs enable these flags by default. -If you're linking statically against Assimp: Make sure your applications uses the same STl settings! +If you're linking statically against ASSIMP: Make sure your applications uses the same STl settings! If you do not, there are two binary incompatible STL versions mangled together and you'll crash. -Alternatively you can disable the fast STL settings for Assimp by removing the 'FastSTL' property sheet from +Alternatively you can disable the fast STL settings for ASSIMP by removing the 'FastSTL' property sheet from the vc project file. -If you're using Assimp in a DLL: It's ok. There's no STL used in the DLL interface, so it doesn't care whether +If you're using ASSIMP in a DLL: It's ok. There's no STL used in the DLL interface, so it doesn't care whether your application uses the same STL settings or not.

Another option is to build against a different STL implementation, for example STlport. There's a special @@ -200,7 +200,7 @@ The Boost-Workaround consists of dummy replacements for some boost utility templ
  • boost.foreach
  • boost.tuple
  • -These implementations are very limited and are not intended for use outside Assimp. A compiler +These implementations are very limited and are not intended for use outside ASSIMP. A compiler with full support for partial template specializations is required. To enable the workaround, put the following in your compiler's list of predefined macros: @code @@ -220,26 +220,26 @@ for more details. @section assimp_dll DLL build -Assimp can be built as DLL. You just need to select a -dll config from the list of project +ASSIMP can be built as DLL. You just need to select a -dll config from the list of project configs and you're fine. Don't forget to copy the DLL to the directory of your executable :-) -NOTE: Theoretically Assimp-dll can be used with multithreaded (non-dll) runtime libraries, +NOTE: Theoretically ASSIMP-dll can be used with multithreaded (non-dll) runtime libraries, as long as you don't utilize any non-public stuff from the code dir. However, if you happen to encounter *very* strange problems try changing the runtime to multithreaded (Debug) DLL. @section assimp_stlport Building against STLport If your compiler's default implementation of the STL is too slow, lacks some features, -contains bugs or if you just want to tweak Assimp's performance a little try a build +contains bugs or if you just want to tweak ASSIMP's performance a little try a build against STLport. STLport is a free, fast and secure STL replacement that works with all major compilers and platforms. To get it visit their website at and download the latest STLport release. Usually you'll just need to run 'configure' + a makefile (see the README for more details). Don't miss to add /stlport to your compiler's default include paths - prior to the directory where the compiler vendor's STL lies. Do the same for /lib and -recompile Assimp. To ensure you're really building against STLport see aiGetCompileFlags(). +recompile ASSIMP. To ensure you're really building against STLport see aiGetCompileFlags().
    -Usually building Assimp against STLport yields a better overall performance so it might be +Usually building ASSIMP against STLport yields a better overall performance so it might be worth a try if the library is too slow for you. */ @@ -251,8 +251,8 @@ worth a try if the library is too slow for you. @section access_cpp Access by C++ class interface The ASSIMP library can be accessed by both a class or flat function interface. The C++ class -interface is the preferred way of interaction: you create an instance of class Assimp::Importer, -maybe adjust some settings of it and then call Assimp::Importer::ReadFile(). The class will +interface is the preferred way of interaction: you create an instance of class ASSIMP::Importer, +maybe adjust some settings of it and then call ASSIMP::Importer::ReadFile(). The class will read the files and process its data, handing back the imported data as a pointer to an aiScene to you. You can now extract the data you need from the file. The importer manages all the resources for itsself. If the importer is destroyed, all the data that was created/read by it will be @@ -269,7 +269,7 @@ C++ example: bool DoTheImportThing( const std::string& pFile) { // Create an instance of the Importer class - Assimp::Importer importer; + ASSIMP::Importer importer; // And have it read the given file with some example postprocessing // Usually - if speed is not the most important aspect for you - you'll @@ -358,7 +358,7 @@ custom implementations of IOStream and IOSystem. A shortened example might look #include // My own implementation of IOStream -class MyIOStream : public Assimp::IOStream +class MyIOStream : public ASSIMP::IOStream { friend class MyIOSystem; @@ -377,7 +377,7 @@ public: }; // Fisher Price - My First Filesystem -class MyIOSystem : public Assimp::IOSystem +class MyIOSystem : public ASSIMP::IOSystem { MyIOSystem() { ... } ~MyIOSystem() { ... } @@ -402,12 +402,12 @@ class MyIOSystem : public Assimp::IOSystem @endcode Now that your IO system is implemented, supply an instance of it to the Importer object by calling -Assimp::Importer::SetIOHandler(). +ASSIMP::Importer::SetIOHandler(). @code void DoTheImportThing( const std::string& pFile) { - Assimp::Importer importer; + ASSIMP::Importer importer; // put my custom IO handling in place importer.SetIOHandler( new MyIOSystem()); @@ -435,7 +435,7 @@ following prerequisites are fulfilled: See the @link assimp_st Single-threaded build section @endlink to learn how to build a lightweight variant -of Assimp which is not thread-safe and does not utilize multiple threads for loading. +of ASSIMP which is not thread-safe and does not utilize multiple threads for loading. @section logging Logging in the AssetImporter @@ -448,13 +448,13 @@ by calling it as a singleton with the requested logging-type. To see how this wo @code // Create a logger instance -Assimp::DefaultLogger::create("",Assimp::Logger::VERBOSE); +ASSIMP::DefaultLogger::create("",ASSIMP::Logger::VERBOSE); // Now I am ready for logging my stuff -Assimp::DefaultLogger::get()->info("this is my info-call"); +ASSIMP::DefaultLogger::get()->info("this is my info-call"); // Kill it after the work is done -Assimp::DefaultLogger::kill(); +ASSIMP::DefaultLogger::kill(); @endcode At first you have to create the default-logger-instance (create). Now you are ready to rock and can log a @@ -498,7 +498,7 @@ severity |= Logger::WARN; severity |= Logger::ERR; // Attaching it to the default logger -Assimp::DefaultLogger::get()->attachStream( new myStream(), severity ); +ASSIMP::DefaultLogger::get()->attachStream( new myStream(), severity ); @endcode @@ -514,7 +514,7 @@ unsigned int severity = 0; severity |= Logger::DEBUGGING; // Detach debug messages from you self defined stream -Assimp::DefaultLogger::get()->attachStream( new myStream(), severity ); +ASSIMP::DefaultLogger::get()->attachStream( new myStream(), severity ); @endcode @@ -541,7 +541,7 @@ In the verbose level debug messages will be logged, too. The ASSIMP library returns the imported data in a collection of structures. aiScene forms the root of the data, from here you gain access to all the nodes, meshes, materials, animations or textures that were read from the imported file. The aiScene is returned from a successful call to -Assimp::Importer::ReadFile(), aiImportFile() or aiImportFileEx() - see the @link usage Usage page @endlink +ASSIMP::Importer::ReadFile(), aiImportFile() or aiImportFileEx() - see the @link usage Usage page @endlink for further information on how to use the library. By default, all 3D data is provided in a right-handed coordinate system such as OpenGL uses. In @@ -549,7 +549,25 @@ this coordinate system, +X points to the right, +Y points away from the viewer i +Z points upwards. Several modeling packages such as 3D Studio Max use this coordinate system as well. By contrast, some other environments use left-handed coordinate systems, a prominent example being DirectX. If you need the imported data to be in a left-handed coordinate system, supply the -aiProcess_ConvertToLeftHanded flag to the ReadFile() function call. +#aiProcess_MakeLeftHanded flag to the ReadFile() function call. + +The output face winding is counter-clockwise. Use #aiProcess_FlipWindingOrder to get CW data. +@code +x0 + + x2 + x1 +@endcode + +The output UV coordinate system has its origin in the lower-left corner: +@code +0y|1y ---------- 1x|1y + | | + | | + | | +0x|0y ---------- 1x|0y +@endcode +Use the #aiProcess_FlipUVs flag to get UV coordinates with the upper-left corner als origin. All matrices in the library are row-major. That means that the matrices are stored row by row in memory, which is similar to the OpenGL matrix layout. A typical 4x4 matrix including a translational part looks like this: @@ -650,7 +668,7 @@ a set of properties accessible by their names. Have a look at aiMaterial.h to se properties are defined. In this file there are also various functions defined to test for the presence of certain properties in a material and retrieve their values. -Example to convert from an Assimp material to a Direct3D 9 material for use with the fixed +Example to convert from an ASSIMP material to a Direct3D 9 material for use with the fixed function pipeline. Textures are not handled, only colors and the specular power, sometimes also refered to as "shininess": @code diff --git a/include/aiDefines.h b/include/aiDefines.h index 773a789ce..4c6273f8f 100644 --- a/include/aiDefines.h +++ b/include/aiDefines.h @@ -65,12 +65,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ////////////////////////////////////////////////////////////////////////// // Define ASSIMP_BUILD_NO_XX_PROCESS to disable a specific - // post-processing step. The spe will be excluded from the - // build in this case. 'XX' stands for the name of the loader. - // List of defines: + // post-processing step. + // Full list of all 'XX': // CALCTANGENTS // JOINVERTICES - // CONVERTTOLH // TRIANGULATE // GENFACENORMALS // GENVERTEXNORMALS @@ -88,6 +86,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // TRANSFORMTEXCOORDS // GENUVCOORDS // ENTITYMESHBUILDER + // MAKELEFTHANDED + // FLIPUVS + // FLIPWINDINGORDER + // *OPTIMIZEMESHES + // *OPTIMIZEANIMS + // *OPTIMIZENODES + // *GENENTITYMESHES // Compiler specific includes and definitions #if (defined _MSC_VER) diff --git a/include/aiPostProcess.h b/include/aiPostProcess.h index d6cceb517..1756c99a4 100644 --- a/include/aiPostProcess.h +++ b/include/aiPostProcess.h @@ -50,89 +50,152 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. extern "C" { #endif -/** Defines the flags for all possible post processing steps. */ +// ----------------------------------------------------------------------------------- +/** @enum aiPostProcessSteps + * @brief Defines the flags for all possible post processing steps. + * + * @see Importer::ReadFile + * @see aiImportFile + * @see aiImportFileEx + */ +// ----------------------------------------------------------------------------------- enum aiPostProcessSteps { - /**
    Calculates the tangents and bitangents for the imported meshes. Does nothing - * if a mesh does not have normals. You might want this post processing step to be - * executed if you plan to use tangent space calculations such as normal mapping - * applied to the meshes. There exists a configuration option, - * #AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE that allows you to specify - * an angle maximum for the step. - */ - aiProcess_CalcTangentSpace = 1, - /**
    Identifies and joins identical vertex data sets within all imported meshes. + // ------------------------------------------------------------------------- + /**
    Calculates the tangents and bitangents for the imported meshes. + * + * Does nothing if a mesh does not have normals. You might want this post + * processing step to be executed if you plan to use tangent space calculations + * such as normal mapping applied to the meshes. There's a config setting, + * #AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE, which allows you to specify + * a maximum smoothing angle for the algorithm. However, usually you'll + * want to let the default value. Thanks. + */ + aiProcess_CalcTangentSpace = 0x1, + + // ------------------------------------------------------------------------- + /**
    Identifies and joins identical vertex data sets within all + * imported meshes. + * * After this step is run each mesh does contain only unique vertices anymore, * so a vertex is possibly used by multiple faces. You usually want - * to use this post processing step.*/ - aiProcess_JoinIdenticalVertices = 2, + * to use this post processing step. If your application deals with + * indexed geometry, this step is compulsory or you'll just waste rendering + * time. If this flag is not specified, no vertices are referenced by + * more than one face and no index buffer is required for rendering. + */ + aiProcess_JoinIdenticalVertices = 0x2, - /**
    Converts all the imported data to a left-handed coordinate space such as - * the DirectX coordinate system. By default the data is returned in a right-handed - * coordinate space which for example OpenGL prefers. In this space, +X points to the - * right, +Y points towards the viewer and and +Z points upwards. In the DirectX + // ------------------------------------------------------------------------- + /**
    Converts all the imported data to a left-handed coordinate space. + * + * By default the data is returned in a right-handed coordinate space which + * for example OpenGL prefers. In this space, +X points to the right, + * +Z points towards the viewer and and +Y points upwards. In the DirectX * coordinate space +X points to the right, +Y points upwards and +Z points * away from the viewer. + * + * You'll probably want to consider this flag if you use Direct3D for + * rendering. The #aiProcess_ConvertToLeftHanded flag supersedes this + * setting and boundles all conversions typically required for D3D-based + * applications. */ - aiProcess_ConvertToLeftHanded = 4, + aiProcess_MakeLeftHanded = 0x4, - /**
    Triangulates all faces of all meshes. By default the imported mesh data might - * contain faces with more than 3 indices. For rendering a mesh you usually need - * all faces to be triangles. This post processing step splits up all higher faces - * to triangles. This step won't modify line and point primitives. If you need - * only triangles, do the following:
    - * 1. Specify both the aiProcess_Triangulate and the aiProcess_SortByPType - * step.
    - * 2. Ignore all point and line meshes when you process assimp's output data. + // ------------------------------------------------------------------------- + /**
    Triangulates all faces of all meshes. + * + * By default the imported mesh data might contain faces with more than 3 + * indices. For rendering you'll usually want all faces to be triangles. + * This post processing step splits up all higher faces to triangles. + * Line and point primitives are *not* modified!. If you want + * 'triangles only' with no other kinds of primitives, try the following + * solution: + *
      + *
    • Specify both #aiProcess_Triangulate and #aiProcess_SortByPType
    • + * Ignore all point and line meshes when you process assimp's output + *
    */ - aiProcess_Triangulate = 8, + aiProcess_Triangulate = 0x8, + // ------------------------------------------------------------------------- /**
    Removes some parts of the data structure (animations, materials, * light sources, cameras, textures, vertex components). * - * The components to be removed are specified in a separate - * configuration option, #AI_CONFIG_PP_RVC_FLAGS. This is quite useful - * if you don't need all parts of the output structure. Especially vertex - * colors are rarely used today ... . Calling this step to exclude non-required - * stuff from the pipeline as early as possible results in an increased - * performance and a better optimized output data structure. - * This step is also useful if you want to force Assimp to recompute - * normals or tangents. The corresponding steps don't recompute them if - * they're already there ( loaded from the source asset). By using this - * step you can make sure they are NOT there. + * The components to be removed are specified in a separate + * configuration option, #AI_CONFIG_PP_RVC_FLAGS. This is quite useful + * if you don't need all parts of the output structure. Especially vertex + * colors are rarely used today ... . Calling this step to remove unrequired + * stuff from the pipeline as early as possible results in an increased + * performance and a better optimized output data structure. + * This step is also useful if you want to force Assimp to recompute + * normals or tangents. The corresponding steps don't recompute them if + * they're already there (loaded from the source asset). By using this + * step you can make sure they are NOT there. + * + * This flag is a poor one, mainly because it's purpose is usually + * misunderstood. Consider the following case: a 3d model has been exported + * from a CAD app, it has per-face vertex colors. Vertex positions can't be + * shared, thus the #aiProcess_JoinIdenticalVertices step fails to + * optimize the data. Just because these nasty, little vertex colors. + * Most apps don't even process them, so it's all for nothing. By using + * this step, unneeded components are excluded as early as possible + * thus opening more room for internal optimzations. */ aiProcess_RemoveComponent = 0x10, - /**
    Generates normals for all faces of all meshes. The normals are shared - * between the three vertices of a face. This is ignored - * if normals are already existing. This flag may not be specified together - * with aiProcess_GenSmoothNormals. - */ + // ------------------------------------------------------------------------- + /**
    Generates normals for all faces of all meshes. + * + * This is ignored if normals are already there at the time where this flag + * is evaluated. Model importers try to load them from the source file, so + * they're usually already there. Face normals are shared between all points + * of a single face, so a single point can have multiple normals, which in + * other words, enforces the library to duplicate vertices in some cases. + * #aiProcess_JoinIdenticalVertices is *senseless* then. + * + * This flag may not be specified together with #aiProcess_GenSmoothNormals. + */ aiProcess_GenNormals = 0x20, - /**
    Generates smooth normals for all vertices in the mesh. This is ignored - * if normals are already existing. This flag may not be specified together - * with aiProcess_GenNormals. There's a configuration option, - * #AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE that allows you to specify + // ------------------------------------------------------------------------- + /**
    Generates smooth normals for all vertices in the mesh. + * + * This is ignored if normals are already there at the time where this flag + * is evaluated. Model importers try to load them from the source file, so + * they're usually already there. + * + * This flag may (of course) not be specified together with + * #aiProcess_GenNormals. There's a configuration option, + * #AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE which allows you to specify * an angle maximum for the normal smoothing algorithm. Normals exceeding * this limit are not smoothed, resulting in a a 'hard' seam between two faces. + * Using a decent angle here (e.g. 80°) results in very good visual + * appearance. */ aiProcess_GenSmoothNormals = 0x40, - /**
    Splits large meshes into submeshes - * This is quite useful for realtime rendering where the number of triangles - * to be maximally rendered in one drawcall is usually limited by the video driver. - * The maximum vertex buffer size suffers from limitations, too. Both - * requirements are met with this step: you can specify both a triangle and vertex - * limit for a single mesh. + // ------------------------------------------------------------------------- + /**
    Splits large meshes into smaller submeshes * - * The split limits can be set through the AI_CONFIG_PP_SLM_VERTEX_LIMIT - * and AI_CONFIG_PP_SLM_TRIANGLE_LIMIT The default values are - * AI_SLM_DEFAULT_MAX_VERTICES and AI_SLM_DEFAULT_MAX_TRIANGLES. + * This is quite useful for realtime rendering where the number of triangles + * which can be maximally processed in a single draw-call is usually limited + * by the video driver/hardware. The maximum vertex buffer is usually limited, + * too. Both requirements can be met with this step: you may specify both a + * triangle and vertex limit for a single mesh. + * + * The split limits can (and should!) be set through the + * #AI_CONFIG_PP_SLM_VERTEX_LIMIT and #AI_CONFIG_PP_SLM_TRIANGLE_LIMIT + * settings. The default values are #AI_SLM_DEFAULT_MAX_VERTICES and + * #AI_SLM_DEFAULT_MAX_TRIANGLES. + * + * Note that splitting is generally a time-consuming task, but not if there's + * nothing to split. The use of this step is recommended for most users. */ aiProcess_SplitLargeMeshes = 0x80, + // ------------------------------------------------------------------------- /**
    Removes the node graph and pre-transforms all vertices with * the local transformation matrices of their nodes. The output * scene does still contain nodes, however, there is only a @@ -149,44 +212,87 @@ enum aiPostProcessSteps */ aiProcess_PreTransformVertices = 0x100, + // ------------------------------------------------------------------------- /**
    Limits the number of bones simultaneously affecting a single vertex - * to a maximum value. If any vertex is affected by more than that number - * of bones, the least important vertex weights are removed and the remaining - * vertex weights are renormalized so that the weights still sum up to 1. - * The default bone weight limit is 4 (defined as AI_LMW_MAX_WEIGHTS in - * LimitBoneWeightsProcess.h), but you can use the aiSetBoneWeightLimit - * function to supply your own limit to the post processing step. - * - * If you intend to perform the skinning in hardware, this post processing step - * might be of interest for you. + * to a maximum value. + * + * If any vertex is affected by more than that number of bones, the least + * important vertex weights are removed and the remaining vertex weights are + * renormalized so that the weights still sum up to 1. + * The default bone weight limit is 4 (defined as #AI_LMW_MAX_WEIGHTS in + * aiConfig.h), but you can use the #AI_CONFIG_PP_LBW_MAX_WEIGHTS setting to + * supply your own limit to the post processing step. + * + * If you intend to perform the skinning in hardware, this post processing + * step might be of interest for you. */ aiProcess_LimitBoneWeights = 0x200, - /**
    Validates the aiScene data structure before it is returned. + // ------------------------------------------------------------------------- + /**
    Validates the imported scene data structure * This makes sure that all indices are valid, all animations and - * bones are linked correctly, all material are correct and so on ... - * This is primarily intended for our internal debugging stuff, - * however, it could be of interest for applications like editors - * where stability is more important than loading performance. + * bones are linked correctly, all material references are correct .. etc. + * + * It is recommended to capture Assimp's log output if you use this flag, + * so you can easily find ot what's actually wrong if a file fails the + * validation. The validator is quite rude and will find *all* + * inconsistencies in the data structure ... plugin developers are + * recommended to use it to debug their loaders. There are two types of + * validation failures: + *
      + *
    • Error: There's something wrong with the imported data. Further + * postprocessing is not possible and the data is not usable at all. + * The import fails. #Importer::GetErrorString() or #aiGetErrorString() + * carry the error message around.
    • + *
    • Warning: There are some minor issues (e.g. 1000000 animation + * keyframes with the same time), but further postprocessing and use + * of the data structure is still safe. Warning details are written + * to the log file, #AI_SCENE_FLAGS_VALIDATION_WARNING is set + * in #aiScene::mFlags
    • + *
    + * + * This post-processing step is not time-consuming. It's use is not + * compulsory, but recommended. */ aiProcess_ValidateDataStructure = 0x400, - /**
    Reorders triangles for vertex cache locality and thus better performance. + // ------------------------------------------------------------------------- + /**
    Reorders triangles for better vertex cache locality. + * * The step tries to improve the ACMR (average post-transform vertex cache - * miss ratio) for all meshes. The step runs in O(n) and is roughly - * basing on the algorithm described in this paper: - * http://www.cs.princeton.edu/gfx/pubs/Sander_2007_%3ETR/tipsy.pdf + * miss ratio) for all meshes. The implementation runs in O(n) and is + * roughly based on the 'tipsify' algorithm (see this + * paper). + * + * If you intend to render huge models in hardware, this step might + * be of interest for you. The #AI_CONFIG_PP_ICL_PTCACHE_SIZEconfig + * setting can be used to fine-tune the cache optimization. */ aiProcess_ImproveCacheLocality = 0x800, - /**
    Searches for redundant materials and removes them. + // ------------------------------------------------------------------------- + /**
    Searches for redundant/unreferenced materials and removes them. * - * This is especially useful in combination with the PretransformVertices - * and OptimizeGraph steps. Both steps join small meshes, but they - * can't do that if two meshes have different materials. - */ + * This is especially useful in combination with the + * #aiProcess_PretransformVertices and #aiProcess_OptimizeMeshes flags. + * Both join small meshes with equal characteristics, but they can't do + * their work if two meshes have different materials. Because several + * material settings are always lost during Assimp's import filters, + * (and because many exporters don't check for redundant materials), huge + * models often have materials which are are defined several times with + * exactly the same settings .. + * + * Several material settings not contributing to the final appearance of + * a surface are ignored in all comparisons ... the material name is + * one of them. So, if you're passing additional information through the + * content pipeline (probably using using *magic* material names), don't + * specify this flag. Alternatively take a look at the + * #AI_CONFIG_PP_RRM_EXCLUDE_LIST setting. + */ aiProcess_RemoveRedundantMaterials = 0x1000, + // ------------------------------------------------------------------------- /**
    This step tries to determine which meshes have normal vectors * that are facing inwards. The algorithm is simple but effective: * the bounding box of all vertices + their normals is compared against @@ -198,7 +304,7 @@ enum aiPostProcessSteps */ aiProcess_FixInfacingNormals = 0x2000, - + // ------------------------------------------------------------------------- /**
    This step splits meshes with more than one primitive type in * homogeneous submeshes. * @@ -206,16 +312,17 @@ enum aiPostProcessSteps * returns, just one bit is set in aiMesh::mPrimitiveTypes. This is * especially useful for real-time rendering where point and line * primitives are often ignored or rendered separately. - * You can use the AI_CONFIG_PP_SBP_REMOVE option to specify which + * You can use the #AI_CONFIG_PP_SBP_REMOVE option to specify which * primitive types you need. This can be used to easily exclude * lines and points, which are rarely used, from the import. */ aiProcess_SortByPType = 0x8000, + // ------------------------------------------------------------------------- /**
    This step searches all meshes for degenerated primitives and * converts them to proper lines or points. * - * A face is degenerated if one or more of its points are identical. + * A face is 'degenerated' if one or more of its points are identical. * To have the degenerated stuff not only detected and collapsed but * also removed, try one of the following procedures: *
    1. (if you support lines&points for rendering but don't @@ -224,7 +331,7 @@ enum aiPostProcessSteps *
  • Specify the #aiProcess_FindDegenerates flag. *
  • *
  • Set the AI_CONFIG_PP_FD_REMOVE option to 1. This will - * cause the step to remove degenerated triangles rom the import + * cause the step to remove degenerated triangles from the import * as soon as they're detected. They won't pass any further * pipeline steps. *
  • @@ -249,6 +356,7 @@ enum aiPostProcessSteps */ aiProcess_FindDegenerates = 0x10000, + // ------------------------------------------------------------------------- /**
    This step searches all meshes for invalid data, such as zeroed * normal vectors or invalid UV coords and removes them. * @@ -259,35 +367,88 @@ enum aiPostProcessSteps */ aiProcess_FindInvalidData = 0x20000, + // ------------------------------------------------------------------------- /**
    This step converts non-UV mappings (such as spherical or - * cylindrical) to proper UV mapping channels. + * cylindrical apping) to proper texture coordinate channels. * * Most applications will support UV mapping only, so you will - * probably want to specify this step in every case. - */ + * probably want to specify this step in every case. Note tha Assimp is not + * always able to match the original mapping implementation of the + * 3d app which produced a model perfectly. It's always better to let the + * father app compute the UV channels, at least 3ds max, maja, blender, + * lightwave, modo, ... are able to achieve this. + * + * @note If this step is not requested, you'll need to process the + * #AI_MATKEY_MAPPING<7tt> material property in order to display all assets + * properly. + */ aiProcess_GenUVCoords = 0x40000, - /**
    This step pre-transforms UV coordinates by the UV transformations - * (such as scalings or rotations). - * - * UV transformations are specified per-texture - see the - * AI_MATKEY_UVTRANSFORM key for more information on this topic. - * This step finds all textures with transformed input UV - * coordinates and generates a new, transformed, UV channel for it. - * Most applications won't support UV transformations, so you will - * probably want to specify this step in every case. - - * todo ... rewrite doc + // ------------------------------------------------------------------------- + /**
    This step applies per-texture UV transformations and bakes + * them to stand-alone vtexture coordinate channelss. + * + * UV transformations are specified per-texture - see the + * #AI_MATKEY_UVTRANSFORM material key for more information. + * This step processes all textures with + * transformed input UV coordinates and generates new (pretransformed) UV channel + * which replace the old channel. Most applications won't support UV + * transformations, so you will probably want to specify this step. + * + * @note UV transformations are usually implemented in realtime apps by + * transforming texture coordinates at vertex shader stage with a 3x3 + * (homogenous) transformation matrix. */ aiProcess_TransformUVCoords = 0x80000, - + // ------------------------------------------------------------------------- /**
    This step searches for duplicate meshes and replaces duplicates * with references to the first mesh. * - * todo ... add more doc + * This step takes a while, don't use it if you have no time. + * It's main purpose is to workaround the limitation that many export + * file formats don't support instanced meshes, so exporters need to + * duplicate meshes. This step removes the duplicates again. Please + * note that Assimp does currently not support per-node material + * assignment to meshes, which means that identical meshes with + * differnent materials are currently *not* joined, although this is + * planned for future versions. + */ + aiProcess_FindInstances = 0x100000, + + // ------------------------------------------------------------------------- + /**
    This step flips all UV coordinates along the y-axis and adjusts + * material settings and bitangents accordingly. + *
    Output UV coordinate system: + * @code + * 0y|0y ---------- 1x|0y + * | | + * | | + * | | + * 0x|1y ---------- 1x|1y + * @endcode + * + * You'll probably want to consider this flag if you use Direct3D for + * rendering. The #aiProcess_ConvertToLeftHanded flag supersedes this + * setting and boundles all conversions typically required for D3D-based + * applications. */ - aiProcess_FindInstances = 0x100000 + aiProcess_FlipUVs = 0x80000000, /* don't change */ + + // ------------------------------------------------------------------------- + /**
    This step adjusts the output face winding order to be clock-wise. + * + * The default face winding order is counter-clockwise. + *
    Output face order: + * @code + * x0 + * + * x1 + * x2 + * @endcode + */ + aiProcess_FlipWindingOrder = 0x40000000 /* don't change */ + // aiProcess_GenEntityMeshes = 0x100000, @@ -296,6 +457,23 @@ enum aiPostProcessSteps }; +// --------------------------------------------------------------------------------------- +/** @def aiProcess_ConvertToLeftHanded + * @brief Shortcut flag for Direct3D-based applications. + * + * Supersedes the #aiProcess_MakeLeftHanded, #aiProcess_FlipUVs and + * #aiProcess_FlipWindingOrder flags. The output data matches Direct3D's conventions: + * left-handed geometry, upper-left origin for UV coordinates and finally clockwise + * face order, suitable for CCW culling. + * + * @deprecated + */ +#define aiProcess_ConvertToLeftHanded ( \ + aiProcess_MakeLeftHanded | \ + aiProcess_FlipUVs | \ + 0 ) + + // --------------------------------------------------------------------------------------- /** @def aiProcessPreset_TargetRealtimeUse_Fast * @brief Default postprocess configuration optimizing the data for real-time rendering. @@ -310,14 +488,14 @@ enum aiPostProcessSteps * Some of them offer further configurable properties, some of them might not be of * use for you so it might be better to not specify them. */ -#define aiProcessPreset_TargetRealtime_Fast \ +#define aiProcessPreset_TargetRealtime_Fast ( \ aiProcess_CalcTangentSpace | \ aiProcess_GenNormals | \ aiProcess_JoinIdenticalVertices | \ aiProcess_Triangulate | \ aiProcess_GenUVCoords | \ aiProcess_SortByPType | \ - 0 + 0 ) // --------------------------------------------------------------------------------------- /** @def aiProcessPreset_TargetRealtime_Quality @@ -331,11 +509,11 @@ enum aiPostProcessSteps * If you're using DirectX, don't forget to combine this value with * the #aiProcess_ConvertToLeftHanded step. If you don't support UV transformations * in your application apply the #aiProcess_TransformUVCoords step, too. - * @note Please take the time to read the doc to the steps enabled by this preset. + * @note Please take the time to read the doc for the steps enabled by this preset. * Some of them offer further configurable properties, some of them might not be of * use for you so it might be better to not specify them. */ -#define aiProcessPreset_TargetRealtime_Quality \ +#define aiProcessPreset_TargetRealtime_Quality ( \ aiProcess_CalcTangentSpace | \ aiProcess_GenSmoothNormals | \ aiProcess_JoinIdenticalVertices | \ @@ -348,7 +526,7 @@ enum aiPostProcessSteps aiProcess_SortByPType | \ aiProcess_FindDegenerates | \ aiProcess_FindInvalidData | \ - 0 + 0 ) // --------------------------------------------------------------------------------------- /** @def aiProcessPreset_TargetRealtime_MaxQuality @@ -360,16 +538,16 @@ enum aiPostProcessSteps * * If you're using DirectX, don't forget to combine this value with * the #aiProcess_ConvertToLeftHanded step. If you don't support UV transformations - * in your application apply the #aiProcess_TransformUVCoords step, too. - * @note Please take the time to read the doc to the steps enabled by this preset. + * in your application, apply the #aiProcess_TransformUVCoords step, too. + * @note Please take the time to read the doc for the steps enabled by this preset. * Some of them offer further configurable properties, some of them might not be of * use for you so it might be better to not specify them. */ -#define aiProcessPreset_TargetRealtime_MaxQuality \ +#define aiProcessPreset_TargetRealtime_MaxQuality ( \ aiProcessPreset_TargetRealtime_Quality | \ aiProcess_FindInstances | \ aiProcess_ValidateDataStructure | \ - 0 + 0 ) #ifdef __cplusplus diff --git a/test/models/LWO/LWO2/MappingModes/concreteBoxMapped.lwo b/test/models/LWO/LWO2/MappingModes/concreteBoxMapped.lwo deleted file mode 100644 index f624ae0ca..000000000 Binary files a/test/models/LWO/LWO2/MappingModes/concreteBoxMapped.lwo and /dev/null differ diff --git a/test/models/LWO/LWO2/MappingModes/concreteCylinderMapped.lwo b/test/models/LWO/LWO2/MappingModes/concreteCylinderMapped.lwo deleted file mode 100644 index 9d5cc856c..000000000 Binary files a/test/models/LWO/LWO2/MappingModes/concreteCylinderMapped.lwo and /dev/null differ diff --git a/test/models/LWO/LWO2/MappingModes/concretePlaneMapped.lwo b/test/models/LWO/LWO2/MappingModes/concretePlaneMapped.lwo deleted file mode 100644 index a46c8ff92..000000000 Binary files a/test/models/LWO/LWO2/MappingModes/concretePlaneMapped.lwo and /dev/null differ diff --git a/test/models/LWO/LWO2/MappingModes/concreteSphereMapped.lwo b/test/models/LWO/LWO2/MappingModes/concreteSphereMapped.lwo deleted file mode 100644 index feebdefda..000000000 Binary files a/test/models/LWO/LWO2/MappingModes/concreteSphereMapped.lwo and /dev/null differ diff --git a/test/models/LWO/LWO2/MappingModes/concreteUVMapped.lwo b/test/models/LWO/LWO2/MappingModes/concreteUVMapped.lwo deleted file mode 100644 index dd876f1bf..000000000 Binary files a/test/models/LWO/LWO2/MappingModes/concreteUVMapped.lwo and /dev/null differ diff --git a/test/models/LWO/LWO2/MappingModes/earth_cylindrical_x.lwo b/test/models/LWO/LWO2/MappingModes/earth_cylindrical_x.lwo new file mode 100644 index 000000000..7f4568c88 Binary files /dev/null and b/test/models/LWO/LWO2/MappingModes/earth_cylindrical_x.lwo differ diff --git a/test/models/LWO/LWO2/MappingModes/earth_cylindrical_x_scale_222_wrap_21.lwo b/test/models/LWO/LWO2/MappingModes/earth_cylindrical_x_scale_222_wrap_21.lwo new file mode 100644 index 000000000..32cf6c1d2 Binary files /dev/null and b/test/models/LWO/LWO2/MappingModes/earth_cylindrical_x_scale_222_wrap_21.lwo differ diff --git a/test/models/LWO/LWO2/MappingModes/earth_cylindrical_y.lwo b/test/models/LWO/LWO2/MappingModes/earth_cylindrical_y.lwo new file mode 100644 index 000000000..53ea08cd7 Binary files /dev/null and b/test/models/LWO/LWO2/MappingModes/earth_cylindrical_y.lwo differ diff --git a/test/models/LWO/LWO2/MappingModes/earth_cylindrical_y_scale_111.lwo b/test/models/LWO/LWO2/MappingModes/earth_cylindrical_y_scale_111.lwo new file mode 100644 index 000000000..a7b798158 Binary files /dev/null and b/test/models/LWO/LWO2/MappingModes/earth_cylindrical_y_scale_111.lwo differ diff --git a/test/models/LWO/LWO2/MappingModes/earth_cylindrical_y_scale_111_wrap_21.lwo b/test/models/LWO/LWO2/MappingModes/earth_cylindrical_y_scale_111_wrap_21.lwo new file mode 100644 index 000000000..6290ede0d Binary files /dev/null and b/test/models/LWO/LWO2/MappingModes/earth_cylindrical_y_scale_111_wrap_21.lwo differ diff --git a/test/models/LWO/LWO2/MappingModes/earth_cylindrical_z.lwo b/test/models/LWO/LWO2/MappingModes/earth_cylindrical_z.lwo new file mode 100644 index 000000000..2da2a1b8c Binary files /dev/null and b/test/models/LWO/LWO2/MappingModes/earth_cylindrical_z.lwo differ diff --git a/test/models/LWO/LWO2/MappingModes/earth_planar_x.lwo b/test/models/LWO/LWO2/MappingModes/earth_planar_x.lwo new file mode 100644 index 000000000..8ca53f11f Binary files /dev/null and b/test/models/LWO/LWO2/MappingModes/earth_planar_x.lwo differ diff --git a/test/models/LWO/LWO2/MappingModes/earth_planar_y.lwo b/test/models/LWO/LWO2/MappingModes/earth_planar_y.lwo new file mode 100644 index 000000000..9b3282c58 Binary files /dev/null and b/test/models/LWO/LWO2/MappingModes/earth_planar_y.lwo differ diff --git a/test/models/LWO/LWO2/MappingModes/earth_planar_z.lwo b/test/models/LWO/LWO2/MappingModes/earth_planar_z.lwo new file mode 100644 index 000000000..4f3634a77 Binary files /dev/null and b/test/models/LWO/LWO2/MappingModes/earth_planar_z.lwo differ diff --git a/test/models/LWO/LWO2/MappingModes/earth_planar_z_scale_111.lwo b/test/models/LWO/LWO2/MappingModes/earth_planar_z_scale_111.lwo new file mode 100644 index 000000000..ab9bc6b58 Binary files /dev/null and b/test/models/LWO/LWO2/MappingModes/earth_planar_z_scale_111.lwo differ diff --git a/test/models/LWO/LWO2/MappingModes/earth_spherical_x.lwo b/test/models/LWO/LWO2/MappingModes/earth_spherical_x.lwo new file mode 100644 index 000000000..9d4caf617 Binary files /dev/null and b/test/models/LWO/LWO2/MappingModes/earth_spherical_x.lwo differ diff --git a/test/models/LWO/LWO2/MappingModes/earth_spherical_x_scale_222_wrap_22.lwo b/test/models/LWO/LWO2/MappingModes/earth_spherical_x_scale_222_wrap_22.lwo new file mode 100644 index 000000000..754c03157 Binary files /dev/null and b/test/models/LWO/LWO2/MappingModes/earth_spherical_x_scale_222_wrap_22.lwo differ diff --git a/test/models/LWO/LWO2/MappingModes/earth_spherical_y.lwo b/test/models/LWO/LWO2/MappingModes/earth_spherical_y.lwo new file mode 100644 index 000000000..5709bd748 Binary files /dev/null and b/test/models/LWO/LWO2/MappingModes/earth_spherical_y.lwo differ diff --git a/test/models/LWO/LWO2/MappingModes/earth_spherical_z.lwo b/test/models/LWO/LWO2/MappingModes/earth_spherical_z.lwo new file mode 100644 index 000000000..c546ad025 Binary files /dev/null and b/test/models/LWO/LWO2/MappingModes/earth_spherical_z.lwo differ diff --git a/test/models/LWO/LWO2/MappingModes/earth_spherical_z_wrap_22.lwo b/test/models/LWO/LWO2/MappingModes/earth_spherical_z_wrap_22.lwo new file mode 100644 index 000000000..eb411872a Binary files /dev/null and b/test/models/LWO/LWO2/MappingModes/earth_spherical_z_wrap_22.lwo differ diff --git a/test/models/LWO/LWO2/MappingModes/earth_uv_cylindrical_y.lwo b/test/models/LWO/LWO2/MappingModes/earth_uv_cylindrical_y.lwo new file mode 100644 index 000000000..8fa7b329b Binary files /dev/null and b/test/models/LWO/LWO2/MappingModes/earth_uv_cylindrical_y.lwo differ diff --git a/tools/assimp_view/SceneAnimator.cpp b/tools/assimp_view/SceneAnimator.cpp index fb0c2ab89..da02d5a0c 100644 --- a/tools/assimp_view/SceneAnimator.cpp +++ b/tools/assimp_view/SceneAnimator.cpp @@ -221,11 +221,11 @@ void SceneAnimator::UpdateTransforms( SceneAnimNode* pNode, const std::vectormChannelIndex < pTransforms.size()); pNode->mLocalTransform = pTransforms[pNode->mChannelIndex]; - - // update global transform as well - CalculateGlobalTransform( pNode); } + // update global transform as well + CalculateGlobalTransform( pNode); + // continue for all children for( std::vector::iterator it = pNode->mChildren.begin(); it != pNode->mChildren.end(); ++it) UpdateTransforms( *it, pTransforms); diff --git a/workspaces/vc8/assimp.vcproj b/workspaces/vc8/assimp.vcproj index c315d5b2c..18136461b 100644 --- a/workspaces/vc8/assimp.vcproj +++ b/workspaces/vc8/assimp.vcproj @@ -2255,10 +2255,6 @@ RelativePath="..\..\code\ValidateDataStructure.h" > - -