diff --git a/code/3DSConverter.cpp b/code/3DSConverter.cpp index 6730bdae7..ed1a84680 100644 --- a/code/3DSConverter.cpp +++ b/code/3DSConverter.cpp @@ -59,6 +59,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; +#ifdef _MSC_VER +# define sprintf sprintf_s +#endif // ------------------------------------------------------------------------------------------------ void Dot3DSImporter::ReplaceDefaultMaterial() @@ -113,8 +116,7 @@ void Dot3DSImporter::ReplaceDefaultMaterial() { (*a) = iIndex; ++iCnt; - DefaultLogger::get()->warn("Material index overflow in 3DS file. Assigning " - "default material ..."); + DefaultLogger::get()->warn("Material index overflow in 3DS file. Using default material"); } } } @@ -157,58 +159,36 @@ void Dot3DSImporter::CheckIndices(Dot3DS::Mesh* sMesh) // ------------------------------------------------------------------------------------------------ void Dot3DSImporter::MakeUnique(Dot3DS::Mesh* sMesh) { - std::vector vNew; - vNew.resize(sMesh->mFaces.size() * 3); - - std::vector vNew2; - - // TODO: Remove this step. By maintaining a small LUT it - // would be possible to do this directly in the parsing step unsigned int iBase = 0; - if (0 != sMesh->mTexCoords.size()) + std::vector vNew; + std::vector vNew2; + + vNew.resize(sMesh->mFaces.size() * 3); + if (sMesh->mTexCoords.size())vNew2.resize(sMesh->mFaces.size() * 3); + + for (unsigned int i = 0; i < sMesh->mFaces.size();++i) { - vNew2.resize(sMesh->mFaces.size() * 3); - for (unsigned int i = 0; i < sMesh->mFaces.size();++i) + uint32_t iTemp1,iTemp2; + + // positions + vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[2]]; + iTemp1 = iBase++; + vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[1]]; + iTemp2 = iBase++; + vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[0]]; + + // texture coordinates + if (sMesh->mTexCoords.size()) { - uint32_t iTemp1,iTemp2; - - // position and texture coordinates - vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[2]]; - vNew2[iBase] = sMesh->mTexCoords[sMesh->mFaces[i].mIndices[2]]; - iTemp1 = iBase++; - - vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[1]]; - vNew2[iBase] = sMesh->mTexCoords[sMesh->mFaces[i].mIndices[1]]; - iTemp2 = iBase++; - - vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[0]]; - vNew2[iBase] = sMesh->mTexCoords[sMesh->mFaces[i].mIndices[0]]; - sMesh->mFaces[i].mIndices[2] = iBase++; - - sMesh->mFaces[i].mIndices[0] = iTemp1; - sMesh->mFaces[i].mIndices[1] = iTemp2; + vNew2[iTemp1] = sMesh->mTexCoords[sMesh->mFaces[i].mIndices[2]]; + vNew2[iTemp2] = sMesh->mTexCoords[sMesh->mFaces[i].mIndices[1]]; + vNew2[iBase] = sMesh->mTexCoords[sMesh->mFaces[i].mIndices[0]]; } - } - else - { - for (unsigned int i = 0; i < sMesh->mFaces.size();++i) - { - uint32_t iTemp1,iTemp2; - // position only - vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[2]]; - iTemp1 = iBase++; - - vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[1]]; - iTemp2 = iBase++; - - vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[0]]; - sMesh->mFaces[i].mIndices[2] = iBase++; - - sMesh->mFaces[i].mIndices[0] = iTemp1; - sMesh->mFaces[i].mIndices[1] = iTemp2; - } + sMesh->mFaces[i].mIndices[2] = iBase++; + sMesh->mFaces[i].mIndices[0] = iTemp1; + sMesh->mFaces[i].mIndices[1] = iTemp2; } sMesh->mPositions = vNew; sMesh->mTexCoords = vNew2; @@ -400,7 +380,7 @@ void Dot3DSImporter::ConvertMaterial(Dot3DS::Material& oldMat, } // store the name of the material itself, too - if( oldMat.mName.length() > 0) + if( oldMat.mName.length()) { aiString tex; tex.Set( oldMat.mName); @@ -430,14 +410,19 @@ void Dot3DSImporter::ConvertMeshes(aiScene* pcOut) a != (*i).mFaceMaterials.end();++a,++iNum) { // check range + // FIX: shouldn't be necessary anymore, has been moved to ReplaceDefaultMaterial() +#if 0 if ((*a) >= this->mScene->mMaterials.size()) { DefaultLogger::get()->error("3DS face material index is out of range"); // use the last material instead + // TODO: assign the default material index aiSplit[this->mScene->mMaterials.size()-1].push_back(iNum); } - else aiSplit[*a].push_back(iNum); + else +#endif + aiSplit[*a].push_back(iNum); } // now generate submeshes bool bFirst = true; @@ -455,14 +440,14 @@ void Dot3DSImporter::ConvertMeshes(aiScene* pcOut) avOutMeshes.push_back(p_pcOut); // convert vertices - p_pcOut->mNumVertices = (unsigned int)aiSplit[p].size()*3; p_pcOut->mNumFaces = (unsigned int)aiSplit[p].size(); + p_pcOut->mNumVertices = p_pcOut->mNumFaces*3; // allocate enough storage for faces p_pcOut->mFaces = new aiFace[p_pcOut->mNumFaces]; iFaceCnt += p_pcOut->mNumFaces; - if (p_pcOut->mNumVertices != 0) + if (p_pcOut->mNumVertices) { p_pcOut->mVertices = new aiVector3D[p_pcOut->mNumVertices]; p_pcOut->mNormals = new aiVector3D[p_pcOut->mNumVertices]; @@ -489,7 +474,7 @@ void Dot3DSImporter::ConvertMeshes(aiScene* pcOut) } } // convert texture coordinates - if ((*i).mTexCoords.size() != 0) + if ((*i).mTexCoords.size()) { p_pcOut->mTextureCoords[0] = new aiVector3D[p_pcOut->mNumVertices]; @@ -525,17 +510,13 @@ void Dot3DSImporter::ConvertMeshes(aiScene* pcOut) pcOut->mMeshes[a] = avOutMeshes[a]; } - if (0 == iFaceCnt) - { + if (!iFaceCnt) throw new ImportErrorException("No faces loaded. The mesh is empty"); - } // for each material in the scene we need to setup the UV source // set for each texture for (unsigned int a = 0; a < pcOut->mNumMaterials;++a) - { TextureTransform::SetupMatUVSrc( pcOut->mMaterials[a], &this->mScene->mMaterials[a] ); - } return; } // ------------------------------------------------------------------------------------------------ @@ -551,7 +532,9 @@ void Dot3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,Dot3DS::Node* const Dot3DS::Mesh* pcMesh = (const Dot3DS::Mesh*)pcSOut->mMeshes[a]->mColors[0]; ai_assert(NULL != pcMesh); - if (0 == ASSIMP_stricmp(pcIn->mName.c_str(),pcMesh->mName.c_str())) + // do case independent comparisons here, just for safety + if (pcIn->mName.length() == pcMesh->mName.length() && + !ASSIMP_stricmp(pcIn->mName.c_str(),pcMesh->mName.c_str())) { iArray.push_back(a); } @@ -560,7 +543,8 @@ void Dot3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,Dot3DS::Node* { aiMatrix4x4& mTrafo = ((Dot3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0])->mMat; aiMatrix4x4 mInv = mTrafo; - mInv.Inverse(); + if (!this->configSkipPivot) + mInv.Inverse(); pcOut->mName.Set(pcIn->mName); pcOut->mNumMeshes = (unsigned int)iArray.size(); @@ -575,7 +559,7 @@ void Dot3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,Dot3DS::Node* const aiVector3D* const pvEnd = mesh->mVertices+mesh->mNumVertices; aiVector3D* pvCurrent = mesh->mVertices; - if(pivot.x || pivot.y || pivot.z) + if(pivot.x || pivot.y || pivot.z && !this->configSkipPivot) { while (pvCurrent != pvEnd) { @@ -593,18 +577,12 @@ void Dot3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,Dot3DS::Node* while (pvCurrent != pvEnd) { std::swap( pvCurrent->y, pvCurrent->z ); - //pvCurrent->y *= -1.0f; ++pvCurrent; } } pcOut->mMeshes[i] = iIndex; } } - /*else - { - DefaultLogger::get()->warn("A node that is not a dummy does not " - "reference a valid mesh."); - }*/ } pcOut->mTransformation = aiMatrix4x4(); pcOut->mNumChildren = (unsigned int)pcIn->mChildren.size(); @@ -636,8 +614,7 @@ void Dot3DSImporter::GenerateNodeGraph(aiScene* pcOut) // unsigned int iCnt = 0; - DefaultLogger::get()->warn("No hierarchy information has been " - "found in the file. A flat hierarchy tree is built ..."); + DefaultLogger::get()->warn("No hierarchy information has been found in the file. "); pcOut->mRootNode->mNumChildren = pcOut->mNumMeshes; pcOut->mRootNode->mChildren = new aiNode* [ pcOut->mNumMeshes ]; @@ -654,11 +631,7 @@ void Dot3DSImporter::GenerateNodeGraph(aiScene* pcOut) char szBuffer[128]; int iLen; -#if _MSC_VER >= 1400 - iLen = sprintf_s(szBuffer,"UNNAMED_%i",i); -#else iLen = sprintf(szBuffer,"UNNAMED_%i",i); -#endif ai_assert(0 < iLen); ::memcpy(pcNode->mName.data,szBuffer,iLen); pcNode->mName.data[iLen] = '\0'; diff --git a/code/3DSHelper.h b/code/3DSHelper.h index be6959ecd..b4a190fc6 100644 --- a/code/3DSHelper.h +++ b/code/3DSHelper.h @@ -120,8 +120,8 @@ public: enum { - // ************************************************************** - // Base chunks which can be found everywhere in the file + // ******************************************************************** + // Basic chunks which can be found everywhere in the file CHUNK_VERSION = 0x0002, CHUNK_RGBF = 0x0010, // float4 R; float4 G; float4 B CHUNK_RGBB = 0x0011, // int1 R; int1 G; int B @@ -132,7 +132,7 @@ public: CHUNK_PERCENTW = 0x0030, // int2 percentage CHUNK_PERCENTF = 0x0031, // float4 percentage - // ************************************************************** + // ******************************************************************** // Unknown and ignored. Possibly a chunk used by PROJ ( // Discreet 3DS max Project File)? @@ -162,7 +162,7 @@ public: CHUNK_BIT_MAP = 0x1100, CHUNK_BIT_MAP_EXISTS = 0x1101, - // ************************************************************** + // ******************************************************************** // Viewport related stuff. Ignored CHUNK_DEFAULT_VIEW = 0x3000, CHUNK_VIEW_TOP = 0x3010, @@ -173,7 +173,7 @@ public: CHUNK_VIEW_BACK = 0x3060, CHUNK_VIEW_USER = 0x3070, CHUNK_VIEW_CAMERA = 0x3080, - // ************************************************************** + // ******************************************************************** // Mesh chunks CHUNK_OBJBLOCK = 0x4000, @@ -196,7 +196,7 @@ public: // to the root node's transformation matrix CHUNK_MASTER_SCALE = 0x0100, - // ************************************************************** + // ******************************************************************** // Material chunks CHUNK_MAT_MATERIAL = 0xAFFF, @@ -280,7 +280,7 @@ public: // Specifies whether a materail requires two-sided rendering CHUNK_MAT_TWO_SIDE = 0xA081, - // ************************************************************** + // ******************************************************************** // Main keyframer chunk. Contains translation/rotation/scaling data CHUNK_KEYFRAMER = 0xB000, @@ -293,7 +293,7 @@ public: CHUNK_TRACKROTATE = 0xB021, CHUNK_TRACKSCALE = 0xB022, - // ************************************************************** + // ******************************************************************** // Keyframes for various other stuff in the file // Ignored CHUNK_AMBIENTKEY = 0xB001, @@ -308,7 +308,7 @@ public: CHUNK_TRACKLIGTGT = 0xB006, CHUNK_TRACKSPOTL = 0xB007, CHUNK_FRAMES = 0xB008 - // ************************************************************** + // ******************************************************************** }; }; diff --git a/code/3DSLoader.cpp b/code/3DSLoader.cpp index eccb07b13..4a4bcc229 100644 --- a/code/3DSLoader.cpp +++ b/code/3DSLoader.cpp @@ -55,6 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../include/aiMesh.h" #include "../include/aiScene.h" #include "../include/aiAssert.h" +#include "../include/assimp.hpp" // boost headers #include @@ -99,6 +100,12 @@ bool Dot3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) co return false; } // ------------------------------------------------------------------------------------------------ +// Setup configuration properties +void Dot3DSImporter::SetupProperties(const Importer* pImp) +{ + this->configSkipPivot = pImp->GetProperty(AI_CONFIG_IMPORT_3DS_IGNORE_PIVOT,0) ? true : false; +} +// ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. void Dot3DSImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) @@ -144,48 +151,46 @@ void Dot3DSImporter::InternReadFile( try { this->ParseMainChunk(iRemaining); + + // Generate an unique set of vertices/indices for + // all meshes contained in the file + for (std::vector::iterator + i = this->mScene->mMeshes.begin(); + i != this->mScene->mMeshes.end();++i) + { + // TODO: see function body + this->CheckIndices(&(*i)); + this->MakeUnique(&(*i)); + + // first generate normals for the mesh + this->GenNormals(&(*i)); + } + + // Apply scaling and offsets to all texture coordinates + TextureTransform::ApplyScaleNOffset(this->mScene->mMaterials); + + // Replace all occurences of the default material with a valid material. + // Generate it if no material containing DEFAULT in its name has been + // found in the file + this->ReplaceDefaultMaterial(); + + // Convert the scene from our internal representation to an aiScene object + this->ConvertScene(pScene); + + // Generate the node graph for the scene. This is a little bit + // tricky since we'll need to split some meshes into submeshes + this->GenerateNodeGraph(pScene); + + // Now apply a master scaling factor to the scene + this->ApplyMasterScale(pScene); + } catch ( ImportErrorException* ex) { - delete[] this->mBuffer; + delete[] this->mBuffer;AI_DEBUG_INVALIDATE_PTR(this->mBuffer); throw ex; - }; - - // Generate an unique set of vertices/indices for - // all meshes contained in the file - for (std::vector::iterator - i = this->mScene->mMeshes.begin(); - i != this->mScene->mMeshes.end();++i) - { - // TODO: see function body - this->CheckIndices(&(*i)); - this->MakeUnique(&(*i)); - - // first generate normals for the mesh - this->GenNormals(&(*i)); } - - // Apply scaling and offsets to all texture coordinates - TextureTransform::ApplyScaleNOffset(this->mScene->mMaterials); - - // Replace all occurences of the default material with a valid material. - // Generate it if no material containing DEFAULT in its name has been - // found in the file - this->ReplaceDefaultMaterial(); - - // Convert the scene from our internal representation to an aiScene object - this->ConvertScene(pScene); - - // Generate the node graph for the scene. This is a little bit - // tricky since we'll need to split some meshes into submeshes - this->GenerateNodeGraph(pScene); - - // Now apply a master scaling factor to the scene - this->ApplyMasterScale(pScene); - - delete[] this->mBuffer; - delete this->mScene; - return; + delete[] this->mBuffer;AI_DEBUG_INVALIDATE_PTR(this->mBuffer); } // ------------------------------------------------------------------------------------------------ void Dot3DSImporter::ApplyMasterScale(aiScene* pScene) diff --git a/code/3DSLoader.h b/code/3DSLoader.h index a0a1c4f95..f32f9084c 100644 --- a/code/3DSLoader.h +++ b/code/3DSLoader.h @@ -43,8 +43,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_3DSIMPORTER_H_INC #define AI_3DSIMPORTER_H_INC -#include - #include "BaseImporter.h" #include "../include/aiTypes.h" @@ -73,11 +71,19 @@ protected: ~Dot3DSImporter(); public: + // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. * See BaseImporter::CanRead() for details. */ bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + // ------------------------------------------------------------------- + /** Called prior to ReadFile(). + * The function is a request to the importer to update its configuration + * basing on the Importer's configuration property list. + */ + void SetupProperties(const Importer* pImp); + protected: // ------------------------------------------------------------------- @@ -233,6 +239,10 @@ protected: protected: + + /** Configuration option: skip pivot chunks */ + bool configSkipPivot; + /** Buffer to hold the loaded file */ unsigned char* mBuffer; diff --git a/code/ASELoader.cpp b/code/ASELoader.cpp index 0ae153c94..f36e2cd84 100644 --- a/code/ASELoader.cpp +++ b/code/ASELoader.cpp @@ -109,14 +109,11 @@ void ASEImporter::InternReadFile( // Check whether we can read from the file if( file.get() == NULL) - { throw new ImportErrorException( "Failed to open ASE file " + pFile + "."); - } size_t fileSize = file->FileSize(); std::string::size_type pos = pFile.find_last_of('.'); std::string extension = pFile.substr( pos); - this->mIsAsk = (extension[3] == 'k' || extension[3] == 'K'); // allocate storage and copy the contents of the file to a memory buffer // (terminate it with zero) @@ -144,11 +141,7 @@ void ASEImporter::InternReadFile( { if ((*i).bSkip)continue; - // transform all vertices into worldspace - // world2obj transform is specified in the - // transformation matrix of a scenegraph node this->TransformVertices(*i); - // now we need to create proper meshes from the import we need to // split them by materials, build valid vertex/face lists ... this->BuildUniqueRepresentation(*i); @@ -215,7 +208,7 @@ void ASEImporter::GenerateDefaultMaterial() this->mParser->m_vMaterials.push_back ( ASE::Material() ); ASE::Material& mat = this->mParser->m_vMaterials.back(); - mat.mDiffuse = aiColor3D(0.6f,0.6f,0.6f); + mat.mDiffuse = aiColor3D(0.6f,0.6f,0.6f); mat.mSpecular = aiColor3D(1.0f,1.0f,1.0f); mat.mAmbient = aiColor3D(0.05f,0.05f,0.05f); mat.mShading = Dot3DSFile::Gouraud; @@ -449,21 +442,6 @@ void ASEImporter::BuildNodes() std::string* szMyName = (std::string*)pcScene->mMeshes[*i]->mColors[1]; if (!szMyName)continue; -#if 0 // moved to the scope above - for (std::vector::iterator - a = i+1; - a != aiList.end();++a) - { - std::string* szMyName2 = (std::string*)pcScene->mMeshes[*i]->mColors[1]; - if (!szMyName)continue; - if (0 == ASSIMP_stricmp(szMyName2->c_str(),szMyName->c_str())) - { - a = aiList.erase(a); - if (a == aiList.end())break; - } - } -#endif - DefaultLogger::get()->info("Generating dummy node: " + szMyName[1] + ". " "This node is not defined in the ASE file, but referenced as " "parent node."); @@ -604,19 +582,6 @@ void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh) for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) mesh.amTexCoords[c] = amTexCoords[c]; - - // now need to transform all vertices with the inverse of their - // transformation matrix ... - //aiMatrix4x4 mInverse = mesh.mTransform; - //mInverse.Inverse(); - - //for (std::vector::iterator - // i = mesh.mPositions.begin(); - // i != mesh.mPositions.end();++i) - //{ - // (*i) = mInverse * (*i); - //} - return; } // ------------------------------------------------------------------------------------------------ @@ -1066,7 +1031,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh pc->mName.Set(mesh.mBones[jfkennedy].mName); pc->mNumWeights = (unsigned int)avBonesOut[jfkennedy].size(); pc->mWeights = new aiVertexWeight[pc->mNumWeights]; - memcpy(pc->mWeights,&avBonesOut[jfkennedy][0], + ::memcpy(pc->mWeights,&avBonesOut[jfkennedy][0], sizeof(aiVertexWeight) * pc->mNumWeights); ++pcBone; } @@ -1246,9 +1211,8 @@ void ASEImporter::GenerateNormals(ASE::Mesh& mesh) aiVector3D pDelta2 = *pV3 - *pV1; aiVector3D vNor = pDelta1 ^ pDelta2; - mesh.mNormals[face.mIndices[0]] = vNor; - mesh.mNormals[face.mIndices[1]] = vNor; - mesh.mNormals[face.mIndices[2]] = vNor; + for (unsigned int i = 0; i < 3;++i) + mesh.mNormals[face.mIndices[i]] = vNor; } // calculate the position bounds so we have a reliable epsilon to @@ -1287,15 +1251,13 @@ void ASEImporter::GenerateNormals(ASE::Mesh& mesh) posEpsilon,poResult); aiVector3D vNormals; - float fDiv = 0.0f; for (std::vector::const_iterator a = poResult.begin(); a != poResult.end();++a) { vNormals += mesh.mNormals[(*a)]; - fDiv += 1.0f; } - vNormals /= fDiv; + vNormals.Normalize(); avNormals[(*i).mIndices[c]] = vNormals; poResult.clear(); } diff --git a/code/ASELoader.h b/code/ASELoader.h index c2d849664..86f4e2edc 100644 --- a/code/ASELoader.h +++ b/code/ASELoader.h @@ -114,8 +114,6 @@ protected: * \param mesh Mesh to work on */ void TransformVertices(ASE::Mesh& mesh); - - // ------------------------------------------------------------------- /** Create one-material-per-mesh meshes ;-) * \param mesh Mesh to work with * \param Receives the list of all created meshes @@ -168,13 +166,10 @@ protected: /** Buffer to hold the loaded file */ unsigned char* mBuffer; - /** true if this is an .ask file */ - bool mIsAsk; - /** Scene to be filled */ aiScene* pcScene; }; } // end of namespace Assimp -#endif // AI_3DSIMPORTER_H_INC \ No newline at end of file +#endif // AI_3DSIMPORTER_H_INC diff --git a/code/ASEParser.cpp b/code/ASEParser.cpp index aeac3caae..6036221b1 100644 --- a/code/ASEParser.cpp +++ b/code/ASEParser.cpp @@ -794,6 +794,7 @@ void Parser::ParseLV1GeometryObjectBlock(ASE::Mesh& mesh) { this->m_szFile+=9; this->ParseLV2NodeTransformBlock(mesh);continue; + //mesh.mTransform.Transpose(); } // mesh data if (0 == strncmp(this->m_szFile,"*MESH" ,5) && diff --git a/code/CalcTangentsProcess.cpp b/code/CalcTangentsProcess.cpp index 8fa0a9a00..aad7e345b 100644 --- a/code/CalcTangentsProcess.cpp +++ b/code/CalcTangentsProcess.cpp @@ -56,6 +56,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../include/aiPostProcess.h" #include "../include/aiMesh.h" #include "../include/aiScene.h" +#include "../include/assimp.hpp" using namespace Assimp; @@ -80,6 +81,16 @@ bool CalcTangentsProcess::IsActive( unsigned int pFlags) const return (pFlags & aiProcess_CalcTangentSpace) != 0; } +// ------------------------------------------------------------------------------------------------ +// Executes the post processing step on the given imported data. +void CalcTangentsProcess::SetupProperties(const Importer* pImp) +{ + // get the current value of the property + this->configMaxAngle = pImp->GetProperty(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE,45000) / 1000.0f; + this->configMaxAngle = std::max(std::min(this->configMaxAngle,180.0f),0.0f); + this->configMaxAngle *= 0.0174532925f; +} + // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. void CalcTangentsProcess::Execute( aiScene* pScene) @@ -213,7 +224,6 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh) vertexFinder.FindPositions( origPos, posEpsilon, verticesFound); // look among them for other vertices sharing the same normal and a close-enough tangent/bitangent - static const float MAX_DIFF_ANGLE = 0.701f; for( unsigned int b = 0; b < verticesFound.size(); b++) { unsigned int idx = verticesFound[b]; @@ -221,9 +231,9 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh) continue; if( meshNorm[idx] * origNorm < angleEpsilon) continue; - if( meshTang[idx] * origTang < MAX_DIFF_ANGLE) + if( acosf( meshTang[idx] * origTang) > this->configMaxAngle) continue; - if( meshBitang[idx] * origBitang < MAX_DIFF_ANGLE) + if( acosf( meshBitang[idx] * origBitang) > this->configMaxAngle) continue; // it's similar enough -> add it to the smoothing group diff --git a/code/CalcTangentsProcess.h b/code/CalcTangentsProcess.h index 35c116b45..60bc35cb2 100644 --- a/code/CalcTangentsProcess.h +++ b/code/CalcTangentsProcess.h @@ -70,26 +70,39 @@ protected: 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. + /** Returns whether the processing step is present in the given flag. + * @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; + // ------------------------------------------------------------------- + /** Called prior to ExecuteOnScene(). + * The function is a request to the process to update its configuration + * basing on the Importer's configuration property list. + */ + void SetupProperties(const Importer* pImp); + +protected: + + // ------------------------------------------------------------------- + /** Calculates tangents and bitangents for a specific mesh. + * @param pMesh The mesh to process. + */ + bool ProcessMesh( aiMesh* pMesh); + // ------------------------------------------------------------------- /** 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); -protected: - // ------------------------------------------------------------------- - /** Calculates tangents and bitangents for the given mesh - * @param pMesh The mesh to process. - */ - bool ProcessMesh( aiMesh* pMesh); +private: + + /** Configuration option: maximum smoothing angle, in radians*/ + float configMaxAngle; }; } // end of namespace Assimp diff --git a/code/GenVertexNormalsProcess.cpp b/code/GenVertexNormalsProcess.cpp index d471731b1..5c879f439 100644 --- a/code/GenVertexNormalsProcess.cpp +++ b/code/GenVertexNormalsProcess.cpp @@ -48,6 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../include/aiPostProcess.h" #include "../include/aiMesh.h" #include "../include/aiScene.h" +#include "../include/assimp.hpp" using namespace Assimp; @@ -70,7 +71,15 @@ bool GenVertexNormalsProcess::IsActive( unsigned int pFlags) const { return (pFlags & aiProcess_GenSmoothNormals) != 0; } - +// ------------------------------------------------------------------------------------------------ +// Executes the post processing step on the given imported data. +void GenVertexNormalsProcess::SetupProperties(const Importer* pImp) +{ + // get the current value of the property + this->configMaxAngle = pImp->GetProperty(AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE,180000) / 1000.0f; + this->configMaxAngle = std::max(std::min(this->configMaxAngle,180.0f),0.0f); + this->configMaxAngle *= 0.0174532925f; +} // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. void GenVertexNormalsProcess::Execute( aiScene* pScene) @@ -111,14 +120,10 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh) aiVector3D pDelta1 = *pV2 - *pV1; aiVector3D pDelta2 = *pV3 - *pV1; aiVector3D vNor = pDelta1 ^ pDelta2; - - /*if (face.mIndices[1] > face.mIndices[2]) - vNor *= -1.0f;*/ + vNor.Normalize(); for (unsigned int i = 0;i < face.mNumIndices;++i) - { pMesh->mNormals[face.mIndices[i]] = vNor; - } } // calculate the position bounds so we have a reliable epsilon to @@ -135,10 +140,14 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh) } const float posEpsilon = (maxVec - minVec).Length() * 1e-5f; + // set up a SpatialSort to quickly find all vertices close to a given position SpatialSort vertexFinder( pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D)); std::vector verticesFound; + const float fLimit = (AI_MESH_SMOOTHING_ANGLE_NOT_SET == pMesh->mMaxSmoothingAngle + ? this->configMaxAngle : pMesh->mMaxSmoothingAngle); + aiVector3D* pcNew = new aiVector3D[pMesh->mNumVertices]; for (unsigned int i = 0; i < pMesh->mNumVertices;++i) { @@ -148,12 +157,19 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh) vertexFinder.FindPositions( posThis, posEpsilon, verticesFound); aiVector3D pcNor; + unsigned int div = 0; for (unsigned int a = 0; a < verticesFound.size(); ++a) { unsigned int vidx = verticesFound[a]; + + // check whether the angle between the two normals is not too large + if (acosf(pMesh->mNormals[vidx] * pMesh->mNormals[i]) > fLimit) + continue; + pcNor += pMesh->mNormals[vidx]; + ++div; } - pcNor /= (float) verticesFound.size(); + pcNor.Normalize(); pcNew[i] = pcNor; } delete[] pMesh->mNormals; diff --git a/code/GenVertexNormalsProcess.h b/code/GenVertexNormalsProcess.h index 4eee32ae7..5ae9ed2a5 100644 --- a/code/GenVertexNormalsProcess.h +++ b/code/GenVertexNormalsProcess.h @@ -38,7 +38,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file Defines a post processing step to compute vertex normals for all loaded vertizes */ +/** @file Defines a post processing step to compute vertex normals + for all loaded vertizes */ #ifndef AI_GENVERTEXNORMALPROCESS_H_INC #define AI_GENVERTEXNORMALPROCESS_H_INC @@ -48,7 +49,7 @@ class GenNormalsTest; namespace Assimp { // --------------------------------------------------------------------------- -/** The GenFaceNormalsProcess computes vertex normals for all vertizes of all meshes +/** The GenFaceNormalsProcess computes vertex normals for all vertizes */ class ASSIMP_API GenVertexNormalsProcess : public BaseProcess { @@ -64,12 +65,20 @@ protected: 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. + /** Returns whether the processing step is present in the given flag. + * @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; + + // ------------------------------------------------------------------- + /** Called prior to ExecuteOnScene(). + * The function is a request to the process to update its configuration + * basing on the Importer's configuration property list. + */ + void SetupProperties(const Importer* pImp); // ------------------------------------------------------------------- /** Executes the post processing step on the given imported data. @@ -78,9 +87,19 @@ public: */ void Execute( aiScene* pScene); +protected: + + // ------------------------------------------------------------------- + /** Computes normals for a specific mesh + * @param pcMesh Mesh + * @return true if vertex normals have been computed + */ + bool GenMeshVertexNormals (aiMesh* pcMesh); private: - bool GenMeshVertexNormals (aiMesh* pcMesh); + + /** Configuration option: maximum smoothing angle, in radians*/ + float configMaxAngle; }; }; // end of namespace Assimp diff --git a/code/Importer.cpp b/code/Importer.cpp index b8184c2fa..8cae3f3b1 100644 --- a/code/Importer.cpp +++ b/code/Importer.cpp @@ -93,10 +93,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #if (!defined AI_BUILD_NO_MDR_IMPORTER) # include "MDRLoader.h" #endif +#endif #if (!defined AI_BUILD_NO_MDC_IMPORTER) # include "MDCLoader.h" #endif -#endif #if (!defined AI_BUILD_NO_MD5_IMPORTER) # include "MD5Loader.h" #endif @@ -202,10 +202,10 @@ Importer::Importer() : #if (!defined AI_BUILD_NO_MDR_IMPORTER) mImporter.push_back( new MDRImporter()); #endif +#endif #if (!defined AI_BUILD_NO_MDC_IMPORTER) mImporter.push_back( new MDCImporter()); #endif -#endif #if (!defined AI_BUILD_NO_MD5_IMPORTER) mImporter.push_back( new MD5Importer()); #endif diff --git a/code/LimitBoneWeightsProcess.cpp b/code/LimitBoneWeightsProcess.cpp index 15a01d1e7..841a46e71 100644 --- a/code/LimitBoneWeightsProcess.cpp +++ b/code/LimitBoneWeightsProcess.cpp @@ -88,11 +88,7 @@ void LimitBoneWeightsProcess::Execute( aiScene* pScene) void LimitBoneWeightsProcess::SetupProperties(const Importer* pImp) { // get the current value of the property - if(0xffffffff == (this->mMaxWeights = pImp->GetProperty( - AI_CONFIG_PP_LBW_MAX_WEIGHTS,0xffffffff))) - { - this->mMaxWeights = AI_LMW_MAX_WEIGHTS; - } + this->mMaxWeights = pImp->GetProperty(AI_CONFIG_PP_LBW_MAX_WEIGHTS,AI_LMW_MAX_WEIGHTS); } // ------------------------------------------------------------------------------------------------ diff --git a/code/LimitBoneWeightsProcess.h b/code/LimitBoneWeightsProcess.h index f32c946fc..4572985d7 100644 --- a/code/LimitBoneWeightsProcess.h +++ b/code/LimitBoneWeightsProcess.h @@ -83,10 +83,11 @@ protected: 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. + /** Returns whether the processing step is present in the given flag. + * @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; @@ -95,7 +96,7 @@ public: * The function is a request to the process to update its configuration * basing on the Importer's configuration property list. */ - virtual void SetupProperties(const Importer* pImp); + void SetupProperties(const Importer* pImp); protected: diff --git a/code/MD2Loader.cpp b/code/MD2Loader.cpp index 2a2a353a3..0e8b11b23 100644 --- a/code/MD2Loader.cpp +++ b/code/MD2Loader.cpp @@ -169,7 +169,7 @@ void MD2Importer::ValidateHeader( ) if (this->m_pcHeader->numVertices > AI_MD2_MAX_VERTS) DefaultLogger::get()->warn("The model contains more vertices than Quake 2 supports"); - if (this->m_pcHeader->numFrames >= this->configFrameID ) + if (this->m_pcHeader->numFrames <= this->configFrameID ) throw new ImportErrorException("The requested frame is not existing the file"); } diff --git a/code/MD3Loader.cpp b/code/MD3Loader.cpp index 25e4a4e08..fc74f4c43 100644 --- a/code/MD3Loader.cpp +++ b/code/MD3Loader.cpp @@ -93,28 +93,26 @@ bool MD3Importer::CanRead( const std::string& pFile, IOSystem* pIOHandler) const void MD3Importer::ValidateHeaderOffsets() { // check magic number - if (this->m_pcHeader->IDENT != AI_MD3_MAGIC_NUMBER_BE && - this->m_pcHeader->IDENT != AI_MD3_MAGIC_NUMBER_LE) + if (pcHeader->IDENT != AI_MD3_MAGIC_NUMBER_BE && + pcHeader->IDENT != AI_MD3_MAGIC_NUMBER_LE) throw new ImportErrorException( "Invalid MD3 file: Magic bytes not found"); // check file format version - if (this->m_pcHeader->VERSION > 15) + if (pcHeader->VERSION > 15) DefaultLogger::get()->warn( "Unsupported MD3 file version. Continuing happily ..."); // check some values whether they are valid - if (!this->m_pcHeader->NUM_FRAMES) - throw new ImportErrorException( "Invalid MD3 file: NUM_FRAMES is 0"); - if (!this->m_pcHeader->NUM_SURFACES) + if (!pcHeader->NUM_SURFACES) throw new ImportErrorException( "Invalid md3 file: NUM_SURFACES is 0"); - if (this->m_pcHeader->OFS_FRAMES >= this->fileSize || - this->m_pcHeader->OFS_SURFACES >= this->fileSize || - this->m_pcHeader->OFS_EOF > this->fileSize) + if (pcHeader->OFS_FRAMES >= fileSize || + pcHeader->OFS_SURFACES >= fileSize || + pcHeader->OFS_EOF > fileSize) { throw new ImportErrorException("Invalid MD3 header: some offsets are outside the file"); } - if (this->m_pcHeader->NUM_FRAMES >= this->configFrameID ) + if (pcHeader->NUM_FRAMES <= this->configFrameID ) throw new ImportErrorException("The requested frame is not existing the file"); } // ------------------------------------------------------------------------------------------------ @@ -123,10 +121,10 @@ void MD3Importer::ValidateSurfaceHeaderOffsets(const MD3::Surface* pcSurf) // calculate the relative offset of the surface int32_t ofs = int32_t((const unsigned char*)pcSurf-this->mBuffer); - if (pcSurf->OFS_TRIANGLES + ofs + pcSurf->NUM_TRIANGLES * sizeof(MD3::Triangle) > this->fileSize || - pcSurf->OFS_SHADERS + ofs + pcSurf->NUM_SHADER * sizeof(MD3::Shader) > this->fileSize || - pcSurf->OFS_ST + ofs + pcSurf->NUM_VERTICES * sizeof(MD3::TexCoord) > this->fileSize || - pcSurf->OFS_XYZNORMAL + ofs + pcSurf->NUM_VERTICES * sizeof(MD3::Vertex) > this->fileSize) + if (pcSurf->OFS_TRIANGLES + ofs + pcSurf->NUM_TRIANGLES * sizeof(MD3::Triangle) > fileSize || + pcSurf->OFS_SHADERS + ofs + pcSurf->NUM_SHADER * sizeof(MD3::Shader) > fileSize || + pcSurf->OFS_ST + ofs + pcSurf->NUM_VERTICES * sizeof(MD3::TexCoord) > fileSize || + pcSurf->OFS_XYZNORMAL + ofs + pcSurf->NUM_VERTICES * sizeof(MD3::Vertex) > fileSize) { throw new ImportErrorException("Invalid MD3 surface header: some offsets are outside the file"); } @@ -170,310 +168,279 @@ void MD3Importer::InternReadFile( throw new ImportErrorException( "MD3 File is too small."); // allocate storage and copy the contents of the file to a memory buffer - this->mBuffer = new unsigned char[fileSize]; - file->Read( (void*)mBuffer, 1, fileSize); + std::vector mBuffer2 (fileSize); + file->Read( &mBuffer2[0], 1, fileSize); + mBuffer = &mBuffer2[0]; - try + pcHeader = (BE_NCONST MD3::Header*)mBuffer; + +#ifdef AI_BUILD_BIG_ENDIAN + + ByteSwap::Swap4(&pcHeader->VERSION); + ByteSwap::Swap4(&pcHeader->FLAGS); + ByteSwap::Swap4(&pcHeader->IDENT); + ByteSwap::Swap4(&pcHeader->NUM_FRAMES); + ByteSwap::Swap4(&pcHeader->NUM_SKINS); + ByteSwap::Swap4(&pcHeader->NUM_SURFACES); + ByteSwap::Swap4(&pcHeader->NUM_TAGS); + ByteSwap::Swap4(&pcHeader->OFS_EOF); + ByteSwap::Swap4(&pcHeader->OFS_FRAMES); + ByteSwap::Swap4(&pcHeader->OFS_SURFACES); + ByteSwap::Swap4(&pcHeader->OFS_TAGS); + +#endif + + // validate the header + this->ValidateHeaderOffsets(); + + // now navigate to the list of surfaces + const MD3::Surface* pcSurfaces = (const MD3::Surface*)(mBuffer + pcHeader->OFS_SURFACES); + + // allocate output storage + pScene->mNumMeshes = pcHeader->NUM_SURFACES; + pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; + + pScene->mNumMaterials = pcHeader->NUM_SURFACES; + pScene->mMaterials = new aiMaterial*[pScene->mNumMeshes]; + + // if an exception is thrown before the meshes are allocated -> + // otherwise the pointer value would be invalid and delete would crash + ::memset(pScene->mMeshes,0,pScene->mNumMeshes*sizeof(aiMesh*)); + ::memset(pScene->mMaterials,0,pScene->mNumMaterials*sizeof(aiMaterial*)); + + unsigned int iNum = pcHeader->NUM_SURFACES; + unsigned int iNumMaterials = 0; + unsigned int iDefaultMatIndex = 0xFFFFFFFF; + while (iNum-- > 0) { - this->m_pcHeader = (const MD3::Header*)this->mBuffer; - #ifdef AI_BUILD_BIG_ENDIAN - ByteSwap::Swap4(&m_pcHeader->VERSION); - ByteSwap::Swap4(&m_pcHeader->FLAGS); - ByteSwap::Swap4(&m_pcHeader->IDENT); - ByteSwap::Swap4(&m_pcHeader->NUM_FRAMES); - ByteSwap::Swap4(&m_pcHeader->NUM_SKINS); - ByteSwap::Swap4(&m_pcHeader->NUM_SURFACES); - ByteSwap::Swap4(&m_pcHeader->NUM_TAGS); - ByteSwap::Swap4(&m_pcHeader->OFS_EOF); - ByteSwap::Swap4(&m_pcHeader->OFS_FRAMES); - ByteSwap::Swap4(&m_pcHeader->OFS_SURFACES); - ByteSwap::Swap4(&m_pcHeader->OFS_TAGS); + ByteSwap::Swap4(pcSurfaces->FLAGS); + ByteSwap::Swap4(pcSurfaces->IDENT); + ByteSwap::Swap4(pcSurfaces->NUM_FRAMES); + ByteSwap::Swap4(pcSurfaces->NUM_SHADER); + ByteSwap::Swap4(pcSurfaces->NUM_TRIANGLES); + ByteSwap::Swap4(pcSurfaces->NUM_VERTICES); + ByteSwap::Swap4(pcSurfaces->OFS_END); + ByteSwap::Swap4(pcSurfaces->OFS_SHADERS); + ByteSwap::Swap4(pcSurfaces->OFS_ST); + ByteSwap::Swap4(pcSurfaces->OFS_TRIANGLES); + ByteSwap::Swap4(pcSurfaces->OFS_XYZNORMAL); #endif - // validate the header - this->ValidateHeaderOffsets(); + // validate the surface + this->ValidateSurfaceHeaderOffsets(pcSurfaces); - // now navigate to the list of surfaces - const MD3::Surface* pcSurfaces = (const MD3::Surface*) - (this->mBuffer + this->m_pcHeader->OFS_SURFACES); + // navigate to the vertex list of the surface + const MD3::Vertex* pcVertices = (const MD3::Vertex*) + (((uint8_t*)pcSurfaces) + pcSurfaces->OFS_XYZNORMAL); - // allocate output storage - pScene->mNumMeshes = this->m_pcHeader->NUM_SURFACES; - pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; + // navigate to the triangle list of the surface + const MD3::Triangle* pcTriangles = (const MD3::Triangle*) + (((uint8_t*)pcSurfaces) + pcSurfaces->OFS_TRIANGLES); - pScene->mNumMaterials = this->m_pcHeader->NUM_SURFACES; - pScene->mMaterials = new aiMaterial*[pScene->mNumMeshes]; + // navigate to the texture coordinate list of the surface + const MD3::TexCoord* pcUVs = (const MD3::TexCoord*) + (((uint8_t*)pcSurfaces) + pcSurfaces->OFS_ST); - // if an exception is thrown before the meshes are allocated -> - // otherwise the pointer value would be invalid and delete would crash - ::memset(pScene->mMeshes,0,pScene->mNumMeshes*sizeof(aiMesh*)); - ::memset(pScene->mMaterials,0,pScene->mNumMaterials*sizeof(aiMaterial*)); + // navigate to the shader list of the surface + const MD3::Shader* pcShaders = (const MD3::Shader*) + (((uint8_t*)pcSurfaces) + pcSurfaces->OFS_SHADERS); - unsigned int iNum = this->m_pcHeader->NUM_SURFACES; - unsigned int iNumMaterials = 0; - unsigned int iDefaultMatIndex = 0xFFFFFFFF; - while (iNum-- > 0) + // if the submesh is empty ignore it + if (0 == pcSurfaces->NUM_VERTICES || 0 == pcSurfaces->NUM_TRIANGLES) { - -#ifdef AI_BUILD_BIG_ENDIAN - - ByteSwap::Swap4(pcSurfaces->FLAGS); - ByteSwap::Swap4(pcSurfaces->IDENT); - ByteSwap::Swap4(pcSurfaces->NUM_FRAMES); - ByteSwap::Swap4(pcSurfaces->NUM_SHADER); - ByteSwap::Swap4(pcSurfaces->NUM_TRIANGLES); - ByteSwap::Swap4(pcSurfaces->NUM_VERTICES); - ByteSwap::Swap4(pcSurfaces->OFS_END); - ByteSwap::Swap4(pcSurfaces->OFS_SHADERS); - ByteSwap::Swap4(pcSurfaces->OFS_ST); - ByteSwap::Swap4(pcSurfaces->OFS_TRIANGLES); - ByteSwap::Swap4(pcSurfaces->OFS_XYZNORMAL); - -#endif - - // validate the surface - this->ValidateSurfaceHeaderOffsets(pcSurfaces); - - // navigate to the vertex list of the surface - const MD3::Vertex* pcVertices = (const MD3::Vertex*) - (((uint8_t*)pcSurfaces) + pcSurfaces->OFS_XYZNORMAL); - - // navigate to the triangle list of the surface - const MD3::Triangle* pcTriangles = (const MD3::Triangle*) - (((uint8_t*)pcSurfaces) + pcSurfaces->OFS_TRIANGLES); - - // navigate to the texture coordinate list of the surface - const MD3::TexCoord* pcUVs = (const MD3::TexCoord*) - (((uint8_t*)pcSurfaces) + pcSurfaces->OFS_ST); - - // navigate to the shader list of the surface - const MD3::Shader* pcShaders = (const MD3::Shader*) - (((uint8_t*)pcSurfaces) + pcSurfaces->OFS_SHADERS); - - // if the submesh is empty ignore it - if (0 == pcSurfaces->NUM_VERTICES || 0 == pcSurfaces->NUM_TRIANGLES) - { - pcSurfaces = (const MD3::Surface*)(((uint8_t*)pcSurfaces) + pcSurfaces->OFS_END); - pScene->mNumMeshes--; - continue; - } + pcSurfaces = (const MD3::Surface*)(((uint8_t*)pcSurfaces) + pcSurfaces->OFS_END); + pScene->mNumMeshes--; + continue; + } #ifdef AI_BUILD_BIG_ENDIAN - for (uint32_t i = 0; i < pcSurfaces->NUM_VERTICES;++i) - { - ByteSwap::Swap2( & pcVertices[i].NORMAL ); - ByteSwap::Swap2( & pcVertices[i].X ); - ByteSwap::Swap2( & pcVertices[i].Y ); - ByteSwap::Swap2( & pcVertices[i].Z ); + for (uint32_t i = 0; i < pcSurfaces->NUM_VERTICES;++i) + { + ByteSwap::Swap2( & pcVertices[i].NORMAL ); + ByteSwap::Swap2( & pcVertices[i].X ); + ByteSwap::Swap2( & pcVertices[i].Y ); + ByteSwap::Swap2( & pcVertices[i].Z ); - ByteSwap::Swap4( & pcUVs[i].U ); - ByteSwap::Swap4( & pcUVs[i].U ); - } - for (uint32_t i = 0; i < pcSurfaces->NUM_TRIANGLES;++i) - { - ByteSwap::Swap4(pcTriangles[i].INDEXES[0]); - ByteSwap::Swap4(pcTriangles[i].INDEXES[1]); - ByteSwap::Swap4(pcTriangles[i].INDEXES[2]); - } + ByteSwap::Swap4( & pcUVs[i].U ); + ByteSwap::Swap4( & pcUVs[i].U ); + } + for (uint32_t i = 0; i < pcSurfaces->NUM_TRIANGLES;++i) + { + ByteSwap::Swap4(pcTriangles[i].INDEXES[0]); + ByteSwap::Swap4(pcTriangles[i].INDEXES[1]); + ByteSwap::Swap4(pcTriangles[i].INDEXES[2]); + } #endif - // allocate the output mesh - pScene->mMeshes[iNum] = new aiMesh(); - aiMesh* pcMesh = pScene->mMeshes[iNum]; + // allocate the output mesh + pScene->mMeshes[iNum] = new aiMesh(); + aiMesh* pcMesh = pScene->mMeshes[iNum]; - pcMesh->mNumVertices = pcSurfaces->NUM_TRIANGLES*3; - pcMesh->mNumFaces = pcSurfaces->NUM_TRIANGLES; - pcMesh->mFaces = new aiFace[pcSurfaces->NUM_TRIANGLES]; - pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices]; - pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices]; - pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices]; - pcMesh->mNumUVComponents[0] = 2; + pcMesh->mNumVertices = pcSurfaces->NUM_TRIANGLES*3; + pcMesh->mNumFaces = pcSurfaces->NUM_TRIANGLES; + pcMesh->mFaces = new aiFace[pcSurfaces->NUM_TRIANGLES]; + pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices]; + pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices]; + pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices]; + pcMesh->mNumUVComponents[0] = 2; - // fill in all triangles - unsigned int iCurrent = 0; - for (unsigned int i = 0; i < (unsigned int)pcSurfaces->NUM_TRIANGLES;++i) + // fill in all triangles + unsigned int iCurrent = 0; + for (unsigned int i = 0; i < (unsigned int)pcSurfaces->NUM_TRIANGLES;++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) { - pcMesh->mFaces[i].mIndices = new unsigned int[3]; - pcMesh->mFaces[i].mNumIndices = 3; + // read vertices + pcMesh->mVertices[iCurrent].x = pcVertices[ pcTriangles->INDEXES[c]].X; + pcMesh->mVertices[iCurrent].y = pcVertices[ pcTriangles->INDEXES[c]].Y*-1.0f; + pcMesh->mVertices[iCurrent].z = pcVertices[ pcTriangles->INDEXES[c]].Z; - unsigned int iTemp = iCurrent; - for (unsigned int c = 0; c < 3;++c,++iCurrent) - { - // read vertices - pcMesh->mVertices[iCurrent].x = pcVertices[ pcTriangles->INDEXES[c]].X; - pcMesh->mVertices[iCurrent].y = pcVertices[ pcTriangles->INDEXES[c]].Y*-1.0f; - pcMesh->mVertices[iCurrent].z = pcVertices[ pcTriangles->INDEXES[c]].Z; + // convert the normal vector to uncompressed float3 format + LatLngNormalToVec3(pcVertices[pcTriangles->INDEXES[c]].NORMAL, + (float*)&pcMesh->mNormals[iCurrent]); - // convert the normal vector to uncompressed float3 format - LatLngNormalToVec3(pcVertices[pcTriangles->INDEXES[c]].NORMAL, - (float*)&pcMesh->mNormals[iCurrent]); + pcMesh->mNormals[iCurrent].y *= -1.0f; - pcMesh->mNormals[iCurrent].y *= -1.0f; - - // read texture coordinates - pcMesh->mTextureCoords[0][iCurrent].x = pcUVs[ pcTriangles->INDEXES[c]].U; - pcMesh->mTextureCoords[0][iCurrent].y = 1.0f-pcUVs[ pcTriangles->INDEXES[c]].V; - } - // FIX: flip the face ordering for use with OpenGL - pcMesh->mFaces[i].mIndices[0] = iTemp+2; - pcMesh->mFaces[i].mIndices[1] = iTemp+1; - pcMesh->mFaces[i].mIndices[2] = iTemp+0; - pcTriangles++; + // read texture coordinates + pcMesh->mTextureCoords[0][iCurrent].x = pcUVs[ pcTriangles->INDEXES[c]].U; + pcMesh->mTextureCoords[0][iCurrent].y = 1.0f-pcUVs[ pcTriangles->INDEXES[c]].V; } + // FIX: flip the face ordering for use with OpenGL + pcMesh->mFaces[i].mIndices[0] = iTemp+2; + pcMesh->mFaces[i].mIndices[1] = iTemp+1; + pcMesh->mFaces[i].mIndices[2] = iTemp+0; + pcTriangles++; + } - // get the first shader (= texture?) assigned to the surface - if (0 != pcSurfaces->NUM_SHADER) + // get the first shader (= texture?) assigned to the surface + if (pcSurfaces->NUM_SHADER) + { + // make a relative path. + // if the MD3's internal path itself and the given path are using + // the same directory remove it + const char* szEndDir1 = ::strrchr((const char*)pcHeader->NAME,'\\'); + if (!szEndDir1)szEndDir1 = ::strrchr((const char*)pcHeader->NAME,'/'); + + const char* szEndDir2 = ::strrchr((const char*)pcShaders->NAME,'\\'); + if (!szEndDir2)szEndDir2 = ::strrchr((const char*)pcShaders->NAME,'/'); + + if (szEndDir1 && szEndDir2) { - // make a relative path. - // if the MD3's internal path itself and the given path are using - // the same directory remove it - const char* szEndDir1 = ::strrchr((const char*)this->m_pcHeader->NAME,'\\'); - if (!szEndDir1)szEndDir1 = ::strrchr((const char*)this->m_pcHeader->NAME,'/'); + // both of them are valid + const unsigned int iLen1 = (unsigned int)(szEndDir1 - (const char*)pcHeader->NAME); + const unsigned int iLen2 = std::min (iLen1, (unsigned int)(szEndDir2 - (const char*)pcShaders->NAME) ); - const char* szEndDir2 = ::strrchr((const char*)pcShaders->NAME,'\\'); - if (!szEndDir2)szEndDir2 = ::strrchr((const char*)pcShaders->NAME,'/'); - - if (szEndDir1 && szEndDir2) + bool bSuccess = true; + for (unsigned int a = 0; a < iLen2;++a) { - // both of them are valid - const unsigned int iLen1 = (unsigned int)(szEndDir1 - (const char*)this->m_pcHeader->NAME); - const unsigned int iLen2 = std::min (iLen1, (unsigned int)(szEndDir2 - (const char*)pcShaders->NAME) ); - - bool bSuccess = true; - for (unsigned int a = 0; a < iLen2;++a) + char sz = ::tolower ( pcShaders->NAME[a] ); + char sz2 = ::tolower ( pcHeader->NAME[a] ); + if (sz != sz2) { - char sz = ::tolower ( pcShaders->NAME[a] ); - char sz2 = ::tolower ( this->m_pcHeader->NAME[a] ); - if (sz != sz2) - { - bSuccess = false; - break; - } - } - if (bSuccess) - { - // use the file name only - szEndDir2++; - } - else - { - // use the full path - szEndDir2 = (const char*)pcShaders->NAME; + bSuccess = false; + break; } } - - // now try to find out whether we have this shader already - bool bHave = false; - for (unsigned int p = 0; p < iNumMaterials;++p) + if (bSuccess) { - if (iDefaultMatIndex == p)continue; - - aiString szOut; - if(AI_SUCCESS == aiGetMaterialString ( (aiMaterial*)pScene->mMaterials[p], - AI_MATKEY_TEXTURE_DIFFUSE(0),&szOut)) - { - if (0 == ASSIMP_stricmp(szOut.data,szEndDir2)) - { - // equal. reuse this material (texture) - bHave = true; - pcMesh->mMaterialIndex = p; - break; - } - } - } - - if (!bHave) - { - MaterialHelper* pcHelper = new MaterialHelper(); - - if (szEndDir2) - { - if (szEndDir2[0]) - { - aiString szString; - const size_t iLen = ::strlen(szEndDir2); - ::memcpy(szString.data,szEndDir2,iLen); - szString.data[iLen] = '\0'; - szString.length = iLen; - - pcHelper->AddProperty(&szString,AI_MATKEY_TEXTURE_DIFFUSE(0)); - } - else - { - DefaultLogger::get()->warn("Texture file name has zero length. " - "It will be skipped."); - } - } - - int iMode = (int)aiShadingMode_Gouraud; - pcHelper->AddProperty(&iMode, 1, AI_MATKEY_SHADING_MODEL); - - // add a small ambient color value - Quake 3 seems to have one - aiColor3D clr; - clr.b = clr.g = clr.r = 0.05f; - pcHelper->AddProperty(&clr, 1,AI_MATKEY_COLOR_AMBIENT); - - aiString szName; - szName.Set(AI_DEFAULT_MATERIAL_NAME); - pcHelper->AddProperty(&szName,AI_MATKEY_NAME); - - pScene->mMaterials[iNumMaterials] = (aiMaterial*)pcHelper; - iDefaultMatIndex = pcMesh->mMaterialIndex = iNumMaterials++; - } - } - else - { - if (0xFFFFFFFF != iDefaultMatIndex) - { - pcMesh->mMaterialIndex = iDefaultMatIndex; + // use the file name only + szEndDir2++; } else { - MaterialHelper* pcHelper = new MaterialHelper(); - - // fill in a default material - int iMode = (int)aiShadingMode_Gouraud; - pcHelper->AddProperty(&iMode, 1, AI_MATKEY_SHADING_MODEL); - - aiColor3D clr; - clr.b = clr.g = clr.r = 0.6f; - pcHelper->AddProperty(&clr, 1,AI_MATKEY_COLOR_DIFFUSE); - pcHelper->AddProperty(&clr, 1,AI_MATKEY_COLOR_SPECULAR); - - clr.b = clr.g = clr.r = 0.05f; - pcHelper->AddProperty(&clr, 1,AI_MATKEY_COLOR_AMBIENT); - - pScene->mMaterials[iNumMaterials] = (aiMaterial*)pcHelper; - iDefaultMatIndex = pcMesh->mMaterialIndex = iNumMaterials++; + // use the full path + szEndDir2 = (const char*)pcShaders->NAME; } } - // go to the next surface - pcSurfaces = (const MD3::Surface*)(((unsigned char*)pcSurfaces) + pcSurfaces->OFS_END); + MaterialHelper* pcHelper = new MaterialHelper(); + + if (szEndDir2) + { + if (szEndDir2[0]) + { + aiString szString; + const size_t iLen = ::strlen(szEndDir2); + ::memcpy(szString.data,szEndDir2,iLen); + szString.data[iLen] = '\0'; + szString.length = iLen; + + pcHelper->AddProperty(&szString,AI_MATKEY_TEXTURE_DIFFUSE(0)); + } + else + { + DefaultLogger::get()->warn("Texture file name has zero length. " + "It will be skipped."); + } + } + + int iMode = (int)aiShadingMode_Gouraud; + pcHelper->AddProperty(&iMode, 1, AI_MATKEY_SHADING_MODEL); + + // add a small ambient color value - Quake 3 seems to have one + aiColor3D clr; + clr.b = clr.g = clr.r = 0.05f; + pcHelper->AddProperty(&clr, 1,AI_MATKEY_COLOR_AMBIENT); + + clr.b = clr.g = clr.r = 1.0f; + pcHelper->AddProperty(&clr, 1,AI_MATKEY_COLOR_DIFFUSE); + pcHelper->AddProperty(&clr, 1,AI_MATKEY_COLOR_SPECULAR); + + aiString szName; + szName.Set(AI_DEFAULT_MATERIAL_NAME); + pcHelper->AddProperty(&szName,AI_MATKEY_NAME); + + pScene->mMaterials[iNumMaterials] = (aiMaterial*)pcHelper; + pcMesh->mMaterialIndex = iNumMaterials++; } + else + { + if (0xFFFFFFFF != iDefaultMatIndex) + { + pcMesh->mMaterialIndex = iDefaultMatIndex; + } + else + { + MaterialHelper* pcHelper = new MaterialHelper(); - if (0 == pScene->mNumMeshes) - throw new ImportErrorException( "Invalid md3 file: File contains no valid mesh"); - pScene->mNumMaterials = iNumMaterials; + // fill in a default material + int iMode = (int)aiShadingMode_Gouraud; + pcHelper->AddProperty(&iMode, 1, AI_MATKEY_SHADING_MODEL); - // now we need to generate an empty node graph - pScene->mRootNode = new aiNode(); - pScene->mRootNode->mNumMeshes = pScene->mNumMeshes; - pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes]; + aiColor3D clr; + clr.b = clr.g = clr.r = 0.6f; + pcHelper->AddProperty(&clr, 1,AI_MATKEY_COLOR_DIFFUSE); + pcHelper->AddProperty(&clr, 1,AI_MATKEY_COLOR_SPECULAR); - for (unsigned int i = 0; i < pScene->mNumMeshes;++i) - pScene->mRootNode->mMeshes[i] = i; + clr.b = clr.g = clr.r = 0.05f; + pcHelper->AddProperty(&clr, 1,AI_MATKEY_COLOR_AMBIENT); + pScene->mMaterials[iNumMaterials] = (aiMaterial*)pcHelper; + iDefaultMatIndex = pcMesh->mMaterialIndex = iNumMaterials++; + } + } + // go to the next surface + pcSurfaces = (const MD3::Surface*)(((unsigned char*)pcSurfaces) + pcSurfaces->OFS_END); } - catch (ImportErrorException* ex) - { - delete[] this->mBuffer; AI_DEBUG_INVALIDATE_PTR(this->mBuffer); - throw ex; - } - delete[] this->mBuffer; AI_DEBUG_INVALIDATE_PTR(this->mBuffer); -} \ No newline at end of file + + if (!pScene->mNumMeshes) + throw new ImportErrorException( "Invalid MD3 file: File contains no valid mesh"); + pScene->mNumMaterials = iNumMaterials; + + // now we need to generate an empty node graph + pScene->mRootNode = new aiNode(); + pScene->mRootNode->mNumMeshes = pScene->mNumMeshes; + pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes]; + + for (unsigned int i = 0; i < pScene->mNumMeshes;++i) + pScene->mRootNode->mMeshes[i] = i; +} diff --git a/code/MD3Loader.h b/code/MD3Loader.h index 2eb85eada..3939b87c3 100644 --- a/code/MD3Loader.h +++ b/code/MD3Loader.h @@ -42,17 +42,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_MD3LOADER_H_INCLUDED #define AI_MD3LOADER_H_INCLUDED -#include - #include "BaseImporter.h" +#include "ByteSwap.h" #include "../include/aiTypes.h" struct aiNode; #include "MD3FileData.h" -namespace Assimp -{ +namespace Assimp { class MaterialHelper; using namespace MD3; @@ -117,10 +115,10 @@ protected: unsigned int configFrameID; /** Header of the MD3 file */ - const MD3::Header* m_pcHeader; + BE_NCONST MD3::Header* pcHeader; - /** Buffer to hold the loaded file */ - const unsigned char* mBuffer; + /** File buffer */ + BE_NCONST unsigned char* mBuffer; /** Size of the file, in bytes */ unsigned int fileSize; diff --git a/code/MDCFileData.h b/code/MDCFileData.h index 9e205cc9e..dfd1a8124 100644 --- a/code/MDCFileData.h +++ b/code/MDCFileData.h @@ -53,14 +53,7 @@ http://themdcfile.planetwolfenstein.gamespy.com/MDC_File_Format.pdf #include "../include/aiMesh.h" #include "../include/aiAnim.h" -#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) -# pragma pack(push,1) -# define PACK_STRUCT -#elif defined( __GNUC__ ) -# define PACK_STRUCT __attribute__((packed)) -#else -# error Compiler not supported -#endif +#include "./Compiler/pushpack1.h" namespace Assimp { @@ -188,11 +181,7 @@ struct Shader } PACK_STRUCT; -// reset packing to the original value -#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) -# pragma pack( pop ) -#endif -#undef PACK_STRUCT +#include "./Compiler/poppack1.h" // --------------------------------------------------------------------------- diff --git a/code/MDCLoader.cpp b/code/MDCLoader.cpp new file mode 100644 index 000000000..65c7f464d --- /dev/null +++ b/code/MDCLoader.cpp @@ -0,0 +1,476 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (ASSIMP) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2008, ASSIMP Development Team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the ASSIMP team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the ASSIMP Development Team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ + +/** @file Implementation of the MDC importer class */ + +// internal headers +#include "MDCLoader.h" +#include "MD3FileData.h" +#include "MaterialSystem.h" +#include "StringComparison.h" +#include "MDCNormalTable.h" // shouldn't be included by other units +#include "ByteSwap.h" + +// public ASSIMP headers +#include "../include/IOStream.h" +#include "../include/IOSystem.h" +#include "../include/aiMesh.h" +#include "../include/aiScene.h" +#include "../include/aiAssert.h" +#include "../include/DefaultLogger.h" +#include "../include/assimp.hpp" + +// boost headers +#include + +using namespace Assimp; +using namespace Assimp::MDC; + + +// ------------------------------------------------------------------------------------------------ +void MDC::BuildVertex(const Frame& frame, + const BaseVertex& bvert, + const CompressedVertex& cvert, + aiVector3D& vXYZOut, + aiVector3D& vNorOut) +{ + // compute the position + const float xd = (cvert.xd - AI_MDC_CVERT_BIAS) * AI_MDC_DELTA_SCALING; + const float yd = (cvert.yd - AI_MDC_CVERT_BIAS) * AI_MDC_DELTA_SCALING; + const float zd = (cvert.zd - AI_MDC_CVERT_BIAS) * AI_MDC_DELTA_SCALING; + vXYZOut.x = frame.localOrigin.x + AI_MDC_BASE_SCALING * (bvert.x + xd); + vXYZOut.y = frame.localOrigin.y + AI_MDC_BASE_SCALING * (bvert.y + yd); + vXYZOut.z = frame.localOrigin.z + AI_MDC_BASE_SCALING * (bvert.z + zd); + + // compute the normal vector .. ehm ... lookup it in the table :-) + vNorOut.x = mdcNormals[cvert.nd][0]; + vNorOut.y = mdcNormals[cvert.nd][1]; + vNorOut.z = mdcNormals[cvert.nd][2]; +} + +// ------------------------------------------------------------------------------------------------ +// Constructor to be privately used by Importer +MDCImporter::MDCImporter() +{ +} + +// ------------------------------------------------------------------------------------------------ +// Destructor, private as well +MDCImporter::~MDCImporter() +{ +} +// ------------------------------------------------------------------------------------------------ +// Returns whether the class can handle the format of the given file. +bool MDCImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +{ + // simple check of file extension is enough for the moment + std::string::size_type pos = pFile.find_last_of('.'); + // no file extension - can't read + if( pos == std::string::npos) + return false; + std::string extension = pFile.substr( pos); + + if (extension.length() < 4)return false; + if (extension[0] != '.')return false; + + if( extension[1] != 'M' && extension[1] != 'm')return false; + if( extension[2] != 'D' && extension[2] != 'd')return false; + if( extension[3] != 'C' && extension[3] != 'c')return false; + + return true; +} +// ------------------------------------------------------------------------------------------------ +// Validate the header of the given MDC file +void MDCImporter::ValidateHeader() +{ + AI_SWAP4( this->pcHeader->ulVersion ); + AI_SWAP4( this->pcHeader->ulFlags ); + AI_SWAP4( this->pcHeader->ulNumFrames ); + AI_SWAP4( this->pcHeader->ulNumTags ); + AI_SWAP4( this->pcHeader->ulNumSurfaces ); + AI_SWAP4( this->pcHeader->ulNumSkins ); + AI_SWAP4( this->pcHeader->ulOffsetBorderFrames ); + + if (pcHeader->ulIdent != AI_MDC_MAGIC_NUMBER_BE && + pcHeader->ulIdent != AI_MDC_MAGIC_NUMBER_LE) + { + char szBuffer[5]; + szBuffer[0] = ((char*)&pcHeader->ulIdent)[0]; + szBuffer[1] = ((char*)&pcHeader->ulIdent)[1]; + szBuffer[2] = ((char*)&pcHeader->ulIdent)[2]; + szBuffer[3] = ((char*)&pcHeader->ulIdent)[3]; + szBuffer[4] = '\0'; + + throw new ImportErrorException("Invalid MDC magic word: should be IDPC, the " + "magic word found is " + std::string( szBuffer )); + } + + if (pcHeader->ulVersion != AI_MDC_VERSION) + DefaultLogger::get()->warn("Unsupported MDC file version (2 (AI_MDC_VERSION) was expected)"); + + if (pcHeader->ulOffsetBorderFrames + pcHeader->ulNumFrames * sizeof(MDC::Frame) > this->fileSize || + pcHeader->ulOffsetSurfaces + pcHeader->ulNumSurfaces * sizeof(MDC::Surface) > this->fileSize) + { + throw new ImportErrorException("Some of the offset values in the MDC header are invalid " + "and point to something behind the file."); + } + + if (this->configFrameID >= this->pcHeader->ulNumFrames) + throw new ImportErrorException("The requested frame is not available"); +} +// ------------------------------------------------------------------------------------------------ +// Validate the header of a given MDC file surface +void MDCImporter::ValidateSurfaceHeader(BE_NCONST MDC::Surface* pcSurf) +{ + AI_SWAP4(pcSurf->ulFlags); + AI_SWAP4(pcSurf->ulNumCompFrames); + AI_SWAP4(pcSurf->ulNumBaseFrames); + AI_SWAP4(pcSurf->ulNumShaders); + AI_SWAP4(pcSurf->ulNumVertices); + AI_SWAP4(pcSurf->ulNumTriangles); + AI_SWAP4(pcSurf->ulOffsetTriangles); + AI_SWAP4(pcSurf->ulOffsetTexCoords); + AI_SWAP4(pcSurf->ulOffsetBaseVerts); + AI_SWAP4(pcSurf->ulOffsetCompVerts); + AI_SWAP4(pcSurf->ulOffsetFrameBaseFrames); + AI_SWAP4(pcSurf->ulOffsetFrameCompFrames); + AI_SWAP4(pcSurf->ulOffsetEnd); + + const unsigned int iMax = this->fileSize - (unsigned int)((int8_t*)pcSurf-(int8_t*)pcHeader); + + if (pcSurf->ulOffsetBaseVerts + pcSurf->ulNumVertices * sizeof(MDC::BaseVertex) > iMax || + (pcSurf->ulNumCompFrames && pcSurf->ulOffsetCompVerts + pcSurf->ulNumVertices * sizeof(MDC::CompressedVertex) > iMax) || + pcSurf->ulOffsetTriangles + pcSurf->ulNumTriangles * sizeof(MDC::Triangle) > iMax || + pcSurf->ulOffsetTexCoords + pcSurf->ulNumVertices * sizeof(MDC::TexturCoord) > iMax || + pcSurf->ulOffsetShaders + pcSurf->ulNumShaders * sizeof(MDC::Shader) > iMax || + pcSurf->ulOffsetFrameBaseFrames + pcSurf->ulNumBaseFrames * 2 > iMax || + (pcSurf->ulNumCompFrames && pcSurf->ulOffsetFrameCompFrames + pcSurf->ulNumCompFrames * 2 > iMax)) + { + throw new ImportErrorException("Some of the offset values in the MDC surface header " + "are invalid and point somewhere behind the file."); + } +} +// ------------------------------------------------------------------------------------------------ +// Setup configuration properties +void MDCImporter::SetupProperties(const Importer* pImp) +{ + // The AI_CONFIG_IMPORT_MDC_KEYFRAME option overrides the + // AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option. + if(0xffffffff == (this->configFrameID = pImp->GetProperty( + AI_CONFIG_IMPORT_MDC_KEYFRAME,0xffffffff))) + { + this->configFrameID = pImp->GetProperty(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0); + } +} +// ------------------------------------------------------------------------------------------------ +// Imports the given file into the given scene structure. +void MDCImporter::InternReadFile( + const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) +{ + boost::scoped_ptr file( pIOHandler->Open( pFile)); + + // Check whether we can read from the file + if( file.get() == NULL) + throw new ImportErrorException( "Failed to open MDC file " + pFile + "."); + + // check whether the mdc file is large enough to contain the file header + fileSize = (unsigned int)file->FileSize(); + if( fileSize < sizeof(MDC::Header)) + throw new ImportErrorException( "MDC File is too small."); + + std::vector mBuffer2(fileSize); + file->Read( &mBuffer2[0], 1, fileSize); + mBuffer = &mBuffer2[0]; + + // validate the file header + this->pcHeader = (BE_NCONST MDC::Header*)this->mBuffer; + this->ValidateHeader(); + + std::vector aszShaders; + + // get a pointer to the frame we want to read + BE_NCONST MDC::Frame* pcFrame = (BE_NCONST MDC::Frame*)(this->mBuffer+ + this->pcHeader->ulOffsetBorderFrames); + + // no need to swap the other members, we won't need them + pcFrame += configFrameID; + AI_SWAP4( pcFrame->localOrigin[0] ); + AI_SWAP4( pcFrame->localOrigin[1] ); + AI_SWAP4( pcFrame->localOrigin[2] ); + + // get the number of valid surfaces + BE_NCONST MDC::Surface* pcSurface, *pcSurface2; + pcSurface = pcSurface2 = (BE_NCONST MDC::Surface*)(mBuffer + pcHeader->ulOffsetSurfaces); + unsigned int iNumShaders = 0; + for (unsigned int i = 0; i < pcHeader->ulNumSurfaces;++i) + { + // validate the surface header + this->ValidateSurfaceHeader(pcSurface2); + + if (pcSurface2->ulNumVertices && pcSurface2->ulNumTriangles)++pScene->mNumMeshes; + iNumShaders += pcSurface2->ulNumShaders; + pcSurface2 = (const MDC::Surface*)((int8_t*)pcSurface2 + pcSurface2->ulOffsetEnd); + } + aszShaders.reserve(iNumShaders); + pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; + + // necessary that we don't crash if an exception occurs + for (unsigned int i = 0; i < pScene->mNumMeshes;++i) + pScene->mMeshes[i] = NULL; + + // now read all surfaces + unsigned int iDefaultMatIndex = 0xffffffff; + for (unsigned int i = 0, iNum = 0; i < pcHeader->ulNumSurfaces;++i) + { + if (!pcSurface->ulNumVertices || !pcSurface->ulNumTriangles)continue; + aiMesh* pcMesh = pScene->mMeshes[iNum++] = new aiMesh(); + + pcMesh->mNumFaces = pcSurface->ulNumTriangles; + pcMesh->mNumVertices = pcMesh->mNumFaces * 3; + + // store the name of the surface for use as node name. + // FIX: make sure there is a 0 termination + const_cast(pcSurface->ucName[AI_MDC_MAXQPATH-1]) = '\0'; + pcMesh->mTextureCoords[3] = (aiVector3D*)pcSurface->ucName; + + // go to the first shader in the file. ignore the others. + if (pcSurface->ulNumShaders) + { + const MDC::Shader* pcShader = (const MDC::Shader*)((int8_t*)pcSurface + pcSurface->ulOffsetShaders); + pcMesh->mMaterialIndex = (unsigned int)aszShaders.size(); + + // create a new shader + aszShaders.push_back(std::string( pcShader->ucName, std::min( + ::strlen(pcShader->ucName),sizeof(pcShader->ucName)) )); + } + // need to create a default material + else if (0xffffffff == iDefaultMatIndex) + { + pcMesh->mMaterialIndex = iDefaultMatIndex = (unsigned int)aszShaders.size(); + aszShaders.push_back(std::string()); + } + // otherwise assign a reference to the default material + else pcMesh->mMaterialIndex = iDefaultMatIndex; + + // allocate output storage for the mesh + aiVector3D* pcVertCur = pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices]; + aiVector3D* pcNorCur = pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices]; + aiVector3D* pcUVCur = pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices]; + aiFace* pcFaceCur = pcMesh->mFaces = new aiFace[pcMesh->mNumFaces]; + + // create all vertices/faces + BE_NCONST MDC::Triangle* pcTriangle = (BE_NCONST MDC::Triangle*) + ((int8_t*)pcSurface+pcSurface->ulOffsetTriangles); + + BE_NCONST MDC::TexturCoord* const pcUVs = (BE_NCONST MDC::TexturCoord*) + ((int8_t*)pcSurface+pcSurface->ulOffsetTexCoords); + + // get a pointer to the uncompressed vertices + int16_t iOfs = *((int16_t*) ((int8_t*) pcSurface + + pcSurface->ulOffsetFrameBaseFrames) + this->configFrameID); + + AI_SWAP2(iOfs); + + BE_NCONST MDC::BaseVertex* const pcVerts = (BE_NCONST MDC::BaseVertex*) + ((int8_t*)pcSurface+pcSurface->ulOffsetBaseVerts) + + ((int)iOfs * pcSurface->ulNumVertices * 4); + + // do the main swapping stuff ... +#if (defined AI_BUILD_BIG_ENDIAN) + + // swap all triangles + for (unsigned int i = 0; i < pcSurface->ulNumTriangles;++i) + { + AI_SWAP4( pcTriangle[i].aiIndices[0] ); + AI_SWAP4( pcTriangle[i].aiIndices[1] ); + AI_SWAP4( pcTriangle[i].aiIndices[2] ); + } + + // swap all vertices + for (unsigned int i = 0; i < pcSurface->ulNumVertices*pcSurface->ulNumBaseFrames;++i) + { + AI_SWAP2( pcVerts->normal ); + AI_SWAP2( pcVerts->x ); + AI_SWAP2( pcVerts->y ); + AI_SWAP2( pcVerts->z ); + } + + // swap all texture coordinates + for (unsigned int i = 0; i < pcSurface->ulNumVertices;++i) + { + AI_SWAP4( pcUVs->v ); + AI_SWAP4( pcUVs->v ); + } + +#endif + + const MDC::CompressedVertex* pcCVerts; + int16_t* mdcCompVert = NULL; + + // access compressed frames for large frame numbers, but never for the first + if( this->configFrameID && pcSurface->ulNumCompFrames > 0 ) + { + mdcCompVert = (int16_t*) ((int8_t*)pcSurface+pcSurface->ulOffsetFrameCompFrames) + this->configFrameID; + AI_SWAP2P(mdcCompVert); + if( *mdcCompVert >= 0 ) + { + pcCVerts = (const MDC::CompressedVertex*)((int8_t*)pcSurface + + pcSurface->ulOffsetCompVerts) + *mdcCompVert * pcSurface->ulNumVertices; + } + else mdcCompVert = NULL; + } + + // copy all faces + for (unsigned int iFace = 0; iFace < pcSurface->ulNumTriangles;++iFace, + ++pcTriangle,++pcFaceCur) + { + const unsigned int iOutIndex = iFace*3; + pcFaceCur->mNumIndices = 3; + pcFaceCur->mIndices = new unsigned int[3]; + + for (unsigned int iIndex = 0; iIndex < 3;++iIndex, + ++pcVertCur,++pcUVCur,++pcNorCur) + { + uint32_t quak = pcTriangle->aiIndices[iIndex]; + if (quak >= pcSurface->ulNumVertices) + { + DefaultLogger::get()->error("MDC vertex index is out of range"); + quak = pcSurface->ulNumVertices-1; + } + + // compressed vertices? + if (mdcCompVert) + { + MDC::BuildVertex(*pcFrame,pcVerts[quak],pcCVerts[quak], + *pcVertCur,*pcNorCur); + } + else + { + // copy position + pcVertCur->x = pcVerts[quak].x * AI_MDC_BASE_SCALING; + pcVertCur->y = pcVerts[quak].y * AI_MDC_BASE_SCALING; + pcVertCur->z = pcVerts[quak].z * AI_MDC_BASE_SCALING; + + // copy normals + MD3::LatLngNormalToVec3( pcVerts[quak].normal, &pcNorCur->x ); + + // copy texture coordinates + pcUVCur->x = pcUVs[quak].u; + pcUVCur->y = 1.0f-pcUVs[quak].v; // DX to OGL + } + pcVertCur->x += pcFrame->localOrigin[0] ; + pcVertCur->y += pcFrame->localOrigin[1] ; + pcVertCur->z += pcFrame->localOrigin[2] ; + } + + // swap the face order - DX to OGL + pcFaceCur->mIndices[0] = iOutIndex + 2; + pcFaceCur->mIndices[1] = iOutIndex + 1; + pcFaceCur->mIndices[2] = iOutIndex + 0; + } + + pcSurface = (BE_NCONST MDC::Surface*)((int8_t*)pcSurface + pcSurface->ulOffsetEnd); + } + + // create a flat node graph with a root node and one child for each surface + if (!pScene->mNumMeshes) + throw new ImportErrorException( "Invalid MDC file: File contains no valid mesh"); + else if (1 == pScene->mNumMeshes) + { + pScene->mRootNode = new aiNode(); + pScene->mRootNode->mName.Set(std::string((const char*)pScene->mMeshes[0]->mTextureCoords[3])); + pScene->mRootNode->mNumMeshes = 1; + pScene->mRootNode->mMeshes = new unsigned int[1]; + pScene->mRootNode->mMeshes[0] = 0; + } + else + { + pScene->mRootNode = new aiNode(); + pScene->mRootNode->mNumChildren = pScene->mNumMeshes; + pScene->mRootNode->mChildren = new aiNode*[pScene->mNumMeshes]; + pScene->mRootNode->mName.Set(""); + for (unsigned int i = 0; i < pScene->mNumMeshes;++i) + { + aiNode* pcNode = pScene->mRootNode->mChildren[i] = new aiNode(); + pcNode->mParent = pScene->mRootNode; + pcNode->mName.Set(std::string((const char*)pScene->mMeshes[i]->mTextureCoords[3])); + pcNode->mNumMeshes = 1; + pcNode->mMeshes = new unsigned int[1]; + pcNode->mMeshes[0] = i; + } + } + + // make sure we invalidate the pointer to the mesh name + for (unsigned int i = 0; i < pScene->mNumMeshes;++i) + pScene->mMeshes[i]->mTextureCoords[3] = NULL; + + // create materials + pScene->mNumMaterials = aszShaders.size(); + pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]; + for (unsigned int i = 0; i < pScene->mNumMaterials;++i) + { + MaterialHelper* pcMat = new MaterialHelper(); + pScene->mMaterials[i] = pcMat; + + const std::string& name = aszShaders[i]; + + int iMode = (int)aiShadingMode_Gouraud; + pcMat->AddProperty(&iMode, 1, AI_MATKEY_SHADING_MODEL); + + // add a small ambient color value - RtCW seems to have one + aiColor3D clr; + clr.b = clr.g = clr.r = 0.05f; + pcMat->AddProperty(&clr, 1,AI_MATKEY_COLOR_AMBIENT); + + if (name.length())clr.b = clr.g = clr.r = 1.0f; + else clr.b = clr.g = clr.r = 0.6f; + + pcMat->AddProperty(&clr, 1,AI_MATKEY_COLOR_DIFFUSE); + pcMat->AddProperty(&clr, 1,AI_MATKEY_COLOR_SPECULAR); + + if (name.length()) + { + aiString path; + path.Set(name); + pcMat->AddProperty(&path,AI_MATKEY_TEXTURE_DIFFUSE(0)); + } + } +} diff --git a/code/MDCLoader.h b/code/MDCLoader.h new file mode 100644 index 000000000..c31affbc6 --- /dev/null +++ b/code/MDCLoader.h @@ -0,0 +1,132 @@ +/* +Open Asset Import Library (ASSIMP) +---------------------------------------------------------------------- + +Copyright (c) 2006-2008, ASSIMP Development Team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the ASSIMP team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the ASSIMP Development Team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +/** @file Definition of the MDC importer class. */ +#ifndef AI_MDCLOADER_H_INCLUDED +#define AI_MDCLOADER_H_INCLUDED + +#include "../include/aiTypes.h" + +#include "BaseImporter.h" +#include "MDCFileData.h" +#include "ByteSwap.h" + +namespace Assimp +{ +using namespace MDC; + +// --------------------------------------------------------------------------- +/** Used to load MDC files +*/ +class MDCImporter : public BaseImporter +{ + friend class Importer; + +protected: + /** Constructor to be privately used by Importer */ + MDCImporter(); + + /** Destructor, private as well */ + ~MDCImporter(); + +public: + + // ------------------------------------------------------------------- + /** Returns whether the class can handle the format of the given file. + * See BaseImporter::CanRead() for details. */ + bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + + // ------------------------------------------------------------------- + /** Called prior to ReadFile(). + * The function is a request to the importer to update its configuration + * basing on the Importer's configuration property list. + */ + void SetupProperties(const Importer* pImp); + +protected: + + // ------------------------------------------------------------------- + /** Called by Importer::GetExtensionList() for each loaded importer. + * See BaseImporter::GetExtensionList() for details + */ + void GetExtensionList(std::string& append) + { + append.append("*.mdc"); + } + + // ------------------------------------------------------------------- + /** Imports the given file into the given scene structure. + * See BaseImporter::InternReadFile() for details + */ + void InternReadFile( const std::string& pFile, aiScene* pScene, + IOSystem* pIOHandler); + +protected: + + + // ------------------------------------------------------------------- + /** Validate the header of the file + */ + void ValidateHeader(); + + // ------------------------------------------------------------------- + /** Validate the header of a MDC surface + */ + void ValidateSurfaceHeader(BE_NCONST MDC::Surface* pcSurf); + +protected: + + + /** Configuration option: frame to be loaded */ + unsigned int configFrameID; + + /** Header of the MDC file */ + BE_NCONST MDC::Header* pcHeader; + + /** Buffer to hold the loaded file */ + unsigned char* mBuffer; + + /** size of the file, in bytes */ + unsigned int fileSize; +}; + +} // end of namespace Assimp + +#endif // AI_3DSIMPORTER_H_INC \ No newline at end of file diff --git a/code/MDCNormalTable.h b/code/MDCNormalTable.h new file mode 100644 index 000000000..198fef3ac --- /dev/null +++ b/code/MDCNormalTable.h @@ -0,0 +1,299 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + +#if (!defined MDC_NORMAL_TABLE_INCLUDED) +#define MDC_NORMAL_TABLE_INCLUDED + +/* mdc decoding normal table */ +float mdcNormals[ 256 ][ 3 ] = +{ + { 1.000000f, 0.000000f, 0.000000f }, + { 0.980785f, 0.195090f, 0.000000f }, + { 0.923880f, 0.382683f, 0.000000f }, + { 0.831470f, 0.555570f, 0.000000f }, + { 0.707107f, 0.707107f, 0.000000f }, + { 0.555570f, 0.831470f, 0.000000f }, + { 0.382683f, 0.923880f, 0.000000f }, + { 0.195090f, 0.980785f, 0.000000f }, + { -0.000000f, 1.000000f, 0.000000f }, + { -0.195090f, 0.980785f, 0.000000f }, + { -0.382683f, 0.923880f, 0.000000f }, + { -0.555570f, 0.831470f, 0.000000f }, + { -0.707107f, 0.707107f, 0.000000f }, + { -0.831470f, 0.555570f, 0.000000f }, + { -0.923880f, 0.382683f, 0.000000f }, + { -0.980785f, 0.195090f, 0.000000f }, + { -1.000000f, -0.000000f, 0.000000f }, + { -0.980785f, -0.195090f, 0.000000f }, + { -0.923880f, -0.382683f, 0.000000f }, + { -0.831470f, -0.555570f, 0.000000f }, + { -0.707107f, -0.707107f, 0.000000f }, + { -0.555570f, -0.831469f, 0.000000f }, + { -0.382684f, -0.923880f, 0.000000f }, + { -0.195090f, -0.980785f, 0.000000f }, + { 0.000000f, -1.000000f, 0.000000f }, + { 0.195090f, -0.980785f, 0.000000f }, + { 0.382684f, -0.923879f, 0.000000f }, + { 0.555570f, -0.831470f, 0.000000f }, + { 0.707107f, -0.707107f, 0.000000f }, + { 0.831470f, -0.555570f, 0.000000f }, + { 0.923880f, -0.382683f, 0.000000f }, + { 0.980785f, -0.195090f, 0.000000f }, + { 0.980785f, 0.000000f, -0.195090f }, + { 0.956195f, 0.218245f, -0.195090f }, + { 0.883657f, 0.425547f, -0.195090f }, + { 0.766809f, 0.611510f, -0.195090f }, + { 0.611510f, 0.766809f, -0.195090f }, + { 0.425547f, 0.883657f, -0.195090f }, + { 0.218245f, 0.956195f, -0.195090f }, + { -0.000000f, 0.980785f, -0.195090f }, + { -0.218245f, 0.956195f, -0.195090f }, + { -0.425547f, 0.883657f, -0.195090f }, + { -0.611510f, 0.766809f, -0.195090f }, + { -0.766809f, 0.611510f, -0.195090f }, + { -0.883657f, 0.425547f, -0.195090f }, + { -0.956195f, 0.218245f, -0.195090f }, + { -0.980785f, -0.000000f, -0.195090f }, + { -0.956195f, -0.218245f, -0.195090f }, + { -0.883657f, -0.425547f, -0.195090f }, + { -0.766809f, -0.611510f, -0.195090f }, + { -0.611510f, -0.766809f, -0.195090f }, + { -0.425547f, -0.883657f, -0.195090f }, + { -0.218245f, -0.956195f, -0.195090f }, + { 0.000000f, -0.980785f, -0.195090f }, + { 0.218245f, -0.956195f, -0.195090f }, + { 0.425547f, -0.883657f, -0.195090f }, + { 0.611510f, -0.766809f, -0.195090f }, + { 0.766809f, -0.611510f, -0.195090f }, + { 0.883657f, -0.425547f, -0.195090f }, + { 0.956195f, -0.218245f, -0.195090f }, + { 0.923880f, 0.000000f, -0.382683f }, + { 0.892399f, 0.239118f, -0.382683f }, + { 0.800103f, 0.461940f, -0.382683f }, + { 0.653281f, 0.653281f, -0.382683f }, + { 0.461940f, 0.800103f, -0.382683f }, + { 0.239118f, 0.892399f, -0.382683f }, + { -0.000000f, 0.923880f, -0.382683f }, + { -0.239118f, 0.892399f, -0.382683f }, + { -0.461940f, 0.800103f, -0.382683f }, + { -0.653281f, 0.653281f, -0.382683f }, + { -0.800103f, 0.461940f, -0.382683f }, + { -0.892399f, 0.239118f, -0.382683f }, + { -0.923880f, -0.000000f, -0.382683f }, + { -0.892399f, -0.239118f, -0.382683f }, + { -0.800103f, -0.461940f, -0.382683f }, + { -0.653282f, -0.653281f, -0.382683f }, + { -0.461940f, -0.800103f, -0.382683f }, + { -0.239118f, -0.892399f, -0.382683f }, + { 0.000000f, -0.923880f, -0.382683f }, + { 0.239118f, -0.892399f, -0.382683f }, + { 0.461940f, -0.800103f, -0.382683f }, + { 0.653281f, -0.653282f, -0.382683f }, + { 0.800103f, -0.461940f, -0.382683f }, + { 0.892399f, -0.239117f, -0.382683f }, + { 0.831470f, 0.000000f, -0.555570f }, + { 0.790775f, 0.256938f, -0.555570f }, + { 0.672673f, 0.488726f, -0.555570f }, + { 0.488726f, 0.672673f, -0.555570f }, + { 0.256938f, 0.790775f, -0.555570f }, + { -0.000000f, 0.831470f, -0.555570f }, + { -0.256938f, 0.790775f, -0.555570f }, + { -0.488726f, 0.672673f, -0.555570f }, + { -0.672673f, 0.488726f, -0.555570f }, + { -0.790775f, 0.256938f, -0.555570f }, + { -0.831470f, -0.000000f, -0.555570f }, + { -0.790775f, -0.256938f, -0.555570f }, + { -0.672673f, -0.488726f, -0.555570f }, + { -0.488725f, -0.672673f, -0.555570f }, + { -0.256938f, -0.790775f, -0.555570f }, + { 0.000000f, -0.831470f, -0.555570f }, + { 0.256938f, -0.790775f, -0.555570f }, + { 0.488725f, -0.672673f, -0.555570f }, + { 0.672673f, -0.488726f, -0.555570f }, + { 0.790775f, -0.256938f, -0.555570f }, + { 0.707107f, 0.000000f, -0.707107f }, + { 0.653281f, 0.270598f, -0.707107f }, + { 0.500000f, 0.500000f, -0.707107f }, + { 0.270598f, 0.653281f, -0.707107f }, + { -0.000000f, 0.707107f, -0.707107f }, + { -0.270598f, 0.653282f, -0.707107f }, + { -0.500000f, 0.500000f, -0.707107f }, + { -0.653281f, 0.270598f, -0.707107f }, + { -0.707107f, -0.000000f, -0.707107f }, + { -0.653281f, -0.270598f, -0.707107f }, + { -0.500000f, -0.500000f, -0.707107f }, + { -0.270598f, -0.653281f, -0.707107f }, + { 0.000000f, -0.707107f, -0.707107f }, + { 0.270598f, -0.653281f, -0.707107f }, + { 0.500000f, -0.500000f, -0.707107f }, + { 0.653282f, -0.270598f, -0.707107f }, + { 0.555570f, 0.000000f, -0.831470f }, + { 0.481138f, 0.277785f, -0.831470f }, + { 0.277785f, 0.481138f, -0.831470f }, + { -0.000000f, 0.555570f, -0.831470f }, + { -0.277785f, 0.481138f, -0.831470f }, + { -0.481138f, 0.277785f, -0.831470f }, + { -0.555570f, -0.000000f, -0.831470f }, + { -0.481138f, -0.277785f, -0.831470f }, + { -0.277785f, -0.481138f, -0.831470f }, + { 0.000000f, -0.555570f, -0.831470f }, + { 0.277785f, -0.481138f, -0.831470f }, + { 0.481138f, -0.277785f, -0.831470f }, + { 0.382683f, 0.000000f, -0.923880f }, + { 0.270598f, 0.270598f, -0.923880f }, + { -0.000000f, 0.382683f, -0.923880f }, + { -0.270598f, 0.270598f, -0.923880f }, + { -0.382683f, -0.000000f, -0.923880f }, + { -0.270598f, -0.270598f, -0.923880f }, + { 0.000000f, -0.382683f, -0.923880f }, + { 0.270598f, -0.270598f, -0.923880f }, + { 0.195090f, 0.000000f, -0.980785f }, + { -0.000000f, 0.195090f, -0.980785f }, + { -0.195090f, -0.000000f, -0.980785f }, + { 0.000000f, -0.195090f, -0.980785f }, + { 0.980785f, 0.000000f, 0.195090f }, + { 0.956195f, 0.218245f, 0.195090f }, + { 0.883657f, 0.425547f, 0.195090f }, + { 0.766809f, 0.611510f, 0.195090f }, + { 0.611510f, 0.766809f, 0.195090f }, + { 0.425547f, 0.883657f, 0.195090f }, + { 0.218245f, 0.956195f, 0.195090f }, + { -0.000000f, 0.980785f, 0.195090f }, + { -0.218245f, 0.956195f, 0.195090f }, + { -0.425547f, 0.883657f, 0.195090f }, + { -0.611510f, 0.766809f, 0.195090f }, + { -0.766809f, 0.611510f, 0.195090f }, + { -0.883657f, 0.425547f, 0.195090f }, + { -0.956195f, 0.218245f, 0.195090f }, + { -0.980785f, -0.000000f, 0.195090f }, + { -0.956195f, -0.218245f, 0.195090f }, + { -0.883657f, -0.425547f, 0.195090f }, + { -0.766809f, -0.611510f, 0.195090f }, + { -0.611510f, -0.766809f, 0.195090f }, + { -0.425547f, -0.883657f, 0.195090f }, + { -0.218245f, -0.956195f, 0.195090f }, + { 0.000000f, -0.980785f, 0.195090f }, + { 0.218245f, -0.956195f, 0.195090f }, + { 0.425547f, -0.883657f, 0.195090f }, + { 0.611510f, -0.766809f, 0.195090f }, + { 0.766809f, -0.611510f, 0.195090f }, + { 0.883657f, -0.425547f, 0.195090f }, + { 0.956195f, -0.218245f, 0.195090f }, + { 0.923880f, 0.000000f, 0.382683f }, + { 0.892399f, 0.239118f, 0.382683f }, + { 0.800103f, 0.461940f, 0.382683f }, + { 0.653281f, 0.653281f, 0.382683f }, + { 0.461940f, 0.800103f, 0.382683f }, + { 0.239118f, 0.892399f, 0.382683f }, + { -0.000000f, 0.923880f, 0.382683f }, + { -0.239118f, 0.892399f, 0.382683f }, + { -0.461940f, 0.800103f, 0.382683f }, + { -0.653281f, 0.653281f, 0.382683f }, + { -0.800103f, 0.461940f, 0.382683f }, + { -0.892399f, 0.239118f, 0.382683f }, + { -0.923880f, -0.000000f, 0.382683f }, + { -0.892399f, -0.239118f, 0.382683f }, + { -0.800103f, -0.461940f, 0.382683f }, + { -0.653282f, -0.653281f, 0.382683f }, + { -0.461940f, -0.800103f, 0.382683f }, + { -0.239118f, -0.892399f, 0.382683f }, + { 0.000000f, -0.923880f, 0.382683f }, + { 0.239118f, -0.892399f, 0.382683f }, + { 0.461940f, -0.800103f, 0.382683f }, + { 0.653281f, -0.653282f, 0.382683f }, + { 0.800103f, -0.461940f, 0.382683f }, + { 0.892399f, -0.239117f, 0.382683f }, + { 0.831470f, 0.000000f, 0.555570f }, + { 0.790775f, 0.256938f, 0.555570f }, + { 0.672673f, 0.488726f, 0.555570f }, + { 0.488726f, 0.672673f, 0.555570f }, + { 0.256938f, 0.790775f, 0.555570f }, + { -0.000000f, 0.831470f, 0.555570f }, + { -0.256938f, 0.790775f, 0.555570f }, + { -0.488726f, 0.672673f, 0.555570f }, + { -0.672673f, 0.488726f, 0.555570f }, + { -0.790775f, 0.256938f, 0.555570f }, + { -0.831470f, -0.000000f, 0.555570f }, + { -0.790775f, -0.256938f, 0.555570f }, + { -0.672673f, -0.488726f, 0.555570f }, + { -0.488725f, -0.672673f, 0.555570f }, + { -0.256938f, -0.790775f, 0.555570f }, + { 0.000000f, -0.831470f, 0.555570f }, + { 0.256938f, -0.790775f, 0.555570f }, + { 0.488725f, -0.672673f, 0.555570f }, + { 0.672673f, -0.488726f, 0.555570f }, + { 0.790775f, -0.256938f, 0.555570f }, + { 0.707107f, 0.000000f, 0.707107f }, + { 0.653281f, 0.270598f, 0.707107f }, + { 0.500000f, 0.500000f, 0.707107f }, + { 0.270598f, 0.653281f, 0.707107f }, + { -0.000000f, 0.707107f, 0.707107f }, + { -0.270598f, 0.653282f, 0.707107f }, + { -0.500000f, 0.500000f, 0.707107f }, + { -0.653281f, 0.270598f, 0.707107f }, + { -0.707107f, -0.000000f, 0.707107f }, + { -0.653281f, -0.270598f, 0.707107f }, + { -0.500000f, -0.500000f, 0.707107f }, + { -0.270598f, -0.653281f, 0.707107f }, + { 0.000000f, -0.707107f, 0.707107f }, + { 0.270598f, -0.653281f, 0.707107f }, + { 0.500000f, -0.500000f, 0.707107f }, + { 0.653282f, -0.270598f, 0.707107f }, + { 0.555570f, 0.000000f, 0.831470f }, + { 0.481138f, 0.277785f, 0.831470f }, + { 0.277785f, 0.481138f, 0.831470f }, + { -0.000000f, 0.555570f, 0.831470f }, + { -0.277785f, 0.481138f, 0.831470f }, + { -0.481138f, 0.277785f, 0.831470f }, + { -0.555570f, -0.000000f, 0.831470f }, + { -0.481138f, -0.277785f, 0.831470f }, + { -0.277785f, -0.481138f, 0.831470f }, + { 0.000000f, -0.555570f, 0.831470f }, + { 0.277785f, -0.481138f, 0.831470f }, + { 0.481138f, -0.277785f, 0.831470f }, + { 0.382683f, 0.000000f, 0.923880f }, + { 0.270598f, 0.270598f, 0.923880f }, + { -0.000000f, 0.382683f, 0.923880f }, + { -0.270598f, 0.270598f, 0.923880f }, + { -0.382683f, -0.000000f, 0.923880f }, + { -0.270598f, -0.270598f, 0.923880f }, + { 0.000000f, -0.382683f, 0.923880f }, + { 0.270598f, -0.270598f, 0.923880f }, + { 0.195090f, 0.000000f, 0.980785f }, + { -0.000000f, 0.195090f, 0.980785f }, + { -0.195090f, -0.000000f, 0.980785f }, + { 0.000000f, -0.195090f, 0.980785f } +}; + +#endif // !! MDC_NORMAL_TABLE_INCLUDED \ No newline at end of file diff --git a/code/MDLLoader.cpp b/code/MDLLoader.cpp index fdf779abf..d68136147 100644 --- a/code/MDLLoader.cpp +++ b/code/MDLLoader.cpp @@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "MDLDefaultColorMap.h" #include "MD2FileData.h" #include "qnan.h" +#include "ByteSwap.h" // public ASSIMP headers #include "../include/DefaultLogger.h" @@ -62,8 +63,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; -extern float g_avNormals[162][3]; - // ------------------------------------------------------------------------------------------------ // macros used by the MDL7 loader @@ -81,7 +80,6 @@ extern float g_avNormals[162][3]; _AI_MDL7_ACCESS(_data,_index,_limit,MDL::Vertex_MDL7) #endif - // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer MDLImporter::MDLImporter() @@ -116,36 +114,34 @@ bool MDLImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const return true; } // ------------------------------------------------------------------------------------------------ +// Setup configuration properties +void MDLImporter::SetupProperties(const Importer* pImp) +{ + // The AI_CONFIG_IMPORT_MDL_KEYFRAME option overrides the + // AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option. + if(0xffffffff == (this->configFrameID = pImp->GetProperty( + AI_CONFIG_IMPORT_MDL_KEYFRAME,0xffffffff))) + { + this->configFrameID = pImp->GetProperty(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0); + } +} +// ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. -void MDLImporter::InternReadFile( - const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) +void MDLImporter::InternReadFile( const std::string& pFile, + aiScene* pScene, IOSystem* pIOHandler) { boost::scoped_ptr file( pIOHandler->Open( pFile)); // Check whether we can read from the file if( file.get() == NULL) - { throw new ImportErrorException( "Failed to open MDL file " + pFile + "."); - } - // The AI_CONFIG_IMPORT_MDL_KEYFRAME option overrides the - // AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option. -#if 0 - if(0xffffffff == (this->configFrameID = this->mImporter->GetProperty( - AI_CONFIG_IMPORT_MDL_KEYFRAME,0xffffffff))) - { - this->configFrameID = this->mImporter->GetProperty( - AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0); - } -#endif // this should work for all other types of MDL files, too ... // the quake header is one of the smallest, afaik this->iFileSize = (unsigned int)file->FileSize(); if( this->iFileSize < sizeof(MDL::Header)) - { throw new ImportErrorException( "MDL File is too small."); - } // allocate storage and copy the contents of the file to a memory buffer this->pScene = pScene; @@ -162,89 +158,93 @@ void MDLImporter::InternReadFile( // 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) - { - DefaultLogger::get()->debug("MDL subtype: Quake 1, magic word is IDPO"); - this->iGSFileVersion = 0; - this->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) - { - DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A2, magic word is MDL2"); - this->iGSFileVersion = 2; - this->InternReadFile_Quake1(); - } - // GameStudio A4 MDL3 format - 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"); - this->iGSFileVersion = 3; - this->InternReadFile_3DGS_MDL345(); - } - // GameStudio A5+ MDL4 format - 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"); - this->iGSFileVersion = 4; - this->InternReadFile_3DGS_MDL345(); - } - // GameStudio A5+ MDL5 format - 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"); - this->iGSFileVersion = 5; - this->InternReadFile_3DGS_MDL345(); - } - // GameStudio A6+ MDL6 format (not sure whether it is really existing ... ) - else if (AI_MDL_MAGIC_NUMBER_BE_GS6 == iMagicWord || - AI_MDL_MAGIC_NUMBER_LE_GS6 == iMagicWord) - { - DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A6, magic word is MDL6"); - this->iGSFileVersion = 6; - this->InternReadFile_3DGS_MDL345(); - } - // GameStudio A7 MDL7 format - 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"); - this->iGSFileVersion = 7; - this->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) - { - DefaultLogger::get()->debug("MDL subtype: CS:S\\HLČ, magic word is IDST/IDSQ"); - this->iGSFileVersion = 0; - this->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'; + // Original Quake1 format + if (AI_MDL_MAGIC_NUMBER_BE == iMagicWord || + AI_MDL_MAGIC_NUMBER_LE == iMagicWord) + { + DefaultLogger::get()->debug("MDL subtype: Quake 1, magic word is IDPO"); + this->iGSFileVersion = 0; + this->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) + { + DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A2, magic word is MDL2"); + this->iGSFileVersion = 2; + this->InternReadFile_Quake1(); + } + // GameStudio A4 MDL3 format + 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"); + this->iGSFileVersion = 3; + this->InternReadFile_3DGS_MDL345(); + } + // GameStudio A5+ MDL4 format + 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"); + this->iGSFileVersion = 4; + this->InternReadFile_3DGS_MDL345(); + } + // GameStudio A5+ MDL5 format + 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"); + this->iGSFileVersion = 5; + this->InternReadFile_3DGS_MDL345(); + } + // GameStudio A6+ MDL6 format (not sure whether it is really existing ... ) + else if (AI_MDL_MAGIC_NUMBER_BE_GS6 == iMagicWord || + AI_MDL_MAGIC_NUMBER_LE_GS6 == iMagicWord) + { + DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A6, magic word is MDL6"); + this->iGSFileVersion = 6; + this->InternReadFile_3DGS_MDL345(); + } + // GameStudio A7 MDL7 format + 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"); + this->iGSFileVersion = 7; + this->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) + { + DefaultLogger::get()->debug("MDL subtype: CS:S\\HLČ, magic word is IDST/IDSQ"); + this->iGSFileVersion = 0; + this->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 - throw new ImportErrorException( "Unknown MDL subformat " + pFile + - ". Magic word (" + szBuffer + ") is not known"); - } + // we're definitely unable to load this file + throw new ImportErrorException( "Unknown MDL subformat " + pFile + + ". Magic word (" + szBuffer + ") is not known"); + } - } catch (ImportErrorException* ex) { + } + catch (ImportErrorException* ex) { delete[] this->mBuffer; + AI_DEBUG_INVALIDATE_PTR(this->mBuffer); + AI_DEBUG_INVALIDATE_PTR(this->pIOHandler); + AI_DEBUG_INVALIDATE_PTR(this->pScene); throw ex; } @@ -253,7 +253,6 @@ void MDLImporter::InternReadFile( AI_DEBUG_INVALIDATE_PTR(this->mBuffer); AI_DEBUG_INVALIDATE_PTR(this->pIOHandler); AI_DEBUG_INVALIDATE_PTR(this->pScene); - return; } // ------------------------------------------------------------------------------------------------ void MDLImporter::SizeCheck(const void* szPos) @@ -279,12 +278,7 @@ void MDLImporter::SizeCheck(const void* szPos, const char* szFile, unsigned int if (szFilePtr)++szFilePtr; char szBuffer[1024]; -#if _MSC_VER >= 1400 - ::sprintf_s(szBuffer, -#else - ::sprintf(szBuffer, -#endif - "Invalid MDL file. The file is too small " + ::sprintf(szBuffer,"Invalid MDL file. The file is too small " "or contains invalid data (File: %s Line: %i)",szFilePtr,iLine); throw new ImportErrorException(szBuffer); @@ -295,56 +289,67 @@ void MDLImporter::ValidateHeader_Quake1(const MDL::Header* pcHeader) { // some values may not be NULL if (!pcHeader->num_frames) - { throw new ImportErrorException( "[Quake 1 MDL] There are no frames in the file"); - } + if (!pcHeader->num_verts) - { throw new ImportErrorException( "[Quake 1 MDL] There are no vertices in the file"); - } + if (!pcHeader->num_tris) - { throw new ImportErrorException( "[Quake 1 MDL] There are no triangles in the file"); - } // check whether the maxima are exceeded ...however, this applies for Quake 1 MDLs only if (!this->iGSFileVersion) { if (pcHeader->num_verts > AI_MDL_MAX_VERTS) - { DefaultLogger::get()->warn("Quake 1 MDL model has more than AI_MDL_MAX_VERTS vertices"); - } + if (pcHeader->num_tris > AI_MDL_MAX_TRIANGLES) - { DefaultLogger::get()->warn("Quake 1 MDL model has more than AI_MDL_MAX_TRIANGLES triangles"); - } + if (pcHeader->num_frames > AI_MDL_MAX_FRAMES) - { DefaultLogger::get()->warn("Quake 1 MDL model has more than AI_MDL_MAX_FRAMES frames"); - } + // (this does not apply for 3DGS MDLs) if (!this->iGSFileVersion && pcHeader->version != AI_MDL_VERSION) - { DefaultLogger::get()->warn("Quake 1 MDL model has an unknown version: AI_MDL_VERSION (=6) is " "the expected file format version"); - } - - if (pcHeader->num_skins) - { - if(!pcHeader->skinwidth || !pcHeader->skinheight) - { - DefaultLogger::get()->warn("Skin width or height are 0. Division through " - "zero would occur ..."); - } - } + if(pcHeader->num_skins && (!pcHeader->skinwidth || !pcHeader->skinheight)) + DefaultLogger::get()->warn("Skin width or height are 0"); } } +#ifdef AI_BUILD_BIG_ENDIAN +// ------------------------------------------------------------------------------------------------ +void FlipQuakeHeader(BE_NCONST MDL::Header* pcHeader) +{ + ByteSwap::Swap4(& pcHeader->ident); + ByteSwap::Swap4(& pcHeader->version); + ByteSwap::Swap4(& pcHeader->boundingradius); + ByteSwap::Swap4(& pcHeader->flags); + ByteSwap::Swap4(& pcHeader->num_frames); + ByteSwap::Swap4(& pcHeader->num_skins); + ByteSwap::Swap4(& pcHeader->num_tris); + ByteSwap::Swap4(& pcHeader->num_verts); + for (unsigned int i = 0; i < 3;++i) + { + ByteSwap::Swap4(& pcHeader->scale[i]); + ByteSwap::Swap4(& pcHeader->translate[i]); + } + ByteSwap::Swap4(& pcHeader->size); + ByteSwap::Swap4(& pcHeader->skinheight); + ByteSwap::Swap4(& pcHeader->skin); +} +#endif // ------------------------------------------------------------------------------------------------ void MDLImporter::InternReadFile_Quake1( ) { ai_assert(NULL != pScene); - const MDL::Header* pcHeader = (const MDL::Header*)this->mBuffer; + BE_NCONST MDL::Header* pcHeader = (BE_NCONST MDL::Header*)this->mBuffer; + +#ifdef AI_BUILD_BIG_ENDIAN + FlipQuakeHeader(pcHeader); +#endif + ValidateHeader_Quake1(pcHeader); // current cursor position in the file @@ -353,13 +358,16 @@ void MDLImporter::InternReadFile_Quake1( ) // need to read all textures for (unsigned int i = 0; i < (unsigned int)pcHeader->num_skins;++i) { - union{const MDL::Skin* pcSkin;const MDL::GroupSkin* pcGroupSkin;}; - pcSkin = (const MDL::Skin*)szCurrent; + union{BE_NCONST MDL::Skin* pcSkin;BE_NCONST MDL::GroupSkin* pcGroupSkin;}; + pcSkin = (BE_NCONST MDL::Skin*)szCurrent; + AI_SWAP4( pcSkin->group ); // Quake 1 groupskins if (1 == pcSkin->group) { + AI_SWAP4( pcGroupSkin->nb ); + // need to skip multiple images const unsigned int iNumImages = (unsigned int)pcGroupSkin->nb; szCurrent += sizeof(uint32_t) * 2; @@ -413,6 +421,25 @@ void MDLImporter::InternReadFile_Quake1( ) VALIDATE_FILE_SIZE((const unsigned char*)(pcVertices + pcHeader->num_verts)); +#ifdef AI_BUILD_BIG_ENDIAN + + for (unsigned int i = 0; inum_verts;++i) + { + AI_SWAP4( pcTexCoords[i].onseam ); + AI_SWAP4( pcTexCoords[i].s ); + AI_SWAP4( pcTexCoords[i].t ); + } + + for (unsigned int i = 0; inum_tris;++i) + { + AI_SWAP4( pcTriangles[i].facesfront); + AI_SWAP4( pcTriangles[i].vertex[0]); + AI_SWAP4( pcTriangles[i].vertex[1]); + AI_SWAP4( pcTriangles[i].vertex[2]); + } + +#endif + // setup materials this->SetupMaterialProperties_3DGS_MDL5_Quake1(); @@ -453,7 +480,6 @@ void MDLImporter::InternReadFile_Quake1( ) if (iIndex >= (unsigned int)pcHeader->num_verts) { iIndex = pcHeader->num_verts-1; - DefaultLogger::get()->warn("Index overflow in Q1-MDL vertex list."); } @@ -461,16 +487,16 @@ void MDLImporter::InternReadFile_Quake1( ) vec.x = (float)pcVertices[iIndex].v[0] * pcHeader->scale[0]; vec.x += pcHeader->translate[0]; - // (flip z and y component) - vec.z = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1]; - vec.z += pcHeader->translate[1]; + vec.y = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1]; + vec.y += pcHeader->translate[1]; + vec.y *= -1.0f; - vec.y = (float)pcVertices[iIndex].v[2] * pcHeader->scale[2]; - vec.y += pcHeader->translate[2]; + 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]); - std::swap ( pcMesh->mNormals[iCurrent].y,pcMesh->mNormals[iCurrent].z ); + pcMesh->mNormals[iCurrent].y *= -1.0f; // read texture coordinates float s = (float)pcTexCoords[iIndex].s; @@ -546,6 +572,9 @@ void MDLImporter::InternReadFile_3DGS_MDL345( ) // the header of MDL 3/4/5 is nearly identical to the original Quake1 header const MDL::Header* pcHeader = (const MDL::Header*)this->mBuffer; +#ifdef AI_BUILD_BIG_ENDIAN + FlipQuakeHeader(pcHeader); +#endif this->ValidateHeader_Quake1(pcHeader); // current cursor position in the file @@ -584,6 +613,26 @@ void MDLImporter::InternReadFile_3DGS_MDL345( ) const MDL::Triangle_MDL3* pcTriangles = (const MDL::Triangle_MDL3*)szCurrent; szCurrent += sizeof(MDL::Triangle_MDL3) * pcHeader->num_tris; +#ifdef AI_BUILD_BIG_ENDIAN + + for (unsigned int i = 0; isynctype;++i) + { + AI_SWAP2( pcTexCoords[i].u ); + AI_SWAP2( pcTexCoords[i].v ); + } + + for (unsigned int i = 0; inum_tris;++i) + { + AI_SWAP4( pcTriangles[i].index_xyz[0]); + AI_SWAP4( pcTriangles[i].index_xyz[1]); + AI_SWAP4( pcTriangles[i].index_xyz[2]); + AI_SWAP4( pcTriangles[i].index_uv[0]); + AI_SWAP4( pcTriangles[i].index_uv[1]); + AI_SWAP4( pcTriangles[i].index_uv[2]); + } + +#endif + VALIDATE_FILE_SIZE(szCurrent); // setup materials @@ -620,15 +669,15 @@ void MDLImporter::InternReadFile_3DGS_MDL345( ) const MDL::Frame* pcFrames = (const MDL::Frame*)szCurrent; // byte packed vertices + // BIG TODO: these two snippets are nearly totally identical ... // *********************************************************************** if (0 == pcFrames->type || 3 >= this->iGSFileVersion) { - const MDL::SimpleFrame* pcFirstFrame = - (const MDL::SimpleFrame*)(szCurrent + sizeof(uint32_t)); + const MDL::SimpleFrame* pcFirstFrame = (const MDL::SimpleFrame*)(szCurrent + sizeof(uint32_t)); // get a pointer to the vertices - const MDL::Vertex* pcVertices = (const MDL::Vertex*) ( - (pcFirstFrame->name) + sizeof(pcFirstFrame->name)); + const MDL::Vertex* pcVertices = (const MDL::Vertex*) ((pcFirstFrame->name) + + sizeof(pcFirstFrame->name)); VALIDATE_FILE_SIZE(pcVertices + pcHeader->num_verts); @@ -654,16 +703,16 @@ void MDLImporter::InternReadFile_3DGS_MDL345( ) vec.x = (float)pcVertices[iIndex].v[0] * pcHeader->scale[0]; vec.x += pcHeader->translate[0]; - // (flip z and y component) - vec.z = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1]; - vec.z += pcHeader->translate[1]; + vec.y = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1]; + vec.y += pcHeader->translate[1]; + vec.y *= -1.0f; - vec.y = (float)pcVertices[iIndex].v[2] * pcHeader->scale[2]; - vec.y += pcHeader->translate[2]; + 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]); - std::swap ( pcMesh->mNormals[iCurrent].y,pcMesh->mNormals[iCurrent].z ); + pcMesh->mNormals[iCurrent].y *= -1.0f; // read texture coordinates if (pcHeader->synctype) @@ -684,12 +733,11 @@ void MDLImporter::InternReadFile_3DGS_MDL345( ) 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)); + 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) + sizeof(pcFirstFrame->name)); + const MDL::Vertex_MDL4* pcVertices = (const MDL::Vertex_MDL4*) ((pcFirstFrame->name) + + sizeof(pcFirstFrame->name)); VALIDATE_FILE_SIZE(pcVertices + pcHeader->num_verts); @@ -715,16 +763,16 @@ void MDLImporter::InternReadFile_3DGS_MDL345( ) vec.x = (float)pcVertices[iIndex].v[0] * pcHeader->scale[0]; vec.x += pcHeader->translate[0]; - // (flip z and y component) - vec.z = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1]; - vec.z += pcHeader->translate[1]; + vec.y = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1]; + vec.y += pcHeader->translate[1]; + vec.y *= -1.0f; - vec.y = (float)pcVertices[iIndex].v[2] * pcHeader->scale[2]; - vec.y += pcHeader->translate[2]; + 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]); - std::swap ( pcMesh->mNormals[iCurrent].y,pcMesh->mNormals[iCurrent].z ); + pcMesh->mNormals[iCurrent].y *= -1.0f; // read texture coordinates if (pcHeader->synctype) @@ -920,14 +968,9 @@ void MDLImporter::CalcAbsBoneMatrices_3DGS_MDL7(const MDL::Bone_MDL7* pcBones, if (AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_NOT_THERE == pcHeader->bone_stc_size) { - // no real name for our poor bone :-( -# if (_MSC_VER >= 1400) - pcOutBone->mName.length = ::sprintf_s(pcOutBone->mName.data, - MAXLEN,"UnnamedBone_%i",iBone); -# else - pcOutBone->mName.length = ::sprintf(pcOutBone->mName.data, - "UnnamedBone_%i",iBone); -# endif + // no real name for our poor bone is specified :-( + pcOutBone->mName.length = ::sprintf(pcOutBone->mName.data, + "UnnamedBone_%i",iBone); } else { @@ -1012,17 +1055,15 @@ void MDLImporter::ReadFaces_3DGS_MDL7( // write the output face index groupData.pcFaces[iTriangle].mIndices[2-c] = iOutIndex; - // swap z and y axis aiVector3D& vPosition = groupData.vPositions[ iOutIndex ]; vPosition.x = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .x; - vPosition.z = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .y; - vPosition.y = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .z; + 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; // 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; - } + 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) @@ -1030,8 +1071,8 @@ void MDLImporter::ReadFaces_3DGS_MDL7( // 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]; - vNormal.z = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[1]; - vNormal.y = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[2]; + vNormal.y = -1.0f*_AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[1]; + vNormal.z = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[2]; } else if (AI_MDL7_FRAMEVERTEX120503_STCSIZE <= pcHeader->mainvertex_stc_size) { @@ -1039,8 +1080,7 @@ void MDLImporter::ReadFaces_3DGS_MDL7( aiVector3D& vNormal = groupData.vNormals[ iOutIndex ]; MD2::LookupNormalIndex(_AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex, pcHeader->mainvertex_stc_size) .norm162index,vNormal); - - std::swap(groupData.vNormals[iOutIndex].z,groupData.vNormals[iOutIndex].y); + vNormal.y *= -1.0f; } // validate and process the first uv coordinate set // ************************************************************* @@ -1063,9 +1103,7 @@ void MDLImporter::ReadFaces_3DGS_MDL7( } // assign the material index, but only if it is existing if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV_WITH_MATINDEX) - { groupData.pcFaces[iTriangle].iMatIndex[0] = pcGroupTris->skinsets[0].material; - } } // validate and process the second uv coordinate set // ************************************************************* @@ -1090,14 +1128,11 @@ void MDLImporter::ReadFaces_3DGS_MDL7( // 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; @@ -1144,9 +1179,7 @@ bool MDLImporter::ProcessFrames_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInf // our output frame? if (configFrameID == iFrame) { - const MDL::Vertex_MDL7* pcFrameVertices = (const MDL::Vertex_MDL7*) - (szCurrent + pcHeader->framevertex_stc_size); - + const MDL::Vertex_MDL7* pcFrameVertices = (const 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 @@ -1157,37 +1190,33 @@ bool MDLImporter::ProcessFrames_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInf if (iIndex >= groupInfo.pcGroup->numverts) { - DefaultLogger::get()->warn("Invalid vertex index in frame vertex section. " - "Skipping this frame vertex"); + DefaultLogger::get()->warn("Invalid vertex index in frame vertex section"); continue; } aiVector3D vPosition,vNormal; vPosition.x = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .x; - vPosition.z = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .y; - vPosition.y = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .z; + vPosition.y = -1.0f*_AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .y; + vPosition.z = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .z; // now read the normal vector 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]; - vNormal.z = _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[2]; + vNormal.y = -1.0f* _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .norm[1]; + vNormal.z = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .norm[2]; } 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); - - std::swap(vNormal.z,vNormal.y); + vNormal.y *= -1.0f; } // FIXME: O(n^2) at the moment ... - // shouldn't be too worse, frame vertices aren't required more - // than once a century ... const MDL::Triangle_MDL7* pcGroupTris = groupInfo.pcGroupTris; unsigned int iOutIndex = 0; for (unsigned int iTriangle = 0; iTriangle < (unsigned int)groupInfo.pcGroup->numtris; ++iTriangle) @@ -1204,16 +1233,13 @@ bool MDLImporter::ProcessFrames_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInf } } // get the next triangle in the list - pcGroupTris = (const MDL::Triangle_MDL7*)((const char*)pcGroupTris + - pcHeader->triangle_stc_size); + pcGroupTris = (const MDL::Triangle_MDL7*)((const char*) + pcGroupTris + pcHeader->triangle_stc_size); } } } // parse bone trafo matrix keys (only if there are bones ...) - if (shared.apcOutBones) - { - this->ParseBoneTrafoKeys_3DGS_MDL7(groupInfo,frame,shared); - } + if (shared.apcOutBones)this->ParseBoneTrafoKeys_3DGS_MDL7(groupInfo,frame,shared); szCurrent += iAdd; } *szCurrentOut = szCurrent; @@ -1371,7 +1397,6 @@ void MDLImporter::InternReadFile_3DGS_MDL7( ) // load all bones (they are shared by all groups, so // we'll need to add them to all groups/meshes later) // apcBonesOut is a list of all bones or NULL if they could not been loaded - // TODO (aramis): Make apcBonesOut an MDL::IntBone_MDL7* szCurrent += pcHeader->bones_num * pcHeader->bone_stc_size; sharedData.apcOutBones = this->LoadBones_3DGS_MDL7(); @@ -1493,19 +1518,13 @@ void MDLImporter::InternReadFile_3DGS_MDL7( ) if (!splittedGroupData.aiSplit[qq]->empty()) sharedData.abNeedMaterials[qq] = true; } - - // now generate output meshes - this->GenerateOutputMeshes_3DGS_MDL7(groupData, - splittedGroupData); } else DefaultLogger::get()->warn("[3DGS MDL7] Mesh group consists of 0 " "vertices or faces. It will be skipped."); - // process all frames - if(!ProcessFrames_3DGS_MDL7(groupInfo,groupData, sharedData,szCurrent,&szCurrent)) - { - break; - } + // process all frames and generate output meshes + this->ProcessFrames_3DGS_MDL7(groupInfo,groupData, sharedData,szCurrent,&szCurrent); + this->GenerateOutputMeshes_3DGS_MDL7(groupData,splittedGroupData); } // generate a nodegraph and subnodes for each group @@ -1545,16 +1564,9 @@ void MDLImporter::InternReadFile_3DGS_MDL7( ) // setup the name of the node char* const szBuffer = &aszGroupNameBuffer[i*AI_MDL7_MAX_GROUPNAMESIZE]; - if ('\0' == *szBuffer) - { -#if _MSC_VER >= 1400 - ::sprintf_s(szBuffer,AI_MDL7_MAX_GROUPNAMESIZE,"Group_%i",p); -#else - ::sprintf(szBuffer,"Group_%i",p); -#endif - } + if ('\0' == *szBuffer)pcNode->mName.length = ::sprintf(szBuffer,"Group_%i",p); + else pcNode->mName.length = ::strlen(szBuffer); ::strcpy(pcNode->mName.data,szBuffer); - pcNode->mName.length = ::strlen(szBuffer); ++p; } } @@ -1566,10 +1578,9 @@ void MDLImporter::InternReadFile_3DGS_MDL7( ) this->pScene->mRootNode = pcOldRoot->mChildren[0]; pcOldRoot->mChildren[0] = NULL; delete pcOldRoot; - this->pScene->mRootNode->mParent = NULL; } - else this->pScene->mRootNode->mName.Set("mesh_root"); + else this->pScene->mRootNode->mName.Set(""); delete[] avOutList; delete[] aszGroupNameBuffer; @@ -1578,8 +1589,6 @@ void MDLImporter::InternReadFile_3DGS_MDL7( ) // build a final material list. this->CopyMaterials_3DGS_MDL7(sharedData); - - // handle materials that are just referencing another material correctly this->HandleMaterialReferences_3DGS_MDL7(); // generate output bone animations and add all bones to the scenegraph @@ -1590,7 +1599,7 @@ void MDLImporter::InternReadFile_3DGS_MDL7( ) aiNode* const pc = this->pScene->mRootNode->mChildren[ this->pScene->mRootNode->mNumChildren-1] = new aiNode(); - pc->mName.Set("skeleton_root"); + pc->mName.Set(""); // add bones to the nodegraph this->AddBonesToNodeGraph_3DGS_MDL7((const Assimp::MDL::IntBone_MDL7 **) @@ -1604,64 +1613,15 @@ void MDLImporter::InternReadFile_3DGS_MDL7( ) // ------------------------------------------------------------------------------------------------ void MDLImporter::CopyMaterials_3DGS_MDL7(MDL::IntSharedData_MDL7 &shared) { - unsigned int iNewNumMaterials = 0; - unsigned int p = 0; - for (;p < shared.pcMats.size();++p) - if (shared.abNeedMaterials[p])++iNewNumMaterials; - - this->pScene->mMaterials = new aiMaterial*[iNewNumMaterials]; - if ((unsigned int)shared.pcMats.size() == iNewNumMaterials) - { - this->pScene->mNumMaterials = (unsigned int)shared.pcMats.size(); - for (unsigned int i = 0; i < this->pScene->mNumMaterials;++i) - this->pScene->mMaterials[i] = shared.pcMats[i]; - } - else - { - p = 0; - const unsigned int iMSB = 0x1u << (sizeof (unsigned int)*8-1); - for (unsigned int i = 0; i < (unsigned int)shared.pcMats.size();++i) - { - if (!shared.abNeedMaterials[i]) - { - // destruction is done by the destructor of sh - delete shared.pcMats[i]; - AI_DEBUG_INVALIDATE_PTR(shared.pcMats[i]); - continue; - } - this->pScene->mMaterials[p] = shared.pcMats[i]; - - if (p != i) - { - // replace the material index and MSB in all material - // indices that have been replaced to make sure they won't be - // replaced again (this won't work if there are more than - // 2^31 materials in the model - but this shouldn't care :-)). - for (unsigned int qq = 0; qq < this->pScene->mNumMeshes;++qq) - { - aiMesh* const pcMesh = this->pScene->mMeshes[qq]; - if (i == pcMesh->mMaterialIndex) - { - pcMesh->mMaterialIndex = p | iMSB; - } - } - } - ++p; - } - this->pScene->mNumMaterials = iNewNumMaterials; - - // Remove the MSB from all material indices - for (unsigned int qq = 0; qq < this->pScene->mNumMeshes;++qq) - { - this->pScene->mMeshes[qq]->mMaterialIndex &= ~iMSB; - } - } + this->pScene->mNumMaterials = (unsigned int)shared.pcMats.size(); + this->pScene->mMaterials = new aiMaterial*[this->pScene->mNumMaterials]; + for (unsigned int i = 0; i < this->pScene->mNumMaterials;++i) + this->pScene->mMaterials[i] = shared.pcMats[i]; } // ------------------------------------------------------------------------------------------------ void MDLImporter::HandleMaterialReferences_3DGS_MDL7() { // search for referrer materials - // (there is no test file but Conitec's docs say it is supported ... :cry: ) for (unsigned int i = 0; i < this->pScene->mNumMaterials;++i) { int iIndex = 0; @@ -1672,9 +1632,7 @@ void MDLImporter::HandleMaterialReferences_3DGS_MDL7() { aiMesh* const pcMesh = this->pScene->mMeshes[a]; if (i == pcMesh->mMaterialIndex) - { pcMesh->mMaterialIndex = iIndex; - } } // collapse the rest of the array delete this->pScene->mMaterials[i]; @@ -1731,8 +1689,7 @@ void MDLImporter::ParseBoneTrafoKeys_3DGS_MDL7( else { DefaultLogger::get()->warn("Found animation keyframes " - "in a group that is not the first. They will be igored, " - "the format specification says this should not occur"); + "in a group that is not the first. They will be igored"); } } } @@ -1802,7 +1759,7 @@ void MDLImporter::BuildOutputAnims_3DGS_MDL7( aiBoneAnim* const pcBoneAnim = pcAnim->mBones[iCnt++] = new aiBoneAnim(); pcBoneAnim->mBoneName = aiString( intBone->mName ); - // allocate enough storahe for all keys + // allocate enough storage for all keys pcBoneAnim->mNumPositionKeys = (unsigned int)intBone->pkeyPositions.size(); pcBoneAnim->mNumScalingKeys = (unsigned int)intBone->pkeyPositions.size(); pcBoneAnim->mNumRotationKeys = (unsigned int)intBone->pkeyPositions.size(); diff --git a/code/MDLLoader.h b/code/MDLLoader.h index e528f9e87..b62e467ba 100644 --- a/code/MDLLoader.h +++ b/code/MDLLoader.h @@ -87,6 +87,14 @@ public: * See BaseImporter::CanRead() for details. */ bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + + // ------------------------------------------------------------------- + /** Called prior to ReadFile(). + * The function is a request to the importer to update its configuration + * basing on the Importer's configuration property list. + */ + void SetupProperties(const Importer* pImp); + protected: diff --git a/code/RemoveRedundantMaterials.cpp b/code/RemoveRedundantMaterials.cpp index eb2d1617a..86ab7ff7a 100644 --- a/code/RemoveRedundantMaterials.cpp +++ b/code/RemoveRedundantMaterials.cpp @@ -88,6 +88,10 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene) unsigned int* aiMappingTable = new unsigned int[pScene->mNumMaterials]; unsigned int iNewNum = 0; + std::vector abReferenced(pScene->mNumMaterials,false); + for (unsigned int i = 0;i < pScene->mNumMeshes;++i) + abReferenced[pScene->mMeshes[i]->mMaterialIndex] = true; + // iterate through all materials and calculate a hash for them // store all hashes in a list and so a quick search whether // we do already have a specific hash. This allows us to @@ -96,6 +100,9 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene) aiHashes = new uint32_t[pScene->mNumMaterials]; for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { + // if the material is not referenced ... remove it + if (!abReferenced[i])continue; + uint32_t me = aiHashes[i] = ((MaterialHelper*)pScene->mMaterials[i])->ComputeHash(); for (unsigned int a = 0; a < i;++a) { @@ -120,6 +127,9 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene) ::memset(ppcMaterials,0,sizeof(void*)*iNewNum); for (unsigned int p = 0; p < pScene->mNumMaterials;++p) { + // if the material is not referenced ... remove it + if (!abReferenced[p])continue; + // generate new names for all modified materials const unsigned int idx = aiMappingTable[p]; if (ppcMaterials[idx]) diff --git a/code/SplitLargeMeshes.cpp b/code/SplitLargeMeshes.cpp index e58b83bc0..5c83f07af 100644 --- a/code/SplitLargeMeshes.cpp +++ b/code/SplitLargeMeshes.cpp @@ -101,12 +101,8 @@ void SplitLargeMeshesProcess_Triangle::Execute( aiScene* pScene) // Setup properties void SplitLargeMeshesProcess_Triangle::SetupProperties( const Importer* pImp) { - // get the current value of the split property - if(0xcdcdcdcd == (this->LIMIT = pImp->GetProperty( - AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,0xcdcdcdcd))) - { - this->LIMIT = AI_SLM_DEFAULT_MAX_TRIANGLES; - } + // get the current value of the split property + this->LIMIT = pImp->GetProperty(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES); } // ------------------------------------------------------------------------------------------------ // Update a node after some meshes have been split @@ -291,15 +287,11 @@ void SplitLargeMeshesProcess_Triangle::SplitMesh( // copy positions if (pMesh->mVertices != NULL) - { pcMesh->mVertices[iIndexOut] = pMesh->mVertices[iIndex]; - } // copy normals if (pMesh->HasNormals()) - { pcMesh->mNormals[iIndexOut] = pMesh->mNormals[iIndex]; - } // copy tangents/bitangents if (pMesh->HasTangentsAndBitangents()) @@ -312,17 +304,13 @@ void SplitLargeMeshesProcess_Triangle::SplitMesh( for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { if (pMesh->HasTextureCoords( c)) - { pcMesh->mTextureCoords[c][iIndexOut] = pMesh->mTextureCoords[c][iIndex]; - } } // vertex colors for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS;++c) { if (pMesh->HasVertexColors( c)) - { pcMesh->mColors[c][iIndexOut] = pMesh->mColors[c][iIndex]; - } } } } @@ -386,12 +374,7 @@ void SplitLargeMeshesProcess_Vertex::Execute( aiScene* pScene) // Setup properties void SplitLargeMeshesProcess_Vertex::SetupProperties( const Importer* pImp) { - // get the current value of the split property - if(0xcdcdcdcd == (this->LIMIT = pImp->GetProperty( - AI_CONFIG_PP_SLM_VERTEX_LIMIT,0xcdcdcdcd))) - { - this->LIMIT = AI_SLM_DEFAULT_MAX_VERTICES; - } + this->LIMIT = pImp->GetProperty(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES); } // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. @@ -455,9 +438,15 @@ void SplitLargeMeshesProcess_Vertex::SplitMesh( } // clear the temporary helper array - if (0 != iBase) + if (iBase) { - memset(&avWasCopied[0],0xFF,pMesh->mNumVertices * sizeof(unsigned int)); + // we can't use memset here we unsigned int needn' be 32 bits + for (std::vector::iterator + iter = avWasCopied.begin(),end = avWasCopied.end(); + iter != end;++iter) + { + (*iter) = 0xffffffff; + } } // output vectors diff --git a/code/ValidateDataStructure.cpp b/code/ValidateDataStructure.cpp index ba1a5926f..98ccfc924 100644 --- a/code/ValidateDataStructure.cpp +++ b/code/ValidateDataStructure.cpp @@ -710,10 +710,10 @@ __break_out: } if (pBoneAnim->mPositionKeys[i].mTime <= dLast) { - this->ReportError("aiBoneAnim::mPositionKeys[%i].mTime (%.5f) is larger " + this->ReportWarning("aiBoneAnim::mPositionKeys[%i].mTime (%.5f) is smaller " "than aiAnimation::mPositionKeys[%i] (which is %.5f)",i, (float)pBoneAnim->mPositionKeys[i].mTime, - i, (float)dLast); + i-1, (float)dLast); } dLast = pBoneAnim->mPositionKeys[i].mTime; } @@ -738,10 +738,10 @@ __break_out: } if (pBoneAnim->mRotationKeys[i].mTime <= dLast) { - this->ReportError("aiBoneAnim::mRotationKeys[%i].mTime (%.5f) is larger " + this->ReportWarning("aiBoneAnim::mRotationKeys[%i].mTime (%.5f) is smaller " "than aiAnimation::mRotationKeys[%i] (which is %.5f)",i, (float)pBoneAnim->mRotationKeys[i].mTime, - i, (float)dLast); + i-1, (float)dLast); } dLast = pBoneAnim->mRotationKeys[i].mTime; } @@ -766,10 +766,10 @@ __break_out: } if (pBoneAnim->mScalingKeys[i].mTime <= dLast) { - this->ReportError("aiBoneAnim::mScalingKeys[%i].mTime (%.5f) is larger " + this->ReportWarning("aiBoneAnim::mScalingKeys[%i].mTime (%.5f) is smaller " "than aiAnimation::mScalingKeys[%i] (which is %.5f)",i, (float)pBoneAnim->mScalingKeys[i].mTime, - i, (float)dLast); + i-1, (float)dLast); } dLast = pBoneAnim->mScalingKeys[i].mTime; } diff --git a/include/aiConfig.h b/include/aiConfig.h index b82ca2b42..179792479 100644 --- a/include/aiConfig.h +++ b/include/aiConfig.h @@ -105,6 +105,27 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define AI_CONFIG_IMPORT_3DS_IGNORE_PIVOT "imp.3ds.nopivot" +// --------------------------------------------------------------------------- +/** \brief Specifies the maximum angle that may be between two vertex tangents + * that their tangents and bitangents are smoothed. + * + * This applies to the CalcTangentSpace-Step. The angle is specified + * in degrees * 1000, so 180000 is PI. The default value is + * 45 degrees. The maximum value is 180000. + */ +#define AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE "pp.ct.max_smoothing" + +// --------------------------------------------------------------------------- +/** \brief Specifies the maximum angle that may be between two face normals + * at the same vertex position that their are smoothed. + * + * This applies to the GenSmoothNormals-Step. The angle is specified + * in degrees * 1000, so 180000 is PI. The default value is + * 180 degrees (all vertex normals are smoothed). The maximum value is 180000 + * \note This can be manually overriden by loaders via #aiMesh::mMaxSmoothingAngle; + */ +#define AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE "pp.gsn.max_smoothing" + #define AI_CONFIG_PP_OG_MAX_DEPTH "pp.og.max_depth" #define AI_CONFIG_PP_OG_MIN_TRIS_PER_NODE "pp.og.min_tris" diff --git a/include/aiMesh.h b/include/aiMesh.h index 98182f549..8aed9f3b7 100644 --- a/include/aiMesh.h +++ b/include/aiMesh.h @@ -248,6 +248,8 @@ struct aiBone #endif // !! AI_MAX_NUMBER_OF_TEXTURECOORDS +#define AI_MESH_SMOOTHING_ANGLE_NOT_SET (10e10f) + // --------------------------------------------------------------------------- /** A mesh represents a geometry or model with a single material. * @@ -358,8 +360,9 @@ struct aiMesh * If the angle between two vertex normals is larger, * the vertex normals should not be smoothed. The GenVertexNormals-Step * takes care of this value. The angle is specified in radians. - * It is 2PI if the source file didn't contain any additional - * information related to the calculation of vertex normals. + * It is set to AI_MESH_SMOOTHING_ANGLE_NOT_SET if the source file didn't + * contain any additional information related to the calculation of + * vertex normals. */ float mMaxSmoothingAngle; @@ -381,7 +384,7 @@ struct aiMesh mColors[a] = NULL; mNumBones = 0; mBones = NULL; mMaterialIndex = 0; - mMaxSmoothingAngle = (float)AI_MATH_TWO_PI; + mMaxSmoothingAngle = AI_MESH_SMOOTHING_ANGLE_NOT_SET; } //! Deletes all storage allocated for the mesh diff --git a/tools/assimp_view/assimp_view.aps b/tools/assimp_view/assimp_view.aps index 0cbec4524..9631b78f5 100644 Binary files a/tools/assimp_view/assimp_view.aps and b/tools/assimp_view/assimp_view.aps differ diff --git a/tools/assimp_view/assimp_view.rc b/tools/assimp_view/assimp_view.rc index 416c48110..1eaa6e776 100644 --- a/tools/assimp_view/assimp_view.rc +++ b/tools/assimp_view/assimp_view.rc @@ -38,21 +38,22 @@ IDI_SMALL ICON "small.ico" // Dialog // -IDD_ABOUTBOX DIALOGEX 22, 17, 283, 170 +IDD_ABOUTBOX DIALOGEX 22, 17, 283, 169 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_CAPTION | WS_SYSMENU -CAPTION "About ASSIMP" +CAPTION "About Open Asset Import Library" FONT 10, "MS Shell Dlg", 400, 0, 0x0 BEGIN - LTEXT "ASSIMP is the free, OpenSource ASSet IMPort Library",IDC_STATIC,42,12,204,12 - LTEXT "Developed by members of the german game development community www.zfx.info",IDC_STATIC,42,30,204,24 - LTEXT "Thomas Schulze \t\taka ",IDC_STATIC,42,66,192,8 - LTEXT "Kim Kulling \t\t\taka ",IDC_STATIC,42,78,186,8 - LTEXT "Rainer Schmidt \t\t\taka ",IDC_STATIC,42,90,180,8 - LTEXT "Alexander Gessler\t\taka ",IDC_STATIC,42,102,186,8 + LTEXT "Open Asset Import Library (Assimp)",IDC_STATIC,77,13,121,12 + LTEXT "A free C/C++ library for game && graphics developers. Developed by members of the german game development community www.zfx.info",IDC_STATIC,47,26,204,24 + LTEXT "Thomas Schulze \t\taka ",IDC_STATIC,55,80,192,8 + LTEXT "Kim Kulling \t\t\taka ",IDC_STATIC,55,92,186,8 + LTEXT "Rainer Schmidt \t\t\taka ",IDC_STATIC,55,104,180,8 + LTEXT "Alexander Gessler\t\taka ",IDC_STATIC,55,68,186,8 CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,60,282,1 - LTEXT "http://zfxce.svn.sourceforge.net/viewvc/zfxce/trunk/ASSIMP",IDC_STATIC,42,120,198,8 - DEFPUSHBUTTON "Love this library",IDOK,199,148,67,14 - CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,138,281,1 + LTEXT "assimp.sourceforge.net",IDC_STATIC,7,137,78,8 + DEFPUSHBUTTON "Love this library",IDOK,200,128,67,14 + CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,148,283,1 + CONTROL 130,IDC_STATIC,"Static",SS_BITMAP,0,149,514,20 END IDD_DIALOGMAIN DIALOGEX 0, 0, 594, 384 @@ -233,6 +234,7 @@ GUIDELINES DESIGNINFO BEGIN IDD_ABOUTBOX, DIALOG BEGIN + TOPMARGIN, 1 BOTTOMMARGIN, 158 END diff --git a/tools/assimp_view/banner.bmp b/tools/assimp_view/banner.bmp index 36ceed902..419b97dde 100644 Binary files a/tools/assimp_view/banner.bmp and b/tools/assimp_view/banner.bmp differ diff --git a/tools/assimp_view/banner_pure.bmp b/tools/assimp_view/banner_pure.bmp index aced0f934..e274a148a 100644 Binary files a/tools/assimp_view/banner_pure.bmp and b/tools/assimp_view/banner_pure.bmp differ diff --git a/workspaces/vc8/assimp.vcproj b/workspaces/vc8/assimp.vcproj index f97923b0a..918d141fe 100644 --- a/workspaces/vc8/assimp.vcproj +++ b/workspaces/vc8/assimp.vcproj @@ -582,6 +582,10 @@ RelativePath="..\..\include\aiAssert.h" > + + @@ -674,6 +678,10 @@ RelativePath="..\..\include\LogStream.h" > + + @@ -965,10 +973,6 @@ - - @@ -1030,6 +1034,30 @@ > + + + + + + + + + + + + + + + +