diff --git a/code/MD5Loader.cpp b/code/MD5Loader.cpp index b7a7f2e46..bd0255c69 100644 --- a/code/MD5Loader.cpp +++ b/code/MD5Loader.cpp @@ -143,7 +143,7 @@ void MD5Importer::InternReadFile( const std::string& pFile, } // make sure we have at least one file - if (!bHadMD5Mesh && !bHadMD5Anim) + if (!bHadMD5Mesh && !bHadMD5Anim && !bHadMD5Camera) throw new ImportErrorException("Failed to read valid contents from this MD5 data set"); // the output scene wouldn't pass the validation without this flag @@ -425,9 +425,6 @@ void MD5Importer::LoadMD5MeshFile () // compute w-component of quaternion MD5::ConvertQuaternion( boneSrc.mRotationQuat, boneSrc.mRotationQuatConverted ); - - //boneSrc.mPositionXYZ.z *= -1.f; - //boneSrc.mRotationQuatConverted = boneSrc.mRotationQuatConverted * aiQuaternion(-0.5f, -0.5f, -0.5f, 0.5f) ; } //unsigned int g = 0; @@ -465,7 +462,6 @@ void MD5Importer::LoadMD5MeshFile () aiBone* bone = mesh->mBones[boneSrc.mMap]; *bone->mWeights++ = aiVertexWeight((unsigned int)(pv-mesh->mVertices),fNewWeight); } - //pv->z *= -1.f; } // undo our nice offset tricks ... @@ -642,14 +638,12 @@ void MD5Importer::LoadMD5AnimFile () // Load an MD5CAMERA file void MD5Importer::LoadMD5CameraFile () { -#if 0 std::string pFile = mFile + "md5camera"; boost::scoped_ptr file( pIOHandler->Open( pFile, "rb")); // Check whether we can read from the file if( file.get() == NULL) { - DefaultLogger::get()->warn("Failed to read MD5CAMERA file: " + pFile); - return; + throw new ImportErrorException("Failed to read MD5CAMERA file: " + pFile); } bHadMD5Camera = true; LoadFileIntoMemory(file.get()); @@ -659,8 +653,59 @@ void MD5Importer::LoadMD5CameraFile () // load the camera animation data from the parse tree MD5::MD5CameraParser cameraParser(parser.mSections); -#endif - throw new ImportErrorException("MD5Camera is not yet supported"); + + if (cameraParser.frames.empty()) + throw new ImportErrorException("MD5CAMERA: No frames parsed"); + + std::vector& cuts = cameraParser.cuts; + std::vector& frames = cameraParser.frames; + + // Construct output graph - a simple dummy node + aiNode* root = pScene->mRootNode = new aiNode(); + root->mName.Set(""); + + // ... but with one camera assigned to it + pScene->mCameras = new aiCamera*[pScene->mNumCameras = 1]; + aiCamera* cam = pScene->mCameras[0] = new aiCamera(); + cam->mName = root->mName; + + // FIXME: Fov is currently set to the first frame's value + cam->mHorizontalFOV = AI_DEG_TO_RAD( frames.front().fFOV ); + + // every cut is written to a separate aiAnimation + if (!cuts.size()) { + cuts.push_back(0); + cuts.push_back(frames.size()-1); + } + else { + cuts.insert(cuts.begin(),0); + + if (cuts.back() < frames.size()-1) + cuts.push_back(frames.size()-1); + } + + pScene->mNumAnimations = cuts.size()-1; + aiAnimation** tmp = pScene->mAnimations = new aiAnimation*[pScene->mNumAnimations]; + for (std::vector::const_iterator it = cuts.begin(); it != cuts.end()-1; ++it) { + + aiAnimation* anim = *tmp++ = new aiAnimation(); + anim->mName.length = ::sprintf(anim->mName.data,"anim%i_from_%i_to_%i",it-cuts.begin(),(*it),*(it+1)); + + anim->mTicksPerSecond = cameraParser.fFrameRate; + anim->mChannels = new aiNodeAnim*[anim->mNumChannels = 1]; + aiNodeAnim* nd = anim->mChannels[0] = new aiNodeAnim(); + nd->mNodeName.Set(""); + + nd->mNumPositionKeys = nd->mNumRotationKeys = *(it+1) - (*it); + nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys]; + nd->mRotationKeys = new aiQuatKey [nd->mNumRotationKeys]; + for (unsigned int i = 0; i < nd->mNumPositionKeys; ++i) { + + nd->mPositionKeys[i].mValue = frames[*it+i].vPositionXYZ; + MD5::ConvertQuaternion(frames[*it+i].vRotationQuat,nd->mRotationKeys[i].mValue); + nd->mRotationKeys[i].mTime = nd->mPositionKeys[i].mTime = *it+i; + } + } } #endif // !! ASSIMP_BUILD_NO_MD5_IMPORTER diff --git a/code/MD5Parser.cpp b/code/MD5Parser.cpp index 59cfae742..839fb09a1 100644 --- a/code/MD5Parser.cpp +++ b/code/MD5Parser.cpp @@ -160,10 +160,12 @@ bool MD5Parser::ParseSection(Section& out) elem.iLineNumber = lineNumber; elem.szStart = buffer; - // terminate the line with zero - remove all spaces at the end + // terminate the line with zero while (!IsLineEnd( *buffer))buffer++; - do {buffer--;}while (IsSpace(*buffer)); - buffer++;*buffer++ = '\0'; + if (*buffer) { + ++lineNumber; + *buffer++ = '\0'; + } } break; } @@ -203,17 +205,16 @@ bool MD5Parser::ParseSection(Section& out) // parse a string, enclosed in quotation marks or not #define AI_MD5_PARSE_STRING(out) \ - bool bQuota = *sz == '\"'; \ + bool bQuota = (*sz == '\"'); \ const char* szStart = sz; \ while (!IsSpaceOrNewLine(*sz))++sz; \ const char* szEnd = sz; \ - if (bQuota) \ - { \ + if (bQuota) { \ szStart++; \ - if ('\"' != *(szEnd-=1)) \ - { \ + if ('\"' != *(szEnd-=1)) { \ MD5Parser::ReportWarning("Expected closing quotation marks in string", \ (*eit).iLineNumber); \ + continue; \ } \ } \ out.length = (size_t)(szEnd - szStart); \ @@ -228,17 +229,13 @@ MD5MeshParser::MD5MeshParser(SectionList& mSections) // now parse all sections for (SectionList::const_iterator iter = mSections.begin(), iterEnd = mSections.end();iter != iterEnd;++iter){ - if ((*iter).mGlobalValue.length()) - { - if ( (*iter).mName == "numMeshes") { - mMeshes.reserve(::strtol10((*iter).mGlobalValue.c_str())); - } - else if ( (*iter).mName == "numJoints") { - mJoints.reserve(::strtol10((*iter).mGlobalValue.c_str())); - } + if ( (*iter).mName == "numMeshes") { + mMeshes.reserve(::strtol10((*iter).mGlobalValue.c_str())); } - else if ((*iter).mName == "joints") - { + else if ( (*iter).mName == "numJoints") { + mJoints.reserve(::strtol10((*iter).mGlobalValue.c_str())); + } + else if ((*iter).mName == "joints") { // "origin" -1 ( -0.000000 0.016430 -0.006044 ) ( 0.707107 0.000000 0.707107 ) for (ElementList::const_iterator eit = (*iter).mElements.begin(), eitEnd = (*iter).mElements.end();eit != eitEnd; ++eit){ mJoints.push_back(BoneDesc()); @@ -248,19 +245,14 @@ MD5MeshParser::MD5MeshParser(SectionList& mSections) AI_MD5_PARSE_STRING(desc.mName); AI_MD5_SKIP_SPACES(); - // negative values can occur here ... - bool bNeg = false; - if ('-' == *sz){sz++;bNeg = true;} - else if ('+' == *sz){sz++;} - desc.mParentIndex = (int)::strtol10(sz,&sz); - if (bNeg)desc.mParentIndex *= -1; - + // negative values, at least -1, is allowed here + desc.mParentIndex = (int)strtol10s(sz,&sz); + AI_MD5_READ_TRIPLE(desc.mPositionXYZ); AI_MD5_READ_TRIPLE(desc.mRotationQuat); // normalized quaternion, so w is not there } } - else if ((*iter).mName == "mesh") - { + else if ((*iter).mName == "mesh") { mMeshes.push_back(MeshDesc()); MeshDesc& desc = mMeshes.back(); @@ -268,37 +260,28 @@ MD5MeshParser::MD5MeshParser(SectionList& mSections) const char* sz = (*eit).szStart; // shader attribute - if (TokenMatch(sz,"shader",6)) - { - // don't expect quotation marks + if (TokenMatch(sz,"shader",6)) { AI_MD5_SKIP_SPACES(); AI_MD5_PARSE_STRING(desc.mShader); } // numverts attribute - else if (TokenMatch(sz,"numverts",8)) - { - // reserve enough storage + else if (TokenMatch(sz,"numverts",8)) { AI_MD5_SKIP_SPACES(); - desc.mVertices.resize(::strtol10(sz)); + desc.mVertices.resize(strtol10(sz)); } // numtris attribute - else if (TokenMatch(sz,"numtris",7)) - { - // reserve enough storage + else if (TokenMatch(sz,"numtris",7)) { AI_MD5_SKIP_SPACES(); - desc.mFaces.resize(::strtol10(sz)); + desc.mFaces.resize(strtol10(sz)); } // numweights attribute - else if (TokenMatch(sz,"numweights",10)) - { - // reserve enough storage + else if (TokenMatch(sz,"numweights",10)) { AI_MD5_SKIP_SPACES(); - desc.mWeights.resize(::strtol10(sz)); + desc.mWeights.resize(strtol10(sz)); } // vert attribute // "vert 0 ( 0.394531 0.513672 ) 0 1" - else if (TokenMatch(sz,"vert",4)) - { + else if (TokenMatch(sz,"vert",4)) { AI_MD5_SKIP_SPACES(); const unsigned int idx = ::strtol10(sz,&sz); AI_MD5_SKIP_SPACES(); @@ -324,30 +307,28 @@ MD5MeshParser::MD5MeshParser(SectionList& mSections) // "tri 0 15 13 12" else if (TokenMatch(sz,"tri",3)) { AI_MD5_SKIP_SPACES(); - const unsigned int idx = ::strtol10(sz,&sz); + const unsigned int idx = strtol10(sz,&sz); if (idx >= desc.mFaces.size()) desc.mFaces.resize(idx+1); aiFace& face = desc.mFaces[idx]; face.mIndices = new unsigned int[face.mNumIndices = 3]; - for (unsigned int i = 0; i < 3;++i) - { + for (unsigned int i = 0; i < 3;++i) { AI_MD5_SKIP_SPACES(); - face.mIndices[i] = ::strtol10(sz,&sz); + face.mIndices[i] = strtol10(sz,&sz); } } // weight attribute // "weight 362 5 0.500000 ( -3.553583 11.893474 9.719339 )" - else if (TokenMatch(sz,"weight",6)) - { + else if (TokenMatch(sz,"weight",6)) { AI_MD5_SKIP_SPACES(); - const unsigned int idx = ::strtol10(sz,&sz); + const unsigned int idx = strtol10(sz,&sz); AI_MD5_SKIP_SPACES(); if (idx >= desc.mWeights.size()) desc.mWeights.resize(idx+1); WeightDesc& weight = desc.mWeights[idx]; - weight.mBone = ::strtol10(sz,&sz); + weight.mBone = strtol10(sz,&sz); AI_MD5_SKIP_SPACES(); sz = fast_atof_move(sz,weight.mWeight); AI_MD5_READ_TRIPLE(weight.vOffsetPosition); @@ -366,8 +347,6 @@ MD5AnimParser::MD5AnimParser(SectionList& mSections) fFrameRate = 24.0f; mNumAnimatedComponents = 0xffffffff; - - // now parse all sections for (SectionList::const_iterator iter = mSections.begin(), iterEnd = mSections.end();iter != iterEnd;++iter) { if ((*iter).mName == "hierarchy") { // "sheath" 0 63 6 @@ -406,15 +385,14 @@ MD5AnimParser::MD5AnimParser(SectionList& mSections) } } else if((*iter).mName == "frame") { - if (!(*iter).mGlobalValue.length()) - { + if (!(*iter).mGlobalValue.length()) { MD5Parser::ReportWarning("A frame section must have a frame index",(*iter).iLineNumber); continue; } mFrames.push_back ( FrameDesc () ); FrameDesc& desc = mFrames.back(); - desc.iIndex = ::strtol10((*iter).mGlobalValue.c_str()); + desc.iIndex = strtol10((*iter).mGlobalValue.c_str()); // we do already know how much storage we will presumably need if (0xffffffff != mNumAnimatedComponents) @@ -430,10 +408,10 @@ MD5AnimParser::MD5AnimParser(SectionList& mSections) } } else if((*iter).mName == "numFrames") { - mFrames.reserve(::strtol10((*iter).mGlobalValue.c_str())); + mFrames.reserve(strtol10((*iter).mGlobalValue.c_str())); } else if((*iter).mName == "numJoints") { - const unsigned int num = ::strtol10((*iter).mGlobalValue.c_str()); + const unsigned int num = strtol10((*iter).mGlobalValue.c_str()); mAnimatedBones.reserve(num); // try to guess the number of animated components if that element is not given @@ -441,7 +419,7 @@ MD5AnimParser::MD5AnimParser(SectionList& mSections) mNumAnimatedComponents = num * 6; } else if((*iter).mName == "numAnimatedComponents") { - mAnimatedBones.reserve( ::strtol10((*iter).mGlobalValue.c_str())); + mAnimatedBones.reserve( strtol10((*iter).mGlobalValue.c_str())); } else if((*iter).mName == "frameRate") { fast_atof_move((*iter).mGlobalValue.c_str(),fFrameRate); @@ -457,6 +435,34 @@ MD5CameraParser::MD5CameraParser(SectionList& mSections) DefaultLogger::get()->debug("MD5CameraParser begin"); fFrameRate = 24.0f; + for (SectionList::const_iterator iter = mSections.begin(), iterEnd = mSections.end();iter != iterEnd;++iter) { + if ((*iter).mName == "numFrames") { + frames.reserve(strtol10((*iter).mGlobalValue.c_str())); + } + else if ((*iter).mName == "frameRate") { + fFrameRate = fast_atof ((*iter).mGlobalValue.c_str()); + } + else if ((*iter).mName == "numCuts") { + cuts.reserve(strtol10((*iter).mGlobalValue.c_str())); + } + else if ((*iter).mName == "cuts") { + for (ElementList::const_iterator eit = (*iter).mElements.begin(), eitEnd = (*iter).mElements.end(); eit != eitEnd; ++eit){ + cuts.push_back(strtol10((*eit).szStart)+1); + } + } + else if ((*iter).mName == "camera") { + for (ElementList::const_iterator eit = (*iter).mElements.begin(), eitEnd = (*iter).mElements.end(); eit != eitEnd; ++eit){ + const char* sz = (*eit).szStart; + + frames.push_back(CameraAnimFrameDesc()); + CameraAnimFrameDesc& cur = frames.back(); + AI_MD5_READ_TRIPLE(cur.vPositionXYZ); + AI_MD5_READ_TRIPLE(cur.vRotationQuat); + AI_MD5_SKIP_SPACES(); + cur.fFOV = fast_atof(sz); + } + } + } DefaultLogger::get()->debug("MD5CameraParser end"); } diff --git a/code/MD5Parser.h b/code/MD5Parser.h index b25ce3828..ab68a735e 100644 --- a/code/MD5Parser.h +++ b/code/MD5Parser.h @@ -426,8 +426,8 @@ private: bool bHad = false; while (true) { if( *in == '\r' || *in == '\n') { - if (!bHad) // we open files in binary mode, so there could be \r\n sequences ... - { + // we open files in binary mode, so there could be \r\n sequences ... + if (!bHad) { bHad = true; ++lineNumber; } @@ -436,7 +436,6 @@ private: else break; in++; } - *out = in; return *in != '\0'; } diff --git a/code/RemoveComments.cpp b/code/RemoveComments.cpp index 8986de1bc..c76941bb7 100644 --- a/code/RemoveComments.cpp +++ b/code/RemoveComments.cpp @@ -38,29 +38,32 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file Defines a helper class, "CommentRemover", which can be - * used to remove comments (single and multi line) from a text file. +/** @file RemoveComments.cpp + * @brief Defines the CommentRemover utility class */ #include "AssimpPCH.h" #include "RemoveComments.h" #include "ParsingUtils.h" -namespace Assimp -{ +namespace Assimp { // ------------------------------------------------------------------------------------------------ +// Remove line comments from a file void CommentRemover::RemoveLineComments(const char* szComment, char* szBuffer, char chReplacement /* = ' ' */) { // validate parameters ai_assert(NULL != szComment && NULL != szBuffer && *szComment); - const size_t len = ::strlen(szComment); - while (*szBuffer) - { - if (!::strncmp(szBuffer,szComment,len)) - { + const size_t len = strlen(szComment); + while (*szBuffer) { + + // skip over quotes + if (*szBuffer == '\"' || *szBuffer == '\'') + while (*szBuffer++ && *szBuffer != '\"' && *szBuffer != '\''); + + if (!strncmp(szBuffer,szComment,len)) { while (!IsLineEnd(*szBuffer)) *szBuffer++ = chReplacement; } @@ -69,6 +72,7 @@ void CommentRemover::RemoveLineComments(const char* szComment, } // ------------------------------------------------------------------------------------------------ +// Remove multi-line comments from a file void CommentRemover::RemoveMultiLineComments(const char* szCommentStart, const char* szCommentEnd,char* szBuffer, char chReplacement) @@ -77,25 +81,24 @@ void CommentRemover::RemoveMultiLineComments(const char* szCommentStart, ai_assert(NULL != szCommentStart && NULL != szCommentEnd && NULL != szBuffer && *szCommentStart && *szCommentEnd); - const size_t len = ::strlen(szCommentEnd); - const size_t len2 = ::strlen(szCommentStart); + const size_t len = strlen(szCommentEnd); + const size_t len2 = strlen(szCommentStart); - while (*szBuffer) - { - if (!::strncmp(szBuffer,szCommentStart,len2)) - { - while (*szBuffer) - { - if (!::strncmp(szBuffer,szCommentEnd,len)) - { + while (*szBuffer) { + // skip over quotes + if (*szBuffer == '\"' || *szBuffer == '\'') + while (*szBuffer++ && *szBuffer != '\"' && *szBuffer != '\''); + + if (!strncmp(szBuffer,szCommentStart,len2)) { + while (*szBuffer) { + if (!::strncmp(szBuffer,szCommentEnd,len)) { for (unsigned int i = 0; i < len;++i) *szBuffer++ = chReplacement; - + break; } *szBuffer++ = chReplacement; } - if (!(*szBuffer))return; continue; } ++szBuffer;