From 3f2fa97f1869247e27103daf92e30adf3d1a2843 Mon Sep 17 00:00:00 2001 From: ulfjorensen Date: Sat, 1 Aug 2009 13:57:29 +0000 Subject: [PATCH] - Bugfix: Collada-Loader now also reads animations containing multiple channels - Bugfix: Collada-Loader new resolves subelement animation channels correctly - silenced some warnings in the B3DImporter code. There are a lot more over there, though. git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@459 67173fc5-114c-0410-ac8e-9d2fd5bffc1f --- code/B3DImporter.cpp | 4 ++++ code/ColladaLoader.cpp | 10 +++++++-- code/ColladaParser.cpp | 51 +++++++++++++++++++++++++++++++++--------- 3 files changed, 52 insertions(+), 13 deletions(-) diff --git a/code/B3DImporter.cpp b/code/B3DImporter.cpp index 7defc981f..8a7bdda99 100644 --- a/code/B3DImporter.cpp +++ b/code/B3DImporter.cpp @@ -123,6 +123,7 @@ void B3DImporter::Fail( string str ){ int B3DImporter::ReadByte(){ if( _pos<_buf.size() ) return _buf[_pos++]; Fail( "EOF" ); + return 0; } // ------------------------------------------------------------------------------------------------ @@ -133,6 +134,7 @@ int B3DImporter::ReadInt(){ return n; } Fail( "EOF" ); + return 0; } // ------------------------------------------------------------------------------------------------ @@ -143,6 +145,7 @@ float B3DImporter::ReadFloat(){ return n; } Fail( "EOF" ); + return 0.0f; } // ------------------------------------------------------------------------------------------------ @@ -178,6 +181,7 @@ string B3DImporter::ReadString(){ str+=c; } Fail( "EOF" ); + return string(); } // ------------------------------------------------------------------------------------------------ diff --git a/code/ColladaLoader.cpp b/code/ColladaLoader.cpp index 11ddeab7f..b6bafd2ab 100644 --- a/code/ColladaLoader.cpp +++ b/code/ColladaLoader.cpp @@ -844,8 +844,8 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars continue; if( srcChannel.mTarget.find( '/', slashPos+1) != std::string::npos) continue; - std::string targetName = srcChannel.mTarget.substr( 0, slashPos); - if( targetName != nodeName) + std::string targetID = srcChannel.mTarget.substr( 0, slashPos); + if( targetID != srcNode->mID) continue; // find the dot that separates the transformID - there should be only one or zero @@ -860,6 +860,12 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars std::string subElement = srcChannel.mTarget.substr( dotPos+1); if( subElement == "ANGLE") entry.mSubElement = 3; // last number in an Axis-Angle-Transform is the angle + else if( subElement == "X") + entry.mSubElement = 0; + else if( subElement == "Y") + entry.mSubElement = 1; + else if( subElement == "Z") + entry.mSubElement = 2; else DefaultLogger::get()->warn( boost::str( boost::format( "Unknown anim subelement \"%s\". Ignoring") % subElement)); } else diff --git a/code/ColladaParser.cpp b/code/ColladaParser.cpp index 31bbcf564..879a5d5fc 100644 --- a/code/ColladaParser.cpp +++ b/code/ColladaParser.cpp @@ -270,8 +270,9 @@ void ColladaParser::ReadAnimationLibrary() void ColladaParser::ReadAnimation( Collada::Animation* pParent) { // an element may be a container for grouping sub-elements or an animation channel - // this is the channel we're writing to, in case it's a channel - AnimationChannel channel; + // this is the channel collection by ID, in case it has channels + typedef std::map ChannelMap; + ChannelMap channels; // this is the anim container in case we're a container Animation* anim = NULL; @@ -311,8 +312,13 @@ void ColladaParser::ReadAnimation( Collada::Animation* pParent) } else if( IsElement( "sampler")) { - // have it read into our channel - ReadAnimationSampler( channel); + // read the ID to assign the corresponding collada channel afterwards. + int indexID = GetAttribute( "id"); + std::string id = mReader->getAttributeValue( indexID); + ChannelMap::iterator newChannel = channels.insert( std::make_pair( id, AnimationChannel())).first; + + // have it read into a channel + ReadAnimationSampler( newChannel->second); } else if( IsElement( "channel")) { @@ -320,7 +326,13 @@ void ColladaParser::ReadAnimation( Collada::Animation* pParent) // Thanks, Collada! A directly posted information would have been too simple, I guess. // Better add another indirection to that! Can't have enough of those. int indexTarget = GetAttribute( "target"); - channel.mTarget = mReader->getAttributeValue( indexTarget); + int indexSource = GetAttribute( "source"); + const char* sourceId = mReader->getAttributeValue( indexSource); + if( sourceId[0] == '#') + sourceId++; + ChannelMap::iterator cit = channels.find( sourceId); + if( cit != channels.end()) + cit->second.mTarget = mReader->getAttributeValue( indexTarget); if( !mReader->isEmptyElement()) SkipElement(); @@ -340,9 +352,26 @@ void ColladaParser::ReadAnimation( Collada::Animation* pParent) } } - // it turned out to be a channel - add it - if( !channel.mTarget.empty()) - pParent->mChannels.push_back( channel); + // it turned out to have channels - add them + if( !channels.empty()) + { + // special filtering for stupid exporters packing each channel into a separate animation + if( channels.size() == 1) + { + pParent->mChannels.push_back( channels.begin()->second); + } else + { + // else create the animation, if not done yet, and store the channels + if( !anim) + { + anim = new Animation; + anim->mName = animName; + pParent->mSubAnims.push_back( anim); + } + for( ChannelMap::const_iterator it = channels.begin(); it != channels.end(); ++it) + anim->mChannels.push_back( it->second); + } + } } // ------------------------------------------------------------------------------------------------ @@ -2364,10 +2393,10 @@ void ColladaParser::ReadNodeGeometry( Node* pNode) int attrMaterial = GetAttribute( "target"); const char* urlMat = mReader->getAttributeValue( attrMaterial); Collada::SemanticMappingTable s; - if( urlMat[0] != '#') - ThrowException( "Unknown reference format"); + if( urlMat[0] == '#') + urlMat++; - s.mMatName = urlMat+1; + s.mMatName = urlMat; // resolve further material details + THIS UGLY AND NASTY semantic mapping stuff if( !mReader->isEmptyElement())