diff --git a/code/AssimpPCH.h b/code/AssimpPCH.h index a22cf340e..cf5dddc38 100644 --- a/code/AssimpPCH.h +++ b/code/AssimpPCH.h @@ -120,5 +120,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif + #endif // !! ASSIMP_PCH_INCLUDED diff --git a/code/ComputeUVMappingProcess.cpp b/code/ComputeUVMappingProcess.cpp index 4ad0a7add..328a01293 100644 --- a/code/ComputeUVMappingProcess.cpp +++ b/code/ComputeUVMappingProcess.cpp @@ -139,8 +139,8 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out) const static float LOWER_LIMIT = 0.1f; const static float UPPER_LIMIT = 0.9f; - const static float LOWER_EPSILON = 1e-3f; - const static float UPPER_EPSILON = 1.f-1e-3f; + const static float LOWER_EPSILON = 10e-3f; + const static float UPPER_EPSILON = 1.f-10e-3f; for (unsigned int fidx = 0; fidx < mesh->mNumFaces;++fidx) { diff --git a/code/IRRLoader.cpp b/code/IRRLoader.cpp index d312d5da0..a3c79a3ba 100644 --- a/code/IRRLoader.cpp +++ b/code/IRRLoader.cpp @@ -917,7 +917,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) - rootOut->mTransformation.FromEulerAngles(AI_DEG_TO_RAD(root->rotation) ); + rootOut->mTransformation.FromEulerAnglesXYZ(AI_DEG_TO_RAD(root->rotation) ); // apply scaling aiMatrix4x4& mat = rootOut->mTransformation; diff --git a/code/LWOMaterial.cpp b/code/LWOMaterial.cpp index d1124613d..1aa84ce03 100644 --- a/code/LWOMaterial.cpp +++ b/code/LWOMaterial.cpp @@ -147,6 +147,8 @@ bool LWOImporter::HandleTextures(MaterialHelper* pcMat, const TextureList& in, a aiUVTransform trafo; trafo.mScaling.x = (*it).wrapAmountW; trafo.mScaling.y = (*it).wrapAmountH; + + pcMat->AddProperty((float*)&trafo,sizeof(aiUVTransform),AI_MATKEY_UVTRANSFORM(type,cur)); } DefaultLogger::get()->debug("LWO2: Setting up non-UV mapping"); } diff --git a/code/MD2FileData.h b/code/MD2FileData.h index 7a0ac94c6..45981becb 100644 --- a/code/MD2FileData.h +++ b/code/MD2FileData.h @@ -144,8 +144,8 @@ struct Frame */ struct TexCoord { - uint16_t s; - uint16_t t; + int16_t s; + int16_t t; } PACK_STRUCT; // --------------------------------------------------------------------------- diff --git a/code/MD2Loader.cpp b/code/MD2Loader.cpp index 5203856e0..ddfc1d88e 100644 --- a/code/MD2Loader.cpp +++ b/code/MD2Loader.cpp @@ -413,8 +413,8 @@ void MD2Importer::InternReadFile( const std::string& pFile, // the texture coordinates are absolute values but we // need relative values between 0 and 1 - pcOut.x = pcTexCoords[iIndex].s / fDivisorU; - pcOut.y = 1.f - pcTexCoords[iIndex].t / fDivisorV; + pcOut.y = pcTexCoords[iIndex].s / fDivisorU; + pcOut.x = pcTexCoords[iIndex].t / fDivisorV; } } // FIX: flip the face order for use with OpenGL diff --git a/code/NFFLoader.cpp b/code/NFFLoader.cpp index ff99015d5..53c3ba98a 100644 --- a/code/NFFLoader.cpp +++ b/code/NFFLoader.cpp @@ -665,32 +665,66 @@ void NFFImporter::InternReadFile( const std::string& pFile, // 'tpp' - texture polygon patch primitive if ('t' == line[0]) { - if (meshesWithUVCoords.empty()) + currentMeshWithUVCoords = NULL; + for (std::vector::iterator it = meshesWithUVCoords.begin(), end = meshesWithUVCoords.end(); + it != end;++it) + { + if ((*it).shader == s) + { + currentMeshWithUVCoords = &(*it); + break; + } + } + + if (!currentMeshWithUVCoords) { meshesWithUVCoords.push_back(MeshInfo(PatchType_UVAndNormals)); currentMeshWithUVCoords = &meshesWithUVCoords.back(); + currentMeshWithUVCoords->shader = s; } - out = currentMeshWithUVCoords; } // 'pp' - polygon patch primitive else if ('p' == line[1]) { - if (meshesWithNormals.empty()) + currentMeshWithNormals = NULL; + for (std::vector::iterator it = meshesWithNormals.begin(), end = meshesWithNormals.end(); + it != end;++it) + { + if ((*it).shader == s) + { + currentMeshWithNormals = &(*it); + break; + } + } + + if (!currentMeshWithNormals) { meshesWithNormals.push_back(MeshInfo(PatchType_Normals)); currentMeshWithNormals = &meshesWithNormals.back(); + currentMeshWithNormals->shader = s; } - sz = &line[2];out = currentMeshWithNormals; } // 'p' - polygon primitive else { - if (meshes.empty()) + currentMesh = NULL; + for (std::vector::iterator it = meshes.begin(), end = meshes.end(); + it != end;++it) + { + if ((*it).shader == s) + { + currentMesh = &(*it); + break; + } + } + + if (!currentMesh) { meshes.push_back(MeshInfo(PatchType_Simple)); currentMesh = &meshes.back(); + currentMesh->shader = s; } sz = &line[1];out = currentMesh; } @@ -711,7 +745,7 @@ void NFFImporter::InternReadFile( const std::string& pFile, { if(!GetNextLine(buffer,line)) { - DefaultLogger::get()->error("NFF: Unexpected EOF was encountered"); + DefaultLogger::get()->error("NFF: Unexpected EOF was encountered. Patch definition incomplete"); continue; } @@ -764,7 +798,7 @@ void NFFImporter::InternReadFile( const std::string& pFile, // NFF2 uses full colors here so we need to use them too // although NFF uses simple scaling factors - s.diffuse.g = s.diffuse.b = s.diffuse.r; + s.diffuse.g = s.diffuse.b = s.diffuse.r; s.specular.g = s.specular.b = s.specular.r; // if the next one is NOT a number we assume it is a texture file name @@ -787,58 +821,14 @@ void NFFImporter::InternReadFile( const std::string& pFile, { AI_NFF_PARSE_FLOAT(s.ambient); // optional } - - // check whether we have this material already - - // although we have the RRM-Step, this is necessary here. - // otherwise we would generate hundreds of small meshes - // with just a few faces - this is surely never wanted. - currentMesh = currentMeshWithNormals = currentMeshWithUVCoords = NULL; - for (std::vector::iterator it = meshes.begin(), end = meshes.end(); - it != end;++it) - { - if ((*it).bLocked)continue; - if ((*it).shader == s) - { - switch ((*it).pType) - { - case PatchType_Normals: - currentMeshWithNormals = &(*it); - break; - - case PatchType_Simple: - currentMesh = &(*it); - break; - - default: - currentMeshWithUVCoords = &(*it); - break; - }; - } - } - - if (!currentMesh) - { - meshes.push_back(MeshInfo(PatchType_Simple)); - currentMesh = &meshes.back(); - currentMesh->shader = s; - } - if (!currentMeshWithNormals) - { - meshesWithNormals.push_back(MeshInfo(PatchType_Normals)); - currentMeshWithNormals = &meshesWithNormals.back(); - currentMeshWithNormals->shader = s; - } - if (!currentMeshWithUVCoords) - { - meshesWithUVCoords.push_back(MeshInfo(PatchType_UVAndNormals)); - currentMeshWithUVCoords = &meshesWithUVCoords.back(); - currentMeshWithUVCoords->shader = s; - } } // 'shader' - other way to specify a texture else if (TokenMatch(sz,"shader",6)) { - // todo + SkipSpaces(&sz); + const char* old = sz; + while (!IsSpaceOrNewLine(*sz))++sz; + s.texFile = std::string(old, (uintptr_t)sz - (uintptr_t)old); } // 'l' - light source else if (TokenMatch(sz,"l",1)) @@ -856,7 +846,7 @@ void NFFImporter::InternReadFile( const std::string& pFile, meshesLocked.push_back(MeshInfo(PatchType_Simple,true)); MeshInfo& currentMesh = meshesLocked.back(); currentMesh.shader = s; - s.mapping = aiTextureMapping_SPHERE; + currentMesh.shader.mapping = aiTextureMapping_SPHERE; AI_NFF_PARSE_SHAPE_INFORMATION(); @@ -873,7 +863,7 @@ void NFFImporter::InternReadFile( const std::string& pFile, meshesLocked.push_back(MeshInfo(PatchType_Simple,true)); MeshInfo& currentMesh = meshesLocked.back(); currentMesh.shader = s; - s.mapping = aiTextureMapping_SPHERE; + currentMesh.shader.mapping = aiTextureMapping_SPHERE; AI_NFF_PARSE_SHAPE_INFORMATION(); @@ -891,7 +881,7 @@ void NFFImporter::InternReadFile( const std::string& pFile, meshesLocked.push_back(MeshInfo(PatchType_Simple,true)); MeshInfo& currentMesh = meshesLocked.back(); currentMesh.shader = s; - s.mapping = aiTextureMapping_SPHERE; + currentMesh.shader.mapping = aiTextureMapping_SPHERE; AI_NFF_PARSE_SHAPE_INFORMATION(); @@ -909,7 +899,7 @@ void NFFImporter::InternReadFile( const std::string& pFile, meshesLocked.push_back(MeshInfo(PatchType_Simple,true)); MeshInfo& currentMesh = meshesLocked.back(); currentMesh.shader = s; - s.mapping = aiTextureMapping_SPHERE; + currentMesh.shader.mapping = aiTextureMapping_SPHERE; AI_NFF_PARSE_SHAPE_INFORMATION(); @@ -927,7 +917,7 @@ void NFFImporter::InternReadFile( const std::string& pFile, meshesLocked.push_back(MeshInfo(PatchType_Simple,true)); MeshInfo& currentMesh = meshesLocked.back(); currentMesh.shader = s; - s.mapping = aiTextureMapping_SPHERE; + currentMesh.shader.mapping = aiTextureMapping_BOX; AI_NFF_PARSE_SHAPE_INFORMATION(); @@ -942,26 +932,54 @@ void NFFImporter::InternReadFile( const std::string& pFile, else if (TokenMatch(sz,"c",1)) { meshesLocked.push_back(MeshInfo(PatchType_Simple,true)); - MeshInfo& currentMesh = meshes.back(); + MeshInfo& currentMesh = meshesLocked.back(); currentMesh.shader = s; - s.mapping = aiTextureMapping_CYLINDER; + currentMesh.shader.mapping = aiTextureMapping_CYLINDER; + if(!GetNextLine(buffer,line)) + { + DefaultLogger::get()->error("NFF: Unexpected end of file (cone definition not complete)"); + break; + } + sz = line; + + // read the two center points and the respective radii aiVector3D center1, center2; float radius1, radius2; AI_NFF_PARSE_TRIPLE(center1); AI_NFF_PARSE_FLOAT(radius1); + + if(!GetNextLine(buffer,line)) + { + DefaultLogger::get()->error("NFF: Unexpected end of file (cone definition not complete)"); + break; + } + sz = line; + AI_NFF_PARSE_TRIPLE(center2); AI_NFF_PARSE_FLOAT(radius2); - // compute the center point of the cone/cylinder - center2 = (center2-center1)/2.f; - currentMesh.center = center1+center2; - center1 = -center2; + // compute the center point of the cone/cylinder - + // it is its local transformation origin + currentMesh.dir = center2-center1; + currentMesh.center = center1+currentMesh.dir/2.f; + + float f; + if (( f = currentMesh.dir.Length()) < 10e-3f ) + { + DefaultLogger::get()->error("NFF: Cone height is close to zero"); + continue; + } + currentMesh.dir /= f; // normalize // generate the cone - it consists of simple triangles - StandardShapes::MakeCone(center1, radius1, center2, radius2, iTesselation, currentMesh.vertices); + StandardShapes::MakeCone(f, radius1, radius2, + integer_pow(4, iTesselation), currentMesh.vertices); + + // MakeCone() returns tris currentMesh.faces.resize(currentMesh.vertices.size()/3,3); - // generate a name for the mesh + // generate a name for the mesh. 'cone' if it a cone, + // 'cylinder' if it is a cylinder. Funny, isn't it? if (radius1 != radius2) ::sprintf(currentMesh.name,"cone_%i",cone++); else ::sprintf(currentMesh.name,"cylinder_%i",cylinder++); @@ -1125,13 +1143,16 @@ void NFFImporter::InternReadFile( const std::string& pFile, node->mName.Set(src.name); // setup the transformation matrix of the node - node->mTransformation.a4 = src.center.x; - node->mTransformation.b4 = src.center.y; - node->mTransformation.c4 = src.center.z; + aiMatrix4x4::FromToMatrix(aiVector3D(0.f,1.f,0.f), + src.dir,node->mTransformation); - node->mTransformation.a1 = src.radius.x; - node->mTransformation.b2 = src.radius.y; - node->mTransformation.c3 = src.radius.z; + aiMatrix4x4& mat = node->mTransformation; + mat.a1 *= src.radius.x; mat.b1 *= src.radius.x; mat.c1 *= src.radius.x; + mat.a2 *= src.radius.y; mat.b2 *= src.radius.y; mat.c2 *= src.radius.y; + mat.a3 *= src.radius.z; mat.b3 *= src.radius.z; mat.c3 *= src.radius.z; + mat.a4 = src.center.x; + mat.b4 = src.center.y; + mat.c4 = src.center.z; ++ppcChildren; } @@ -1194,7 +1215,8 @@ void NFFImporter::InternReadFile( const std::string& pFile, s.Set(AI_DEFAULT_MATERIAL_NAME); pcMat->AddProperty(&s, AI_MATKEY_NAME); - aiColor3D c = src.shader.color * src.shader.diffuse; + // FIX: Ignore diffuse == 0 + aiColor3D c = src.shader.color * (src.shader.diffuse.r ? src.shader.diffuse : aiColor3D(1.f,1.f,1.f)); pcMat->AddProperty(&c,1,AI_MATKEY_COLOR_DIFFUSE); c = src.shader.color * src.shader.specular; pcMat->AddProperty(&c,1,AI_MATKEY_COLOR_SPECULAR); @@ -1209,6 +1231,9 @@ void NFFImporter::InternReadFile( const std::string& pFile, { s.Set(src.shader.texFile); pcMat->AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0)); + + if (aiTextureMapping_UV != src.shader.mapping) + pcMat->AddProperty((int*)&src.shader.mapping, 1,AI_MATKEY_MAPPING_DIFFUSE(0)); } // setup the name of the material @@ -1218,11 +1243,6 @@ void NFFImporter::InternReadFile( const std::string& pFile, pcMat->AddProperty(&s,AI_MATKEY_NAME); } - if (aiTextureMapping_UV != src.shader.mapping) - { - pcMat->AddProperty((int*)&src.shader.mapping, 1,AI_MATKEY_MAPPING_DIFFUSE(0)); - } - // setup some more material properties that are specific to NFF2 int i; if (src.shader.twoSided) diff --git a/code/NFFLoader.h b/code/NFFLoader.h index 762dda1dc..93a5845c5 100644 --- a/code/NFFLoader.h +++ b/code/NFFLoader.h @@ -174,6 +174,7 @@ private: , bLocked (bL) , matIndex (0) , radius (1.f,1.f,1.f) + , dir (0.f,1.f,0.f) { name[0] = '\0'; // by default meshes are unnamed } @@ -183,7 +184,7 @@ private: bool bLocked; // for spheres, cones and cylinders: center point of the object - aiVector3D center, radius; + aiVector3D center, radius, dir; char name[128]; diff --git a/code/SMDLoader.cpp b/code/SMDLoader.cpp index 9e9cccc5f..4321aac2d 100644 --- a/code/SMDLoader.cpp +++ b/code/SMDLoader.cpp @@ -46,7 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // internal headers #include "SMDLoader.h" #include "fast_atof.h" - +#include "SkeletonMeshBuilder.h" using namespace Assimp; @@ -93,6 +93,7 @@ bool SMDImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const } return true; } + // ------------------------------------------------------------------------------------------------ // Setup configuration properties void SMDImporter::SetupProperties(const Importer* pImp) @@ -105,6 +106,7 @@ void SMDImporter::SetupProperties(const Importer* pImp) configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0); } } + // ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. void SMDImporter::InternReadFile( @@ -120,7 +122,7 @@ void SMDImporter::InternReadFile( iFileSize = (unsigned int)file->FileSize(); - // allocate storage and copy the contents of the file to a memory buffer + // Allocate storage and copy the contents of the file to a memory buffer this->pScene = pScene; std::vector buff(iFileSize+1); @@ -132,20 +134,20 @@ void SMDImporter::InternReadFile( bHasUVs = true; iLineNumber = 1; - // reserve enough space for ... hm ... 10 textures + // Reserve enough space for ... hm ... 10 textures aszTextures.reserve(10); - // reserve enough space for ... hm ... 1000 triangles + // Reserve enough space for ... hm ... 1000 triangles asTriangles.reserve(1000); - // reserve enough space for ... hm ... 20 bones + // Reserve enough space for ... hm ... 20 bones asBones.reserve(20); // parse the file ... ParseFile(); - // if there are no triangles it seems to be an animation SMD, + // If there are no triangles it seems to be an animation SMD, // containing only the animation skeleton. if (asTriangles.empty()) { @@ -154,14 +156,15 @@ void SMDImporter::InternReadFile( throw new ImportErrorException("SMD: No triangles and no bones have " "been found in the file. This file seems to be invalid."); } - // set the flag in the scene structure which indicates + + // Set the flag in the scene structure which indicates // that there is nothing than an animation skeleton pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; } if (!asBones.empty()) { - // check whether all bones have been initialized + // Check whether all bones have been initialized for (std::vector::const_iterator i = asBones.begin(); i != asBones.end();++i) @@ -177,8 +180,9 @@ void SMDImporter::InternReadFile( FixTimeValues(); // compute absolute bone transformation matrices - ComputeAbsoluteBoneTransformations(); + // ComputeAbsoluteBoneTransformations(); } + if (!(pScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE)) { // create output meshes @@ -193,36 +197,30 @@ void SMDImporter::InternReadFile( // build output nodes (bones are added as empty dummy nodes) CreateOutputNodes(); + + if (pScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE) + { + SkeletonMeshBuilder skeleton(pScene); + } } // ------------------------------------------------------------------------------------------------ // Write an error message with line number to the log file void SMDImporter::LogErrorNoThrow(const char* msg) { char szTemp[1024]; - -#if _MSC_VER >= 1400 - sprintf_s(szTemp,"Line %i: %s",iLineNumber,msg); -#else - ai_assert(strlen(msg) < 1000); sprintf(szTemp,"Line %i: %s",iLineNumber,msg); -#endif - DefaultLogger::get()->error(szTemp); } + // ------------------------------------------------------------------------------------------------ // Write a warning with line number to the log file void SMDImporter::LogWarning(const char* msg) { char szTemp[1024]; - -#if _MSC_VER >= 1400 - sprintf_s(szTemp,"Line %i: %s",iLineNumber,msg); -#else ai_assert(strlen(msg) < 1000); - sprintf(szTemp,"Line %i: %s",iLineNumber,msg); -#endif DefaultLogger::get()->warn(szTemp); } + // ------------------------------------------------------------------------------------------------ // Fix invalid time values in the file void SMDImporter::FixTimeValues() @@ -243,10 +241,14 @@ void SMDImporter::FixTimeValues() } dLengthOfAnim = dMax; } + // ------------------------------------------------------------------------------------------------ // create output meshes void SMDImporter::CreateOutputMeshes() { + if (aszTextures.empty()) + aszTextures.push_back(std::string()); + // we need to sort all faces by their material index // in opposition to other loaders we can be sure that each // material is at least used once. @@ -260,9 +262,8 @@ void SMDImporter::CreateOutputMeshes() unsigned int iNum = (unsigned int)asTriangles.size() / pScene->mNumMeshes; iNum += iNum >> 1; for (unsigned int i = 0; i < pScene->mNumMeshes;++i) - { aaiFaces[i].reserve(iNum); - } + // collect all faces iNum = 0; @@ -402,10 +403,9 @@ void SMDImporter::CreateOutputMeshes() // now build all bones of the mesh iNum = 0; for (unsigned int iBone = 0; iBone < asBones.size();++iBone) - { if (!aaiBones[iBone].empty())++iNum; - } - if (iNum) + + if (false && iNum) { pcMesh->mNumBones = iNum; pcMesh->mBones = new aiBone*[pcMesh->mNumBones]; @@ -430,11 +430,11 @@ void SMDImporter::CreateOutputMeshes() ++iNum; } } - delete[] aaiBones; } delete[] aaiFaces; } + // ------------------------------------------------------------------------------------------------ // add bone child nodes void SMDImporter::AddBoneChildren(aiNode* pcNode, uint32_t iParent) @@ -469,6 +469,7 @@ void SMDImporter::AddBoneChildren(aiNode* pcNode, uint32_t iParent) AddBoneChildren(pc,i); } } + // ------------------------------------------------------------------------------------------------ // create output nodes void SMDImporter::CreateOutputNodes() @@ -484,7 +485,7 @@ void SMDImporter::CreateOutputNodes() } // now add all bones as dummy sub nodes to the graph - AddBoneChildren(pScene->mRootNode,(uint32_t)-1); + // AddBoneChildren(pScene->mRootNode,(uint32_t)-1); // if we have only one bone we can even remove the root node if (pScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE && @@ -503,6 +504,7 @@ void SMDImporter::CreateOutputNodes() pScene->mRootNode->mName.length = 10; } } + // ------------------------------------------------------------------------------------------------ // create output animations void SMDImporter::CreateOutputAnimations() @@ -569,10 +571,11 @@ void SMDImporter::CreateOutputAnimations() // there are no scaling keys ... } } + // ------------------------------------------------------------------------------------------------ void SMDImporter::ComputeAbsoluteBoneTransformations() { - // for each bone: determine the key with the lowest time value + // For each bone: determine the key with the lowest time value // theoretically the SMD format should have all keyframes // in order. However, I've seen a file where this wasn't true. for (unsigned int i = 0; i < asBones.size();++i) @@ -609,27 +612,27 @@ void SMDImporter::ComputeAbsoluteBoneTransformations() const aiMatrix4x4& mat = bone.sAnim.asKeys[iIndex].matrix; aiMatrix4x4& matOut = bone.sAnim.asKeys[iIndex].matrixAbsolute; - // the same for the parent bone ... + // The same for the parent bone ... iIndex = parentBone.sAnim.iFirstTimeKey; - const aiMatrix4x4& mat2 = parentBone.sAnim.asKeys[iIndex].matrix; + const aiMatrix4x4& mat2 = parentBone.sAnim.asKeys[iIndex].matrixAbsolute; - // compute the absolute transformation matrix + // Compute the absolute transformation matrix matOut = mat * mat2; } } ++iParent; } - // store the inverse of the absolute transformation matrix + // Store the inverse of the absolute transformation matrix // of the first key as bone offset matrix for (iParent = 0; iParent < asBones.size();++iParent) { SMD::Bone& bone = asBones[iParent]; - aiMatrix4x4& mat = bone.sAnim.asKeys[bone.sAnim.iFirstTimeKey].matrixAbsolute; - bone.mOffsetMatrix = mat; + bone.mOffsetMatrix = bone.sAnim.asKeys[bone.sAnim.iFirstTimeKey].matrixAbsolute; bone.mOffsetMatrix.Inverse(); } } + // ------------------------------------------------------------------------------------------------ // create output materials void SMDImporter::CreateOutputMaterials() @@ -646,9 +649,12 @@ void SMDImporter::CreateOutputMaterials() szName.length = (size_t)::sprintf(szName.data,"Texture_%i",iMat); pcMat->AddProperty(&szName,AI_MATKEY_NAME); - ::strcpy(szName.data, aszTextures[iMat].c_str() ); - szName.length = aszTextures[iMat].length(); - pcMat->AddProperty(&szName,AI_MATKEY_TEXTURE_DIFFUSE(0)); + if (aszTextures[iMat].length()) + { + ::strcpy(szName.data, aszTextures[iMat].c_str() ); + szName.length = aszTextures[iMat].length(); + pcMat->AddProperty(&szName,AI_MATKEY_TEXTURE_DIFFUSE(0)); + } } // create a default material if necessary @@ -675,6 +681,7 @@ void SMDImporter::CreateOutputMaterials() pcHelper->AddProperty(&szName,AI_MATKEY_NAME); } } + // ------------------------------------------------------------------------------------------------ // Parse the file void SMDImporter::ParseFile() @@ -687,10 +694,8 @@ void SMDImporter::ParseFile() if(!SkipSpacesAndLineEnd(szCurrent,&szCurrent)) break; // "version \n", should be 1 for hl and hl² SMD files - if (0 == ASSIMP_strincmp(szCurrent,"version",7) && - IsSpaceOrNewLine(*(szCurrent+7))) + if (TokenMatch(szCurrent,"version",7)) { - szCurrent += 8; if(!SkipSpaces(szCurrent,&szCurrent)) break; if (1 != strtol10(szCurrent,&szCurrent)) { @@ -700,35 +705,27 @@ void SMDImporter::ParseFile() continue; } // "nodes\n" - Starts the node section - if (0 == ASSIMP_strincmp(szCurrent,"nodes",5) && - IsSpaceOrNewLine(*(szCurrent+5))) + if (TokenMatch(szCurrent,"nodes",5)) { - szCurrent += 6; ParseNodesSection(szCurrent,&szCurrent); continue; } // "triangles\n" - Starts the triangle section - if (0 == ASSIMP_strincmp(szCurrent,"triangles",9) && - IsSpaceOrNewLine(*(szCurrent+9))) + if (TokenMatch(szCurrent,"triangles",9)) { - szCurrent += 10; ParseTrianglesSection(szCurrent,&szCurrent); continue; } // "vertexanimation\n" - Starts the vertex animation section - if (0 == ASSIMP_strincmp(szCurrent,"vertexanimation",15) && - IsSpaceOrNewLine(*(szCurrent+15))) + if (TokenMatch(szCurrent,"vertexanimation",15)) { bHasUVs = false; - szCurrent += 16; ParseVASection(szCurrent,&szCurrent); continue; } // "skeleton\n" - Starts the skeleton section - if (0 == ASSIMP_strincmp(szCurrent,"skeleton",8) && - IsSpaceOrNewLine(*(szCurrent+8))) + if (TokenMatch(szCurrent,"skeleton",8)) { - szCurrent += 9; ParseSkeletonSection(szCurrent,&szCurrent); continue; } @@ -736,6 +733,7 @@ void SMDImporter::ParseFile() } return; } + // ------------------------------------------------------------------------------------------------ unsigned int SMDImporter::GetTextureIndex(const std::string& filename) { @@ -744,13 +742,14 @@ unsigned int SMDImporter::GetTextureIndex(const std::string& filename) i = aszTextures.begin(); i != aszTextures.end();++i,++iIndex) { - // case-insensitive ... just for safety + // case-insensitive ... it's a path if (0 == ASSIMP_stricmp ( filename.c_str(),(*i).c_str()))return iIndex; } iIndex = (unsigned int)aszTextures.size(); aszTextures.push_back(filename); return iIndex; } + // ------------------------------------------------------------------------------------------------ // Parse the nodes section of the file void SMDImporter::ParseNodesSection(const char* szCurrent, @@ -770,24 +769,21 @@ void SMDImporter::ParseNodesSection(const char* szCurrent, SkipSpacesAndLineEnd(szCurrent,&szCurrent); *szCurrentOut = szCurrent; } + // ------------------------------------------------------------------------------------------------ // Parse the triangles section of the file void SMDImporter::ParseTrianglesSection(const char* szCurrent, const char** szCurrentOut) { - // parse a triangle, parse another triangle, parse the next triangle ... + // Parse a triangle, parse another triangle, parse the next triangle ... // and so on until we reach a token that looks quite similar to "end" while (true) { if(!SkipSpacesAndLineEnd(szCurrent,&szCurrent)) break; // "end\n" - Ends the triangles section - if (0 == ASSIMP_strincmp(szCurrent,"end",3) && - IsSpaceOrNewLine(*(szCurrent+3))) - { - szCurrent += 4; + if (TokenMatch(szCurrent,"end",3)) break; - } ParseTriangle(szCurrent,&szCurrent); } SkipSpacesAndLineEnd(szCurrent,&szCurrent); @@ -804,39 +800,33 @@ void SMDImporter::ParseVASection(const char* szCurrent, if(!SkipSpacesAndLineEnd(szCurrent,&szCurrent)) break; // "end\n" - Ends the "vertexanimation" section - if (0 == ASSIMP_strincmp(szCurrent,"end",3) && - IsSpaceOrNewLine(*(szCurrent+3))) - { - szCurrent += 4; - //SkipLine(szCurrent,&szCurrent); + if (TokenMatch(szCurrent,"end",3)) break; - } + // "time \n" - if (0 == ASSIMP_strincmp(szCurrent,"time",4) && - IsSpaceOrNewLine(*(szCurrent+4))) + if (TokenMatch(szCurrent,"time",4)) { - szCurrent += 5; // NOTE: The doc says that time values COULD be negative ... - // note2: this is the shape key -> valve docs + // NOTE2: this is the shape key -> valve docs int iTime = 0; if(!ParseSignedInt(szCurrent,&szCurrent,iTime) || configFrameID != (unsigned int)iTime)break; SkipLine(szCurrent,&szCurrent); } else { - ParseVertex(szCurrent,&szCurrent,asTriangles.back().avVertices[iCurIndex],true); - if(3 == ++iCurIndex) + if(0 == iCurIndex) { asTriangles.push_back(SMD::Face()); - iCurIndex = 0; } + if (++iCurIndex == 3)iCurIndex = 0; + ParseVertex(szCurrent,&szCurrent,asTriangles.back().avVertices[iCurIndex],true); } } - if (iCurIndex) + if (iCurIndex != 2 && !asTriangles.empty()) { - // no degenerates, so let this triangle - aszTextures.pop_back(); + // we want to no degenerates, so throw this triangle away + asTriangles.pop_back(); } SkipSpacesAndLineEnd(szCurrent,&szCurrent); @@ -853,18 +843,12 @@ void SMDImporter::ParseSkeletonSection(const char* szCurrent, if(!SkipSpacesAndLineEnd(szCurrent,&szCurrent)) break; // "end\n" - Ends the skeleton section - if (0 == ASSIMP_strincmp(szCurrent,"end",3) && - IsSpaceOrNewLine(*(szCurrent+3))) - { - szCurrent += 4; - //SkipLine(szCurrent,&szCurrent); + if (TokenMatch(szCurrent,"end",3)) break; - } + // "time \n" - Specifies the current animation frame - else if (0 == ASSIMP_strincmp(szCurrent,"time",4) && - IsSpaceOrNewLine(*(szCurrent+4))) + else if (TokenMatch(szCurrent,"time",4)) { - szCurrent += 5; // NOTE: The doc says that time values COULD be negative ... if(!ParseSignedInt(szCurrent,&szCurrent,iTime))break; @@ -876,12 +860,12 @@ void SMDImporter::ParseSkeletonSection(const char* szCurrent, *szCurrentOut = szCurrent; } +// ------------------------------------------------------------------------------------------------ #define SMDI_PARSE_RETURN { \ SkipLine(szCurrent,&szCurrent); \ *szCurrentOut = szCurrent; \ return; \ } - // ------------------------------------------------------------------------------------------------ // Parse a node line void SMDImporter::ParseNodeInfo(const char* szCurrent, @@ -941,6 +925,7 @@ void SMDImporter::ParseNodeInfo(const char* szCurrent, // go to the beginning of the next line SMDI_PARSE_RETURN; } + // ------------------------------------------------------------------------------------------------ // Parse a skeleton element void SMDImporter::ParseSkeletonElement(const char* szCurrent, @@ -997,7 +982,7 @@ void SMDImporter::ParseSkeletonElement(const char* szCurrent, SMDI_PARSE_RETURN; } // build the transformation matrix of the key - key.matrix.FromEulerAngles(vRot.x,vRot.y,vRot.z); + key.matrix.FromEulerAnglesXYZ(vRot.x,vRot.y,vRot.z); { aiMatrix4x4 mTemp; mTemp.a4 = vPos.x; @@ -1009,6 +994,7 @@ void SMDImporter::ParseSkeletonElement(const char* szCurrent, // go to the beginning of the next line SMDI_PARSE_RETURN; } + // ------------------------------------------------------------------------------------------------ // Parse a triangle void SMDImporter::ParseTriangle(const char* szCurrent, @@ -1027,10 +1013,10 @@ void SMDImporter::ParseTriangle(const char* szCurrent, const char* szLast = szCurrent; while (!IsSpaceOrNewLine(*szCurrent++)); - face.iTexture = GetTextureIndex(std::string(szLast, - (uintptr_t)szCurrent-(uintptr_t)szLast)); + // ... and get the index that belongs to this file name + face.iTexture = GetTextureIndex(std::string(szLast,(uintptr_t)szCurrent-(uintptr_t)szLast)); - SkipLine(szCurrent,&szCurrent); + SkipSpacesAndLineEnd(szCurrent,&szCurrent); // load three vertices for (unsigned int iVert = 0; iVert < 3;++iVert) @@ -1040,6 +1026,7 @@ void SMDImporter::ParseTriangle(const char* szCurrent, } *szCurrentOut = szCurrent; } + // ------------------------------------------------------------------------------------------------ // Parse a float bool SMDImporter::ParseFloat(const char* szCurrent, @@ -1051,6 +1038,7 @@ bool SMDImporter::ParseFloat(const char* szCurrent, *szCurrentOut = fast_atof_move(szCurrent,out); return true; } + // ------------------------------------------------------------------------------------------------ // Parse an unsigned int bool SMDImporter::ParseUnsignedInt(const char* szCurrent, @@ -1062,6 +1050,7 @@ bool SMDImporter::ParseUnsignedInt(const char* szCurrent, out = strtol10(szCurrent,szCurrentOut); return true; } + // ------------------------------------------------------------------------------------------------ // Parse a signed int bool SMDImporter::ParseSignedInt(const char* szCurrent, @@ -1073,6 +1062,7 @@ bool SMDImporter::ParseSignedInt(const char* szCurrent, out = strtol10s(szCurrent,szCurrentOut); return true; } + // ------------------------------------------------------------------------------------------------ // Parse a vertex void SMDImporter::ParseVertex(const char* szCurrent, @@ -1143,8 +1133,10 @@ void SMDImporter::ParseVertex(const char* szCurrent, i = vertex.aiBoneLinks.begin(); i != vertex.aiBoneLinks.end();++i) { - if(!ParseUnsignedInt(szCurrent,&szCurrent,(*i).first))SMDI_PARSE_RETURN; - if(!ParseFloat(szCurrent,&szCurrent,(*i).second))SMDI_PARSE_RETURN; + if(!ParseUnsignedInt(szCurrent,&szCurrent,(*i).first)) + SMDI_PARSE_RETURN; + if(!ParseFloat(szCurrent,&szCurrent,(*i).second)) + SMDI_PARSE_RETURN; } // go to the beginning of the next line diff --git a/code/StandardShapes.cpp b/code/StandardShapes.cpp index 58979af1c..c914e73af 100644 --- a/code/StandardShapes.cpp +++ b/code/StandardShapes.cpp @@ -114,6 +114,7 @@ aiMesh* StandardShapes::MakeMesh(const std::vector& positions, { if (positions.size() & numIndices || positions.empty() || !numIndices)return NULL; + // Determine which kinds of primitives the mesh will consist of aiMesh* out = new aiMesh(); switch (numIndices) { @@ -182,18 +183,18 @@ unsigned int StandardShapes::MakeIcosahedron(std::vector& positions) const float t = (1.f + 2.236067977f)/2.f; const float s = sqrt(1.f + t*t); - aiVector3D v0 = aiVector3D(t,1.f, 0.f)/s; - aiVector3D v1 = aiVector3D(-t,1.f, 0.f)/s; - aiVector3D v2 = aiVector3D(t,-1.f, 0.f)/s; - aiVector3D v3 = aiVector3D(-t,-1.f, 0.f)/s; - aiVector3D v4 = aiVector3D(1.f, 0.f, t)/s; - aiVector3D v5 = aiVector3D(1.f, 0.f,-t)/s; - aiVector3D v6 = aiVector3D(-1.f, 0.f,t)/s; - aiVector3D v7 = aiVector3D(-1.f, 0.f,-t)/s; - aiVector3D v8 = aiVector3D(0.f, t, 1.f)/s; - aiVector3D v9 = aiVector3D(0.f,-t, 1.f)/s; - aiVector3D v10 = aiVector3D(0.f, t,-1.f)/s; - aiVector3D v11 = aiVector3D(0.f,-t,-1.f)/s; + const aiVector3D v0 = aiVector3D(t,1.f, 0.f)/s; + const aiVector3D v1 = aiVector3D(-t,1.f, 0.f)/s; + const aiVector3D v2 = aiVector3D(t,-1.f, 0.f)/s; + const aiVector3D v3 = aiVector3D(-t,-1.f, 0.f)/s; + const aiVector3D v4 = aiVector3D(1.f, 0.f, t)/s; + const aiVector3D v5 = aiVector3D(1.f, 0.f,-t)/s; + const aiVector3D v6 = aiVector3D(-1.f, 0.f,t)/s; + const aiVector3D v7 = aiVector3D(-1.f, 0.f,-t)/s; + const aiVector3D v8 = aiVector3D(0.f, t, 1.f)/s; + const aiVector3D v9 = aiVector3D(0.f,-t, 1.f)/s; + const aiVector3D v10 = aiVector3D(0.f, t,-1.f)/s; + const aiVector3D v11 = aiVector3D(0.f,-t,-1.f)/s; ADD_TRIANGLE(v0,v8,v4); ADD_TRIANGLE(v0,v5,v10); @@ -232,26 +233,26 @@ unsigned int StandardShapes::MakeDodecahedron(std::vector& positions const float b = sqrt((3.f-2.23606797f)/6.f); const float c = sqrt((3.f+2.23606797f)/6.f); - aiVector3D v0 = aiVector3D(a,a,a); - aiVector3D v1 = aiVector3D(a,a,-a); - aiVector3D v2 = aiVector3D(a,-a,a); - aiVector3D v3 = aiVector3D(a,-a,-a); - aiVector3D v4 = aiVector3D(-a,a,a); - aiVector3D v5 = aiVector3D(-a,a,-a); - aiVector3D v6 = aiVector3D(-a,-a,a); - aiVector3D v7 = aiVector3D(-a,-a,-a); - aiVector3D v8 = aiVector3D(b,c,0.f); - aiVector3D v9 = aiVector3D(-b,c,0.f); - aiVector3D v10 = aiVector3D(b,-c,0.f); - aiVector3D v11 = aiVector3D(-b,-c,0.f); - aiVector3D v12 = aiVector3D(c, 0.f, b); - aiVector3D v13 = aiVector3D(c, 0.f, -b); - aiVector3D v14 = aiVector3D(-c, 0.f, b); - aiVector3D v15 = aiVector3D(-c, 0.f, -b); - aiVector3D v16 = aiVector3D(0.f, b, c); - aiVector3D v17 = aiVector3D(0.f, -b, c); - aiVector3D v18 = aiVector3D(0.f, b, -c); - aiVector3D v19 = aiVector3D(0.f, -b, -c); + const aiVector3D v0 = aiVector3D(a,a,a); + const aiVector3D v1 = aiVector3D(a,a,-a); + const aiVector3D v2 = aiVector3D(a,-a,a); + const aiVector3D v3 = aiVector3D(a,-a,-a); + const aiVector3D v4 = aiVector3D(-a,a,a); + const aiVector3D v5 = aiVector3D(-a,a,-a); + const aiVector3D v6 = aiVector3D(-a,-a,a); + const aiVector3D v7 = aiVector3D(-a,-a,-a); + const aiVector3D v8 = aiVector3D(b,c,0.f); + const aiVector3D v9 = aiVector3D(-b,c,0.f); + const aiVector3D v10 = aiVector3D(b,-c,0.f); + const aiVector3D v11 = aiVector3D(-b,-c,0.f); + const aiVector3D v12 = aiVector3D(c, 0.f, b); + const aiVector3D v13 = aiVector3D(c, 0.f, -b); + const aiVector3D v14 = aiVector3D(-c, 0.f, b); + const aiVector3D v15 = aiVector3D(-c, 0.f, -b); + const aiVector3D v16 = aiVector3D(0.f, b, c); + const aiVector3D v17 = aiVector3D(0.f, -b, c); + const aiVector3D v18 = aiVector3D(0.f, b, -c); + const aiVector3D v19 = aiVector3D(0.f, -b, -c); ADD_PENTAGON(v0, v8, v9, v4, v16); ADD_PENTAGON(v0, v12, v13, v1, v8); @@ -274,12 +275,12 @@ unsigned int StandardShapes::MakeOctahedron(std::vector& positions) { positions.reserve(positions.size()+24); - aiVector3D v0 = aiVector3D(1.0f, 0.f, 0.f) ; - aiVector3D v1 = aiVector3D(-1.0f, 0.f, 0.f); - aiVector3D v2 = aiVector3D(0.f, 1.0f, 0.f); - aiVector3D v3 = aiVector3D(0.f, -1.0f, 0.f); - aiVector3D v4 = aiVector3D(0.f, 0.f, 1.0f); - aiVector3D v5 = aiVector3D(0.f, 0.f, -1.0f); + const aiVector3D v0 = aiVector3D(1.0f, 0.f, 0.f) ; + const aiVector3D v1 = aiVector3D(-1.0f, 0.f, 0.f); + const aiVector3D v2 = aiVector3D(0.f, 1.0f, 0.f); + const aiVector3D v3 = aiVector3D(0.f, -1.0f, 0.f); + const aiVector3D v4 = aiVector3D(0.f, 0.f, 1.0f); + const aiVector3D v5 = aiVector3D(0.f, 0.f, -1.0f); ADD_TRIANGLE(v4,v0,v2); ADD_TRIANGLE(v4,v2,v1); @@ -301,10 +302,10 @@ unsigned int StandardShapes::MakeTetrahedron(std::vector& positions) const float a = 1.41421f/3.f; const float b = 2.4494f/3.f; - aiVector3D v0 = aiVector3D(0.f,0.f,1.f); - aiVector3D v1 = aiVector3D(2*a,0,-1.f/3.f); - aiVector3D v2 = aiVector3D(-a,b,-1.f/3.f); - aiVector3D v3 = aiVector3D(-a,-b,-1.f/3.f); + const aiVector3D v0 = aiVector3D(0.f,0.f,1.f); + const aiVector3D v1 = aiVector3D(2*a,0,-1.f/3.f); + const aiVector3D v2 = aiVector3D(-a,b,-1.f/3.f); + const aiVector3D v3 = aiVector3D(-a,-b,-1.f/3.f); ADD_TRIANGLE(v0,v1,v2); ADD_TRIANGLE(v0,v2,v3); @@ -318,16 +319,16 @@ unsigned int StandardShapes::MakeHexahedron(std::vector& positions, bool polygons /*= false*/) { positions.reserve(positions.size()+36); - float length = 1.f/1.73205080f; + const float length = 1.f/1.73205080f; - aiVector3D v0 = aiVector3D(-1.f,-1.f,-1.f)*length; - aiVector3D v1 = aiVector3D(1.f,-1.f,-1.f)*length; - aiVector3D v2 = aiVector3D(1.f,1.f,-1.f)*length; - aiVector3D v3 = aiVector3D(-1.f,1.f,-1.f)*length; - aiVector3D v4 = aiVector3D(-1.f,-1.f,1.f)*length; - aiVector3D v5 = aiVector3D(1.f,-1.f,1.f)*length; - aiVector3D v6 = aiVector3D(1.f,1.f,1.f)*length; - aiVector3D v7 = aiVector3D(-1.f,1.f,1.f)*length; + const aiVector3D v0 = aiVector3D(-1.f,-1.f,-1.f)*length; + const aiVector3D v1 = aiVector3D(1.f,-1.f,-1.f)*length; + const aiVector3D v2 = aiVector3D(1.f,1.f,-1.f)*length; + const aiVector3D v3 = aiVector3D(-1.f,1.f,-1.f)*length; + const aiVector3D v4 = aiVector3D(-1.f,-1.f,1.f)*length; + const aiVector3D v5 = aiVector3D(1.f,-1.f,1.f)*length; + const aiVector3D v6 = aiVector3D(1.f,1.f,1.f)*length; + const aiVector3D v7 = aiVector3D(-1.f,1.f,1.f)*length; ADD_QUAD(v0,v3,v2,v1); ADD_QUAD(v0,v1,v5,v4); @@ -347,22 +348,95 @@ unsigned int StandardShapes::MakeHexahedron(std::vector& positions, void StandardShapes::MakeSphere(unsigned int tess, std::vector& positions) { + // Reserve enough storage. Every subdivision + // splits each triangle in 4, the icosahedron consists of 60 verts + positions.reserve(positions.size()+60 * integer_pow(4, tess)); + + // Construct an icosahedron to start with MakeIcosahedron(positions); + // ... and subdivide it until the requested output + // tesselation is reached for (unsigned int i = 0; i& positions, - bool bOpened /*= false*/) +void StandardShapes::MakeCone(float height,float radius1, + float radius2,unsigned int tess, + std::vector& positions,bool bOpen /*= false */) { + // Sorry, a cone with less than 3 segments makes + // ABSOLUTELY NO SENSE + if (tess < 3 || !height) + return; + + // No negative radii + radius1 = fabs(radius1); + radius2 = fabs(radius2); + + float halfHeight = height / 2; + + // radius1 is always the smaller one + if (radius2 > radius1) + { + std::swap(radius2,radius1); + halfHeight = -halfHeight; + } + + // Use a large epsilon to check whether the cone is pointy + if (radius1 < (radius2-radius1)*10e-3f)radius1 = 0.f; + + // We will need 3*2 verts per segment + 3*2 verts per segment + // if the cone is closed + const unsigned int mem = tess*6 + (!bOpen ? tess*3 * (radius1 ? 2 : 1) : 0); + positions.reserve(mem); + + // Now construct all segments + const float angle_delta = (float)AI_MATH_TWO_PI / tess; + const float angle_max = (float)AI_MATH_TWO_PI; + + float s = 1.f; // cos(angle == 0); + float t = 0.f; // sin(angle == 0); + + for (float angle = 0.f; angle < angle_max; ) + { + const aiVector3D v1 = aiVector3D (s * radius1, -halfHeight, t * radius1 ); + const aiVector3D v2 = aiVector3D (s * radius2, halfHeight, t * radius2 ); + + const float next = angle + angle_delta; + float s2 = cos(next); + float t2 = sin(next); + + const aiVector3D v3 = aiVector3D (s2 * radius2, halfHeight, t2 * radius2 ); + const aiVector3D v4 = aiVector3D (s2 * radius1, -halfHeight, t2 * radius1 ); + + positions.push_back(v1); + positions.push_back(v3); + positions.push_back(v2); + positions.push_back(v4); + positions.push_back(v3); + positions.push_back(v1); + + if (!bOpen) + { + // generate the end 'cap' + positions.push_back(aiVector3D(s * radius2, halfHeight, t * radius2 )); + positions.push_back(aiVector3D(0.f, halfHeight, 0.f)); + positions.push_back(aiVector3D(s2 * radius2, halfHeight, t2 * radius2 )); + + if (radius1) + { + // generate the other end 'cap' + positions.push_back(aiVector3D(s * radius1, -halfHeight, t * radius1 )); + positions.push_back(aiVector3D(0.f, -halfHeight, 0.f)); + positions.push_back(aiVector3D(s2 * radius1, -halfHeight, t2 * radius1 )); + } + } + s = s2; + t = t2; + angle = next; + } } // ------------------------------------------------------------------------------------------------ @@ -373,7 +447,7 @@ void StandardShapes::MakeCircle( unsigned int tess, std::vector& positions) { - //aiVector3D current = aiVector3D ( normal.x, + // todo } } // ! Assimp diff --git a/code/StandardShapes.h b/code/StandardShapes.h index c1c3cf94a..bb397f603 100644 --- a/code/StandardShapes.h +++ b/code/StandardShapes.h @@ -153,28 +153,28 @@ public: * * |-----| <- radius 1 * - * __x__ <- center 1 - * / \ - * / \ - * / \ - * / \ - * /______x______\ <- center 2 + * __x__ <- ] + * / \ | height + * / \ | + * / \ | + * / \ | + * /______x______\ <- ] <- end cap * * |-------------| <- radius 2 * * @endcode * - * @param center1 First center point + * @param height Height of the cone * @param radius1 First radius - * @param center2 Second center point * @param radius2 Second radius - * @param tess Number of subdivisions - * @param bOpened true for an open cone/cylinder. - * @param positions Receives output triangles. + * @param tess Number of triangles. + * @param bOpened true for an open cone/cylinder. An open shape has + * no 'end caps' + * @param positions Receives output triangles */ - static void MakeCone(aiVector3D& center1,float radius1, - aiVector3D& center2,float radius2,unsigned int tess, - std::vector& positions,bool bOpened = false); + static void MakeCone(float height,float radius1, + float radius2,unsigned int tess, + std::vector& positions,bool bOpen= false); // ---------------------------------------------------------------- @@ -185,7 +185,7 @@ public: * @param normal Normal vector of the circle. * This is also the normal vector of all triangles generated by * this function. - * @param tess Number of triangles + * @param tess Number of segments. * @param positions Receives output triangles. */ static void MakeCircle(const aiVector3D& center, const aiVector3D& normal, diff --git a/code/StringComparison.h b/code/StringComparison.h index e8db1c432..236026f43 100644 --- a/code/StringComparison.h +++ b/code/StringComparison.h @@ -54,7 +54,6 @@ namespace Assimp // @param max Maximum number of characters to be written, including '\0' // @param number Number to be written // @return Number of bytes written. Including '\0'. -// --------------------------------------------------------------------------- inline unsigned int itoa10( char* out, unsigned int max, int32_t number) { ai_assert(NULL != out); @@ -96,7 +95,6 @@ inline unsigned int itoa10( char* out, unsigned int max, int32_t number) // Secure template overload // The compiler should choose this function if he is able to determine the // size of the array automatically. -// --------------------------------------------------------------------------- template inline unsigned int itoa10( char(& out)[length], int32_t number) { @@ -113,13 +111,16 @@ inline unsigned int itoa10( char(& out)[length], int32_t number) * \param s1 First input string * \param s2 Second input string */ -// --------------------------------------------------------------------------- inline int ASSIMP_stricmp(const char *s1, const char *s2) { #if (defined _MSC_VER) return ::_stricmp(s1,s2); +#elif defined( __GNUC__ ) + + return ::strcasecmp(s1,s2); + #else register char c1, c2; do @@ -136,7 +137,6 @@ inline int ASSIMP_stricmp(const char *s1, const char *s2) // --------------------------------------------------------------------------- /** \brief Case independent comparison of two std::strings */ -// --------------------------------------------------------------------------- inline int ASSIMP_stricmp(const std::string& a, const std::string& b) { register int i = (int)b.length()-(int)a.length(); @@ -154,13 +154,16 @@ inline int ASSIMP_stricmp(const std::string& a, const std::string& b) * \param s2 Second input string * \param n Macimum number of characters to compare */ -// --------------------------------------------------------------------------- inline int ASSIMP_strincmp(const char *s1, const char *s2, unsigned int n) { #if (defined _MSC_VER) return ::_strnicmp(s1,s2,n); +#elif defined( __GNUC__ ) + + return ::strncasecmp(s1,s2, n); + #else register char c1, c2; unsigned int p = 0; @@ -175,6 +178,18 @@ inline int ASSIMP_strincmp(const char *s1, const char *s2, unsigned int n) return c1 - c2; #endif } + + +// --------------------------------------------------------------------------- +// Evaluates an integer power. +inline unsigned int integer_pow (unsigned int base, unsigned int power) +{ + unsigned int res = 1; + for (unsigned int i = 0; i < power;++i) + res *= base; + + return res; } +} // end of namespace #endif // ! AI_STRINGCOMPARISON_H_INC diff --git a/code/ValidateDataStructure.cpp b/code/ValidateDataStructure.cpp index 4b7900b67..986dbd01c 100644 --- a/code/ValidateDataStructure.cpp +++ b/code/ValidateDataStructure.cpp @@ -511,7 +511,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh) // check whether all bone weights for a vertex sum to 1.0 ... for (unsigned int i = 0; i < pMesh->mNumVertices;++i) { - if (afSum[i] && (afSum[i] <= 0.995 || afSum[i] >= 1.005)) + if (afSum[i] && (afSum[i] <= 0.94 || afSum[i] >= 1.05)) { ReportWarning("aiMesh::mVertices[%i]: bone weight sum != 1.0 (sum is %f)",i,afSum[i]); } diff --git a/include/IOSystem.h b/include/IOSystem.h index 15c6050cd..b0621e163 100644 --- a/include/IOSystem.h +++ b/include/IOSystem.h @@ -78,7 +78,7 @@ public: /** Compares two paths and check whether the point to identical files. * * The dummy implementation of this virtual performs a - * case-insensitive comparison of the path strings. + * case-insensitive comparison of the absolute path strings. * @param one First file * @param second Second file * @return true if the paths point to the same file. The file needn't diff --git a/include/aiMatrix4x4.h b/include/aiMatrix4x4.h index df762d307..e3caa4ab6 100644 --- a/include/aiMatrix4x4.h +++ b/include/aiMatrix4x4.h @@ -118,8 +118,8 @@ struct aiMatrix4x4 * \param y Rotation angle for the y-axis, in radians * \param z Rotation angle for the z-axis, in radians */ - inline void FromEulerAngles(float x, float y, float z); - inline void FromEulerAngles(const aiVector3D& blubb); + inline void FromEulerAnglesXYZ(float x, float y, float z); + inline void FromEulerAnglesXYZ(const aiVector3D& blubb); /** \brief Returns a rotation matrix for a rotation around the x axis @@ -158,6 +158,18 @@ struct aiMatrix4x4 */ static aiMatrix4x4& Translation( const aiVector3D& v, aiMatrix4x4& out); + + /** A function for creating a rotation matrix that rotates a vector called + * "from" into another vector called "to". + * Input : from[3], to[3] which both must be *normalized* non-zero vectors + * Output: mtx[3][3] -- a 3x3 matrix in colum-major form + * Authors: Tomas Möller, John Hughes + * "Efficiently Building a Matrix to Rotate One Vector to Another" + * Journal of Graphics Tools, 4(4):1-4, 1999 + */ + static aiMatrix4x4& FromToMatrix(const aiVector3D& from, + const aiVector3D& to, aiMatrix4x4& out); + #endif // __cplusplus float a1, a2, a3, a4; diff --git a/include/aiMatrix4x4.inl b/include/aiMatrix4x4.inl index c77d1707a..d1dfce9c2 100644 --- a/include/aiMatrix4x4.inl +++ b/include/aiMatrix4x4.inl @@ -87,12 +87,16 @@ inline aiMatrix4x4& aiMatrix4x4::Inverse() float det = Determinant(); if(det == 0.0f) { + // Matrix not invertible. Setting all elements to nan is not really + // correct in a mathematical sense but it is easy to debug for the + // programmer. const float nan = std::numeric_limits::quiet_NaN(); *this = aiMatrix4x4( nan,nan,nan,nan, nan,nan,nan,nan, nan,nan,nan,nan, nan,nan,nan,nan); + return *this; } @@ -204,43 +208,62 @@ inline void aiMatrix4x4::DecomposeNoScaling (aiQuaternion& rotation, rotation = aiQuaternion((aiMatrix3x3)_this); } // --------------------------------------------------------------------------- -inline void aiMatrix4x4::FromEulerAngles(const aiVector3D& blubb) +inline void aiMatrix4x4::FromEulerAnglesXYZ(const aiVector3D& blubb) { - FromEulerAngles(blubb.x,blubb.y,blubb.z); + FromEulerAnglesXYZ(blubb.x,blubb.y,blubb.z); } // --------------------------------------------------------------------------- -inline void aiMatrix4x4::FromEulerAngles(float x, float y, float z) +inline void aiMatrix4x4::FromEulerAnglesXYZ(float x, float y, float z) { aiMatrix4x4& _this = *this; - const float A = ::cos(x); - const float B = ::sin(x); - const float C = ::cos(y); - const float D = ::sin(y); - const float E = ::cos(z); - const float F = ::sin(z); - const float AD = A * D; - const float BD = B * D; - _this.a1 = C * E; - _this.a2 = -C * F; - _this.a3 = D; - _this.b1 = BD * E + A * F; - _this.b2 = -BD * F + A * E; - _this.b3 = -B * C; - _this.c1 = -AD * E + B * F; - _this.c2 = AD * F + B * E; - _this.c3 = A * C; - _this.a4 = _this.b4 = _this.c4 = _this.d1 = _this.d2 = _this.d3 = 0.0f; - _this.d4 = 1.0f; + float cr = cos( x ); + float sr = sin( x ); + float cp = cos( y ); + float sp = sin( y ); + float cy = cos( z ); + float sy = sin( z ); + + _this.a1 = cp*cy ; + _this.a2 = cp*sy; + _this.a3 = -sp ; + + float srsp = sr*sp; + float crsp = cr*sp; + + _this.b1 = srsp*cy-cr*sy ; + _this.b2 = srsp*sy+cr*cy ; + _this.b3 = sr*cp ; + + _this.c1 = crsp*cy+sr*sy ; + _this.c2 = crsp*sy-sr*cy ; + _this.c3 = cr*cp ; + } // --------------------------------------------------------------------------- inline bool aiMatrix4x4::IsIdentity() const { - return !(a1 != 1.0f || a2 || a3 || a4 || - b1 || b2 != 1.0f || b3 || b4 || - c1 || c2 || c3 != 1.0f || a4 || - d1 || d2 || d3 || d4 != 1.0f); + // Use a small epsilon to solve floating-point inaccuracies + const static float epsilon = 10e-3f; + + return (a2 <= epsilon && a2 >= -epsilon && + a3 <= epsilon && a3 >= -epsilon && + a4 <= epsilon && a4 >= -epsilon && + b1 <= epsilon && b1 >= -epsilon && + b3 <= epsilon && b3 >= -epsilon && + b4 <= epsilon && b4 >= -epsilon && + c1 <= epsilon && c1 >= -epsilon && + c2 <= epsilon && c2 >= -epsilon && + c3 <= epsilon && c3 >= -epsilon && + d1 <= epsilon && d1 >= -epsilon && + d2 <= epsilon && d2 >= -epsilon && + d3 <= epsilon && d3 >= -epsilon && + a1 <= 1.f+epsilon && a1 >= 1.f-epsilon && + b2 <= 1.f+epsilon && b2 >= 1.f-epsilon && + c3 <= 1.f+epsilon && c3 >= 1.f-epsilon && + d4 <= 1.f+epsilon && d4 >= 1.f-epsilon); } + // --------------------------------------------------------------------------- inline aiMatrix4x4& aiMatrix4x4::RotationX(float a, aiMatrix4x4& out) { @@ -312,5 +335,95 @@ inline aiMatrix4x4& aiMatrix4x4::Translation( const aiVector3D& v, aiMatrix4x4& return out; } +// --------------------------------------------------------------------------- +/** A function for creating a rotation matrix that rotates a vector called + * "from" into another vector called "to". + * Input : from[3], to[3] which both must be *normalized* non-zero vectors + * Output: mtx[3][3] -- a 3x3 matrix in colum-major form + * Authors: Tomas Möller, John Hughes + * "Efficiently Building a Matrix to Rotate One Vector to Another" + * Journal of Graphics Tools, 4(4):1-4, 1999 + */ +// --------------------------------------------------------------------------- +inline aiMatrix4x4& aiMatrix4x4::FromToMatrix(const aiVector3D& from, + const aiVector3D& to, aiMatrix4x4& mtx) +{ + const aiVector3D v = from ^ to; + const float e = from * to; + const float f = (e < 0)? -e:e; + + if (f > 1.0 - 0.00001f) /* "from" and "to"-vector almost parallel */ + { + aiVector3D u,v; /* temporary storage vectors */ + aiVector3D x; /* vector most nearly orthogonal to "from" */ + + x.x = (from.x > 0.0)? from.x : -from.x; + x.y = (from.y > 0.0)? from.y : -from.y; + x.z = (from.z > 0.0)? from.z : -from.z; + + if (x.x < x.y) + { + if (x.x < x.z) + { + x.x = 1.0; x.y = x.z = 0.0; + } + else + { + x.z = 1.0; x.y = x.z = 0.0; + } + } + else + { + if (x.y < x.z) + { + x.y = 1.0; x.x = x.z = 0.0; + } + else + { + x.z = 1.0; x.x = x.y = 0.0; + } + } + + u.x = x.x - from.x; u.y = x.y - from.y; u.z = x.z - from.z; + v.x = x.x - to.x; v.y = x.y - to.y; v.z = x.z - to.z; + + const float c1 = 2.0f / (u * u); + const float c2 = 2.0f / (v * v); + const float c3 = c1 * c2 * (u * v); + + for (unsigned int i = 0; i < 3; i++) + { + for (unsigned int j = 0; j < 3; j++) + { + mtx[i][j] = - c1 * u[i] * u[j] - c2 * v[i] * v[j] + + c3 * v[i] * u[j]; + } + mtx[i][i] += 1.0; + } + } + else /* the most common case, unless "from"="to", or "from"=-"to" */ + { + /* ... use this hand optimized version (9 mults less) */ + const float h = 1.0f/(1.0f + e); /* optimization by Gottfried Chen */ + const float hvx = h * v.x; + const float hvz = h * v.z; + const float hvxy = hvx * v.y; + const float hvxz = hvx * v.z; + const float hvyz = hvz * v.y; + mtx[0][0] = e + hvx * v.x; + mtx[0][1] = hvxy - v.z; + mtx[0][2] = hvxz + v.y; + + mtx[1][0] = hvxy + v.z; + mtx[1][1] = e + h * v.y * v.y; + mtx[1][2] = hvyz - v.x; + + mtx[2][0] = hvxz - v.y; + mtx[2][1] = hvyz + v.x; + mtx[2][2] = e + hvz * v.z; + } + return mtx; +} + #endif // __cplusplus #endif // AI_MATRIX4x4_INL_INC diff --git a/test/IRR/multipleAnimators.irr b/test/IRR/multipleAnimators.irr index 998868d4c..fb468aa11 100644 Binary files a/test/IRR/multipleAnimators.irr and b/test/IRR/multipleAnimators.irr differ diff --git a/test/NFF/NFF/ManyEarthsNotJustOne.nff b/test/NFF/NFF/ManyEarthsNotJustOne.nff new file mode 100644 index 000000000..c1261a1d0 --- /dev/null +++ b/test/NFF/NFF/ManyEarthsNotJustOne.nff @@ -0,0 +1,25 @@ +b 0.078 0.361 0.753 +v +from 2.1 1.3 1.7 +at 0 0 0 +up 0 0 1 +angle 45 +hither 0.01 +resolution 512 512 +l 4 3 2 +l 1 -4 4 +l -3 1 5 + +f 1 0.9 0.7 0.5 0.5 45.2776 0 1 ./../../LWOFiles/LWo2/MappingModes/EarthSpherical.jpg +s 0 0 0 0.5 + +f 1 0.9 0.7 0.5 0.5 45.2776 0 1 ./../../LWOFiles/LWo2/MappingModes/EarthSpherical.jpg +s 0.272166 0.272166 0.544331 0.16665 +s 0.643951 0.172546 1.11022e-16 0.16665 +s 0.172546 0.643951 1.11022e-16 0.16665 +s -0.371785 0.0996195 0.544331 0.16665 +s -0.471405 0.471405 1.11022e-16 0.16665 +s -0.643951 -0.172546 1.11022e-16 0.16665 +s 0.0996195 -0.371785 0.544331 0.16665 +s -0.172546 -0.643951 1.11022e-16 0.16665 +s 0.471405 -0.471405 1.11022e-16 0.16665 diff --git a/test/NFF/NFF/cone.nff b/test/NFF/NFF/cone.nff new file mode 100644 index 000000000..744c2d1c9 --- /dev/null +++ b/test/NFF/NFF/cone.nff @@ -0,0 +1,26 @@ + +#red +f 1.0 0.0 0.0 0.5 45.2776 0 1 ./../../LWOFiles/LWo2/MappingModes/EarthCylindric.jpg + + +tess 4 + + +# a simple cone - should go directly through the center +c +10 10 10 3 +-10 -10 -10 6 + + +f 1.0 1.0 1.0 0.5 0.5 45.2776 0 1 ./../../LWOFiles/LWo2/MappingModes/EarthSpherical.jpg +s -10 -10 -10 2 +s 10 10 10 3 + + +#white +f 1.0 1.0 1.0 0.5 0.5 45.2776 0 1 ./../../LWOFiles/LWo2/MappingModes/EarthCylindric.jpg + +# another cone, closed this time +c +20 20 20 6 +11 11 11 0 \ No newline at end of file diff --git a/test/NFF/NFF/cylinder.nff b/test/NFF/NFF/cylinder.nff new file mode 100644 index 000000000..4f0c78f87 --- /dev/null +++ b/test/NFF/NFF/cylinder.nff @@ -0,0 +1,10 @@ + +#red +f 1 0.9 0.7 0.5 0.5 45.2776 0 1 ./../../LWOFiles/LWo2/MappingModes/EarthCylindric.jpg + +tess 4 + +# a simple cylinder - should go directly through the center +c +10 10 10 6 +-10 -10 -10 6 \ No newline at end of file diff --git a/test/NFF/NFF/positionTest.nff b/test/NFF/NFF/positionTest.nff index 304aa9c66..375b51db7 100644 --- a/test/NFF/NFF/positionTest.nff +++ b/test/NFF/NFF/positionTest.nff @@ -1,27 +1,36 @@ +# Enable high-quality subdivision tess 4 + +# This represents a C4H10 molecule (Butan) + + f 0.3 0.3 0.3 1 1 - -# a centered sphere - - s 0 0 0 5 - s 20 0 0 5 - s 40 0 0 5 - s 60 0 0 5 +# Switch to white f 1 1 1 1 1 s -5 0 0 3 - s 0 5 0 3 s 0 -5 0 3 +s 20 5 0 3 +s 20 -5 0 3 +s 40 5 0 3 +s 40 -5 0 3 +s 60 5 0 3 +s 60 -5 0 3 +s 65 0 0 3 +# Now a tube to connect them +c +0 0 0 0.8 +60 0 0 0.8 diff --git a/test/NFF/NFF/spheres.nff b/test/NFF/NFF/spheres.nff index c03c52d49..8a313c921 100644 --- a/test/NFF/NFF/spheres.nff +++ b/test/NFF/NFF/spheres.nff @@ -5,13 +5,13 @@ s 5.0 5.0 5.0 3.0 #blue -f 0.0 0.0 1.0 0 1 1 +f 0.0 0.0 1.0 0 1 1 1 # Another simple sphere s 5.0 4.0 8.0 3.0 #green -f 0.0 1.0 0.0 0 1 1 +f 1.0 1.0 1.0 0.5 0.5 45.2776 0 1 ./../../LWOFiles/LWo2/MappingModes/EarthCylindric.jpg # And another one s 1.0 -4.0 2.0 4.0 2 2 @@ -19,10 +19,6 @@ s 1.0 -4.0 2.0 4.0 2 2 #red f 1.0 0.0 0.0 0 1 1 -# a simple cone -c 10 10 5 3 -c 14 14 3 6 - # An icosahedron tess 0