From 240dbfd86482d1e1a8cda1d4b0c89d2dc7a4bea0 Mon Sep 17 00:00:00 2001 From: aramis_acg Date: Sun, 2 Nov 2008 22:30:37 +0000 Subject: [PATCH] Small fix to the ASE loader - workaround for bitmaps with filename "None". Further work on the IRR loader. Still work in progress. Fixed a minor issue in StandardShapes. Fixed a bug in the Q3D loader causing models without textures to load incorrectly. git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@225 67173fc5-114c-0410-ac8e-9d2fd5bffc1f --- code/ASEParser.cpp | 12 +++ code/FindInvalidDataProcess.cpp | 2 +- code/IRRLoader.cpp | 185 ++++++++++++++++++++++++++++++-- code/IRRLoader.h | 14 +++ code/Q3DLoader.cpp | 12 ++- code/StandardShapes.cpp | 6 +- code/StandardShapes.h | 2 +- include/aiQuaternion.h | 70 ++++++------ 8 files changed, 249 insertions(+), 54 deletions(-) diff --git a/code/ASEParser.cpp b/code/ASEParser.cpp index 260526252..c4402cffc 100644 --- a/code/ASEParser.cpp +++ b/code/ASEParser.cpp @@ -587,7 +587,10 @@ void Parser::ParseLV3MapBlock(Texture& map) if(!ParseString(temp,"*MAP_CLASS")) SkipToNextToken(); if (temp != "Bitmap") + { + DefaultLogger::get()->warn("ASE: Skipping unknown map type: " + temp); parsePath = false; + } continue; } // path to the texture @@ -595,6 +598,15 @@ void Parser::ParseLV3MapBlock(Texture& map) { if(!ParseString(map.mMapName,"*BITMAP")) SkipToNextToken(); + + if (map.mMapName == "None") + { + // Files with 'None' as map name are produced by + // an Maja to ASE exporter which name I forgot .. + DefaultLogger::get()->warn("ASE: Skipping invalid map entry"); + map.mMapName = ""; + } + continue; } // offset on the u axis diff --git a/code/FindInvalidDataProcess.cpp b/code/FindInvalidDataProcess.cpp index 7435a4bcf..54fa6c717 100644 --- a/code/FindInvalidDataProcess.cpp +++ b/code/FindInvalidDataProcess.cpp @@ -208,7 +208,7 @@ inline bool ProcessArray(T*& in, unsigned int num,const char* name, template inline bool AllIdentical(T* in, unsigned int num) { - if (!num)return true; + if (num <= 1)return true; for (unsigned int i = 0; i < num-1;++i) { if (in[i] != in[i+1])return false; diff --git a/code/IRRLoader.cpp b/code/IRRLoader.cpp index c1977041b..68ccb079d 100644 --- a/code/IRRLoader.cpp +++ b/code/IRRLoader.cpp @@ -102,6 +102,129 @@ bool IRRImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const return false; } +// ------------------------------------------------------------------------------------------------ +void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene, + BatchLoader& batch, + std::vector& meshes, + std::vector& anims, + std::vector& attach) +{ + // Setup the name of this node + rootOut->mName.Set(root->name); + + unsigned int oldMeshSize = (unsigned int)meshes.size(); + + // Now determine the type of the node + switch (root->type) + { + case Node::ANIMMESH: + case Node::MESH: + { + // get the loaded mesh from the scene and add it to + // the list of all scenes to be attached to the + // graph we're currently building + aiScene* scene = batch.GetImport(root->meshPath); + if (!scene) + { + DefaultLogger::get()->error("IRR: Unable to load external file: " + root->meshPath); + break; + } + attach.push_back(AttachmentInfo(scene,rootOut)); + } + break; + + case Node::LIGHT: + case Node::CAMERA: + + // We're already finished with lights and cameras + break; + + + case Node::SPHERE: + { + // generate the sphere model. Our input parameter to + // the sphere generation algorithm is the number of + // subdivisions of each triangle - but here we have + // the number of poylgons on a specific axis. Just + // use some limits ... + unsigned int mul = root->spherePolyCountX*root->spherePolyCountY; + if (mul < 100)mul = 2; + else if (mul < 300)mul = 3; + else mul = 4; + + meshes.push_back(StandardShapes::MakeMesh(mul,&StandardShapes::MakeSphere)); + + // Adjust scaling + root->scaling *= root->sphereRadius; + } + break; + + case Node::CUBE: + case Node::SKYBOX: + { + // Skyboxes and normal cubes - generate the cube first + meshes.push_back(StandardShapes::MakeMesh(&StandardShapes::MakeHexahedron)); + + // Adjust scaling + root->scaling *= root->sphereRadius; + } + break; + + case Node::TERRAIN: + { + } + break; + }; + + // Check whether we added a mesh. In this case we'll also + // need to attach it to the node + if (oldMeshSize != (unsigned int) meshes.size()) + { + rootOut->mNumMeshes = 1; + rootOut->mMeshes = new unsigned int[1]; + rootOut->mMeshes[0] = oldMeshSize; + } + + // 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) + aiMatrix4x4 m; + rootOut->mTransformation = aiMatrix4x4::RotationX(AI_DEG_TO_RAD(root->rotation.x),m) + * aiMatrix4x4::RotationY(AI_DEG_TO_RAD(root->rotation.y),m) + * aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(root->rotation.z),m); + + // apply scaling + aiMatrix4x4& mat = rootOut->mTransformation; + mat.a1 *= root->scaling.x; + mat.b1 *= root->scaling.x; + mat.c1 *= root->scaling.x; + 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.y; + mat.c4 = root->position.z; + + // Add all children recursively. First allocate enough storage + // for them, then call us again + rootOut->mNumChildren = (unsigned int)root->children.size(); + if (rootOut->mNumChildren) + { + rootOut->mChildren = new aiNode*[rootOut->mNumChildren]; + 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,anims,attach); + } + } +} + // ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. void IRRImporter::InternReadFile( const std::string& pFile, @@ -133,7 +256,7 @@ void IRRImporter::InternReadFile( const std::string& pFile, // List of output lights std::vector lights; - + // Batch loader used to load external models BatchLoader batch(pIOHandler); cameras.reserve(5); @@ -391,6 +514,10 @@ void IRRImporter::InternReadFile( const std::string& pFile, { curAnim->circleRadius = prop.value; } + else if (curAnim->type == Animator::FOLLOW_SPLINE && prop.name == "Tightness") + { + curAnim->tightness = prop.value; + } } else { @@ -439,13 +566,12 @@ void IRRImporter::InternReadFile( const std::string& pFile, lights.back()->mAngleInnerCone = AI_DEG_TO_RAD( prop.value ); } } - // radius of the sphere to be generated - else if (Node::SPHERE == curNode->type) + // 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" ) { - if (prop.name == "Radius") - { - curNode->sphereRadius = prop.value; - } + curNode->sphereRadius = prop.value; } } } @@ -524,6 +650,34 @@ void IRRImporter::InternReadFile( const std::string& pFile, } batch.AddLoadRequest(prop.value,pp,&map); + curNode->meshPath = prop.value; + } + else if (inAnimator && prop.name == "Type") + { + // type of the animator + if (prop.value == "rotation") + { + curAnim->type = Animator::ROTATION; + } + else if (prop.value == "flyCircle") + { + curAnim->type = Animator::FLY_CIRCLE; + } + else if (prop.value == "flyStraight") + { + curAnim->type = Animator::FLY_CIRCLE; + } + else if (prop.value == "followSpline") + { + curAnim->type = Animator::FOLLOW_SPLINE; + } + else + { + DefaultLogger::get()->warn("IRR: Ignoring unknown animator: " + + prop.value); + + curAnim->type = Animator::UNKNOWN; + } } } } @@ -603,7 +757,6 @@ void IRRImporter::InternReadFile( const std::string& pFile, tempScene->mLights = new aiLight*[tempScene->mNumLights]; ::memcpy(tempScene->mLights,&lights[0],sizeof(void*)*tempScene->mNumLights); - // temporary data std::vector< aiNodeAnim*> anims; std::vector< AttachmentInfo > attach; @@ -615,8 +768,8 @@ void IRRImporter::InternReadFile( const std::string& pFile, /* Now process our scenegraph recursively: generate final * meshes and generate animation channels for all nodes. */ -// GenerateGraph(root,tempScene->mRootNode, tempScene, -// batch, meshes, anims, attach); + GenerateGraph(root,tempScene->mRootNode, tempScene, + batch, meshes, anims, attach); if (!anims.empty()) { @@ -644,9 +797,21 @@ void IRRImporter::InternReadFile( const std::string& pFile, pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; DefaultLogger::get()->info("IRR: No Meshes loaded, setting AI_SCENE_FLAGS_INCOMPLETE flag"); } + else + { + // copy all meshes to the temporary scene + tempScene->mNumMeshes = (unsigned int)meshes.size(); + tempScene->mMeshes = new aiMesh*[tempScene->mNumMeshes]; + ::memcpy(tempScene->mMeshes,&meshes[0],tempScene->mNumMeshes); + } /* Now merge all sub scenes and attach them to the correct * attachment points in the scenegraph. */ SceneCombiner::MergeScenes(pScene,tempScene,attach); + + + /* Finished ... everything destructs automatically and all + * temporary scenes have already been deleted by MergeScenes() + */ } diff --git a/code/IRRLoader.h b/code/IRRLoader.h index 50cc159af..70cf78b80 100644 --- a/code/IRRLoader.h +++ b/code/IRRLoader.h @@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_IRRLOADER_H_INCLUDED #include "IRRMeshLoader.h" +#include "SceneCombiner.h" namespace Assimp { @@ -208,6 +209,9 @@ private: // 0.f if not specified float framesPerSecond; + // Meshes: path to the mesh to be loaded + std::string meshPath; + // Meshes: List of materials to be assigned // along with their corresponding material flags std::vector< std::pair > materials; @@ -221,6 +225,16 @@ private: // List of all animators assigned to the node std::list animators; }; + + + /** Fill the scenegraph recursively + */ + void GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene, + BatchLoader& batch, + std::vector& meshes, + std::vector& anims, + std::vector& attach); + }; } // end of namespace Assimp diff --git a/code/Q3DLoader.cpp b/code/Q3DLoader.cpp index e3acf0c47..31c8bad8e 100644 --- a/code/Q3DLoader.cpp +++ b/code/Q3DLoader.cpp @@ -194,10 +194,10 @@ void Q3DImporter::InternReadFile( const std::string& pFile, normals[i].z = stream.GetF4(); } - if (numTextures) + numVerts = (unsigned int)stream.GetI4(); + if (numTextures && numVerts) { // read all texture coordinates - numVerts = (unsigned int)stream.GetI4(); std::vector& uv = mesh.uv; uv.resize(numVerts); @@ -435,10 +435,14 @@ outer: mat->AddProperty(&srcMat.diffuse, 1,AI_MATKEY_COLOR_DIFFUSE); mat->AddProperty(&srcMat.specular, 1,AI_MATKEY_COLOR_SPECULAR); mat->AddProperty(&srcMat.ambient, 1,AI_MATKEY_COLOR_AMBIENT); - + + // NOTE: Ignore transparency for the moment - it seems + // unclear how to interpret the data +#if 0 if (!(minor > '0' && major == '3')) srcMat.transparency = 1.0f - srcMat.transparency; mat->AddProperty(&srcMat.transparency, 1, AI_MATKEY_OPACITY); +#endif // add shininess - Quick3D seems to use it ins its viewer srcMat.transparency = 16.f; @@ -522,7 +526,7 @@ outer: else *norms = m.normals[ face.indices[n] ]; // copy texture coordinates - if (uv) + if (uv && m.uv.size()) { if (m.prevUVIdx != 0xffffffff && m.uv.size() >= m.verts.size()) // workaround { diff --git a/code/StandardShapes.cpp b/code/StandardShapes.cpp index 0b039b1d7..58979af1c 100644 --- a/code/StandardShapes.cpp +++ b/code/StandardShapes.cpp @@ -166,12 +166,12 @@ aiMesh* StandardShapes::MakeMesh ( unsigned int (*GenerateFunc)( } // ------------------------------------------------------------------------------------------------ -aiMesh* StandardShapes::MakeMesh ( unsigned int (*GenerateFunc)( +aiMesh* StandardShapes::MakeMesh (unsigned int num, void (*GenerateFunc)( unsigned int,std::vector&)) { std::vector temp; - unsigned num = (*GenerateFunc)(4,temp); - return MakeMesh(temp,num); + (*GenerateFunc)(num,temp); + return MakeMesh(temp,3); } // ------------------------------------------------------------------------------------------------ diff --git a/code/StandardShapes.h b/code/StandardShapes.h index 8dff41c6e..c1c3cf94a 100644 --- a/code/StandardShapes.h +++ b/code/StandardShapes.h @@ -78,7 +78,7 @@ public: static aiMesh* MakeMesh ( unsigned int (*GenerateFunc) (std::vector&, bool)); - static aiMesh* MakeMesh ( unsigned int (*GenerateFunc) + static aiMesh* MakeMesh ( unsigned int n, void (*GenerateFunc) (unsigned int,std::vector&)); // ---------------------------------------------------------------- diff --git a/include/aiQuaternion.h b/include/aiQuaternion.h index 41373dad1..d44f22ddb 100644 --- a/include/aiQuaternion.h +++ b/include/aiQuaternion.h @@ -211,41 +211,41 @@ inline aiQuaternion::aiQuaternion( aiVector3D normalized) // Congrats, gmtl! inline void aiQuaternion::Interpolate( aiQuaternion& pOut, const aiQuaternion& pStart, const aiQuaternion& pEnd, float pFactor) { - // calc cosine theta - float cosom = pStart.x * pEnd.x + pStart.y * pEnd.y + pStart.z * pEnd.z + pStart.w * pEnd.w; - - // adjust signs (if necessary) - aiQuaternion end = pEnd; - if( cosom < 0.0f) - { - cosom = -cosom; - end.x = -end.x; // Reverse all signs - end.y = -end.y; - end.z = -end.z; - end.w = -end.w; - } - - // Calculate coefficients - float sclp, sclq; - if( (1.0f - cosom) > 0.0001f) // 0.0001 -> some epsillon - { - // Standard case (slerp) - float omega, sinom; - omega = acos( cosom); // extract theta from dot product's cos theta - sinom = sin( omega); - sclp = sin( (1.0f - pFactor) * omega) / sinom; - sclq = sin( pFactor * omega) / sinom; - } else - { - // Very close, do linear interp (because it's faster) - sclp = 1.0f - pFactor; - sclq = pFactor; - } - - pOut.x = sclp * pStart.x + sclq * end.x; - pOut.y = sclp * pStart.y + sclq * end.y; - pOut.z = sclp * pStart.z + sclq * end.z; - pOut.w = sclp * pStart.w + sclq * end.w; + // calc cosine theta + float cosom = pStart.x * pEnd.x + pStart.y * pEnd.y + pStart.z * pEnd.z + pStart.w * pEnd.w; + + // adjust signs (if necessary) + aiQuaternion end = pEnd; + if( cosom < 0.0f) + { + cosom = -cosom; + end.x = -end.x; // Reverse all signs + end.y = -end.y; + end.z = -end.z; + end.w = -end.w; + } + + // Calculate coefficients + float sclp, sclq; + if( (1.0f - cosom) > 0.0001f) // 0.0001 -> some epsillon + { + // Standard case (slerp) + float omega, sinom; + omega = acos( cosom); // extract theta from dot product's cos theta + sinom = sin( omega); + sclp = sin( (1.0f - pFactor) * omega) / sinom; + sclq = sin( pFactor * omega) / sinom; + } else + { + // Very close, do linear interp (because it's faster) + sclp = 1.0f - pFactor; + sclq = pFactor; + } + + pOut.x = sclp * pStart.x + sclq * end.x; + pOut.y = sclp * pStart.y + sclq * end.y; + pOut.z = sclp * pStart.z + sclq * end.z; + pOut.w = sclp * pStart.w + sclq * end.w; } } // end extern "C"