diff options
Diffstat (limited to 'src/3rdparty/assimp/code/BVHLoader.cpp')
-rw-r--r-- | src/3rdparty/assimp/code/BVHLoader.cpp | 779 |
1 files changed, 394 insertions, 385 deletions
diff --git a/src/3rdparty/assimp/code/BVHLoader.cpp b/src/3rdparty/assimp/code/BVHLoader.cpp index 35a3e20ef..ca6c5d36c 100644 --- a/src/3rdparty/assimp/code/BVHLoader.cpp +++ b/src/3rdparty/assimp/code/BVHLoader.cpp @@ -4,12 +4,12 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp 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 +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 @@ -26,46 +26,55 @@ contributors may be used to endorse or promote products derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +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 +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 +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 +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. --------------------------------------------------------------------------- */ -#include "AssimpPCH.h" + #ifndef ASSIMP_BUILD_NO_BVH_IMPORTER #include "BVHLoader.h" #include "fast_atof.h" #include "SkeletonMeshBuilder.h" +#include <assimp/Importer.hpp> +#include <memory> +#include "TinyFormatter.h" +#include <assimp/IOSystem.hpp> +#include <assimp/scene.h> using namespace Assimp; +using namespace Assimp::Formatter; static const aiImporterDesc desc = { - "BVH Importer (MoCap)", - "", - "", - "", - aiImporterFlags_SupportTextFlavour, - 0, - 0, - 0, - 0, - "bvh" + "BVH Importer (MoCap)", + "", + "", + "", + aiImporterFlags_SupportTextFlavour, + 0, + 0, + 0, + 0, + "bvh" }; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer BVHLoader::BVHLoader() -: noSkeletonMesh() + : mLine(), + mAnimTickDuration(), + mAnimNumFrames(), + noSkeletonMesh() {} // ------------------------------------------------------------------------------------------------ @@ -74,461 +83,461 @@ BVHLoader::~BVHLoader() {} // ------------------------------------------------------------------------------------------------ -// Returns whether the class can handle the format of the given file. +// Returns whether the class can handle the format of the given file. bool BVHLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const { - // check file extension - const std::string extension = GetExtension(pFile); - - if( extension == "bvh") - return true; - - if ((!extension.length() || cs) && pIOHandler) { - const char* tokens[] = {"HIERARCHY"}; - return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); - } - return false; + // check file extension + const std::string extension = GetExtension(pFile); + + if( extension == "bvh") + return true; + + if ((!extension.length() || cs) && pIOHandler) { + const char* tokens[] = {"HIERARCHY"}; + return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); + } + return false; } // ------------------------------------------------------------------------------------------------ void BVHLoader::SetupProperties(const Importer* pImp) { - noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0; + noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0; } // ------------------------------------------------------------------------------------------------ // Loader meta information const aiImporterDesc* BVHLoader::GetInfo () const { - return &desc; + return &desc; } // ------------------------------------------------------------------------------------------------ -// Imports the given file into the given scene structure. +// Imports the given file into the given scene structure. void BVHLoader::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) { - mFileName = pFile; + mFileName = pFile; - // read file into memory - boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile)); - if( file.get() == NULL) - throw DeadlyImportError( "Failed to open file " + pFile + "."); + // read file into memory + std::unique_ptr<IOStream> file( pIOHandler->Open( pFile)); + if( file.get() == NULL) + throw DeadlyImportError( "Failed to open file " + pFile + "."); - size_t fileSize = file->FileSize(); - if( fileSize == 0) - throw DeadlyImportError( "File is too small."); + size_t fileSize = file->FileSize(); + if( fileSize == 0) + throw DeadlyImportError( "File is too small."); - mBuffer.resize( fileSize); - file->Read( &mBuffer.front(), 1, fileSize); + mBuffer.resize( fileSize); + file->Read( &mBuffer.front(), 1, fileSize); - // start reading - mReader = mBuffer.begin(); - mLine = 1; - ReadStructure( pScene); + // start reading + mReader = mBuffer.begin(); + mLine = 1; + ReadStructure( pScene); - if (!noSkeletonMesh) { - // build a dummy mesh for the skeleton so that we see something at least - SkeletonMeshBuilder meshBuilder( pScene); - } + if (!noSkeletonMesh) { + // build a dummy mesh for the skeleton so that we see something at least + SkeletonMeshBuilder meshBuilder( pScene); + } - // construct an animation from all the motion data we read - CreateAnimation( pScene); + // construct an animation from all the motion data we read + CreateAnimation( pScene); } // ------------------------------------------------------------------------------------------------ // Reads the file void BVHLoader::ReadStructure( aiScene* pScene) { - // first comes hierarchy - std::string header = GetNextToken(); - if( header != "HIERARCHY") - ThrowException( "Expected header string \"HIERARCHY\"."); - ReadHierarchy( pScene); - - // then comes the motion data - std::string motion = GetNextToken(); - if( motion != "MOTION") - ThrowException( "Expected beginning of motion data \"MOTION\"."); - ReadMotion( pScene); + // first comes hierarchy + std::string header = GetNextToken(); + if( header != "HIERARCHY") + ThrowException( "Expected header string \"HIERARCHY\"."); + ReadHierarchy( pScene); + + // then comes the motion data + std::string motion = GetNextToken(); + if( motion != "MOTION") + ThrowException( "Expected beginning of motion data \"MOTION\"."); + ReadMotion( pScene); } // ------------------------------------------------------------------------------------------------ // Reads the hierarchy void BVHLoader::ReadHierarchy( aiScene* pScene) { - std::string root = GetNextToken(); - if( root != "ROOT") - ThrowException( "Expected root node \"ROOT\"."); + std::string root = GetNextToken(); + if( root != "ROOT") + ThrowException( "Expected root node \"ROOT\"."); - // Go read the hierarchy from here - pScene->mRootNode = ReadNode(); + // Go read the hierarchy from here + pScene->mRootNode = ReadNode(); } // ------------------------------------------------------------------------------------------------ // Reads a node and recursively its childs and returns the created node; aiNode* BVHLoader::ReadNode() { - // first token is name - std::string nodeName = GetNextToken(); - if( nodeName.empty() || nodeName == "{") - ThrowException( boost::str( boost::format( "Expected node name, but found \"%s\".") % nodeName)); - - // then an opening brace should follow - std::string openBrace = GetNextToken(); - if( openBrace != "{") - ThrowException( boost::str( boost::format( "Expected opening brace \"{\", but found \"%s\".") % openBrace)); - - // Create a node - aiNode* node = new aiNode( nodeName); - std::vector<aiNode*> childNodes; - - // and create an bone entry for it - mNodes.push_back( Node( node)); - Node& internNode = mNodes.back(); - - // now read the node's contents - while( 1) - { - std::string token = GetNextToken(); - - // node offset to parent node - if( token == "OFFSET") - ReadNodeOffset( node); - else if( token == "CHANNELS") - ReadNodeChannels( internNode); - else if( token == "JOINT") - { - // child node follows - aiNode* child = ReadNode(); - child->mParent = node; - childNodes.push_back( child); - } - else if( token == "End") - { - // The real symbol is "End Site". Second part comes in a separate token - std::string siteToken = GetNextToken(); - if( siteToken != "Site") - ThrowException( boost::str( boost::format( "Expected \"End Site\" keyword, but found \"%s %s\".") % token % siteToken)); - - aiNode* child = ReadEndSite( nodeName); - child->mParent = node; - childNodes.push_back( child); - } - else if( token == "}") - { - // we're done with that part of the hierarchy - break; - } else - { - // everything else is a parse error - ThrowException( boost::str( boost::format( "Unknown keyword \"%s\".") % token)); - } - } - - // add the child nodes if there are any - if( childNodes.size() > 0) - { - node->mNumChildren = childNodes.size(); - node->mChildren = new aiNode*[node->mNumChildren]; - std::copy( childNodes.begin(), childNodes.end(), node->mChildren); - } - - // and return the sub-hierarchy we built here - return node; + // first token is name + std::string nodeName = GetNextToken(); + if( nodeName.empty() || nodeName == "{") + ThrowException( format() << "Expected node name, but found \"" << nodeName << "\"." ); + + // then an opening brace should follow + std::string openBrace = GetNextToken(); + if( openBrace != "{") + ThrowException( format() << "Expected opening brace \"{\", but found \"" << openBrace << "\"." ); + + // Create a node + aiNode* node = new aiNode( nodeName); + std::vector<aiNode*> childNodes; + + // and create an bone entry for it + mNodes.push_back( Node( node)); + Node& internNode = mNodes.back(); + + // now read the node's contents + while( 1) + { + std::string token = GetNextToken(); + + // node offset to parent node + if( token == "OFFSET") + ReadNodeOffset( node); + else if( token == "CHANNELS") + ReadNodeChannels( internNode); + else if( token == "JOINT") + { + // child node follows + aiNode* child = ReadNode(); + child->mParent = node; + childNodes.push_back( child); + } + else if( token == "End") + { + // The real symbol is "End Site". Second part comes in a separate token + std::string siteToken = GetNextToken(); + if( siteToken != "Site") + ThrowException( format() << "Expected \"End Site\" keyword, but found \"" << token << " " << siteToken << "\"." ); + + aiNode* child = ReadEndSite( nodeName); + child->mParent = node; + childNodes.push_back( child); + } + else if( token == "}") + { + // we're done with that part of the hierarchy + break; + } else + { + // everything else is a parse error + ThrowException( format() << "Unknown keyword \"" << token << "\"." ); + } + } + + // add the child nodes if there are any + if( childNodes.size() > 0) + { + node->mNumChildren = childNodes.size(); + node->mChildren = new aiNode*[node->mNumChildren]; + std::copy( childNodes.begin(), childNodes.end(), node->mChildren); + } + + // and return the sub-hierarchy we built here + return node; } // ------------------------------------------------------------------------------------------------ // Reads an end node and returns the created node. aiNode* BVHLoader::ReadEndSite( const std::string& pParentName) { - // check opening brace - std::string openBrace = GetNextToken(); - if( openBrace != "{") - ThrowException( boost::str( boost::format( "Expected opening brace \"{\", but found \"%s\".") % openBrace)); - - // Create a node - aiNode* node = new aiNode( "EndSite_" + pParentName); - - // now read the node's contents. Only possible entry is "OFFSET" - while( 1) - { - std::string token = GetNextToken(); - - // end node's offset - if( token == "OFFSET") - { - ReadNodeOffset( node); - } - else if( token == "}") - { - // we're done with the end node - break; - } else - { - // everything else is a parse error - ThrowException( boost::str( boost::format( "Unknown keyword \"%s\".") % token)); - } - } - - // and return the sub-hierarchy we built here - return node; + // check opening brace + std::string openBrace = GetNextToken(); + if( openBrace != "{") + ThrowException( format() << "Expected opening brace \"{\", but found \"" << openBrace << "\"."); + + // Create a node + aiNode* node = new aiNode( "EndSite_" + pParentName); + + // now read the node's contents. Only possible entry is "OFFSET" + while( 1) + { + std::string token = GetNextToken(); + + // end node's offset + if( token == "OFFSET") + { + ReadNodeOffset( node); + } + else if( token == "}") + { + // we're done with the end node + break; + } else + { + // everything else is a parse error + ThrowException( format() << "Unknown keyword \"" << token << "\"." ); + } + } + + // and return the sub-hierarchy we built here + return node; } // ------------------------------------------------------------------------------------------------ // Reads a node offset for the given node void BVHLoader::ReadNodeOffset( aiNode* pNode) { - // Offset consists of three floats to read - aiVector3D offset; - offset.x = GetNextTokenAsFloat(); - offset.y = GetNextTokenAsFloat(); - offset.z = GetNextTokenAsFloat(); - - // build a transformation matrix from it - pNode->mTransformation = aiMatrix4x4( 1.0f, 0.0f, 0.0f, offset.x, 0.0f, 1.0f, 0.0f, offset.y, - 0.0f, 0.0f, 1.0f, offset.z, 0.0f, 0.0f, 0.0f, 1.0f); + // Offset consists of three floats to read + aiVector3D offset; + offset.x = GetNextTokenAsFloat(); + offset.y = GetNextTokenAsFloat(); + offset.z = GetNextTokenAsFloat(); + + // build a transformation matrix from it + pNode->mTransformation = aiMatrix4x4( 1.0f, 0.0f, 0.0f, offset.x, 0.0f, 1.0f, 0.0f, offset.y, + 0.0f, 0.0f, 1.0f, offset.z, 0.0f, 0.0f, 0.0f, 1.0f); } // ------------------------------------------------------------------------------------------------ // Reads the animation channels for the given node void BVHLoader::ReadNodeChannels( BVHLoader::Node& pNode) { - // number of channels. Use the float reader because we're lazy - float numChannelsFloat = GetNextTokenAsFloat(); - unsigned int numChannels = (unsigned int) numChannelsFloat; - - for( unsigned int a = 0; a < numChannels; a++) - { - std::string channelToken = GetNextToken(); - - if( channelToken == "Xposition") - pNode.mChannels.push_back( Channel_PositionX); - else if( channelToken == "Yposition") - pNode.mChannels.push_back( Channel_PositionY); - else if( channelToken == "Zposition") - pNode.mChannels.push_back( Channel_PositionZ); - else if( channelToken == "Xrotation") - pNode.mChannels.push_back( Channel_RotationX); - else if( channelToken == "Yrotation") - pNode.mChannels.push_back( Channel_RotationY); - else if( channelToken == "Zrotation") - pNode.mChannels.push_back( Channel_RotationZ); - else - ThrowException( boost::str( boost::format( "Invalid channel specifier \"%s\".") % channelToken)); - } + // number of channels. Use the float reader because we're lazy + float numChannelsFloat = GetNextTokenAsFloat(); + unsigned int numChannels = (unsigned int) numChannelsFloat; + + for( unsigned int a = 0; a < numChannels; a++) + { + std::string channelToken = GetNextToken(); + + if( channelToken == "Xposition") + pNode.mChannels.push_back( Channel_PositionX); + else if( channelToken == "Yposition") + pNode.mChannels.push_back( Channel_PositionY); + else if( channelToken == "Zposition") + pNode.mChannels.push_back( Channel_PositionZ); + else if( channelToken == "Xrotation") + pNode.mChannels.push_back( Channel_RotationX); + else if( channelToken == "Yrotation") + pNode.mChannels.push_back( Channel_RotationY); + else if( channelToken == "Zrotation") + pNode.mChannels.push_back( Channel_RotationZ); + else + ThrowException( format() << "Invalid channel specifier \"" << channelToken << "\"." ); + } } // ------------------------------------------------------------------------------------------------ // Reads the motion data void BVHLoader::ReadMotion( aiScene* /*pScene*/) { - // Read number of frames - std::string tokenFrames = GetNextToken(); - if( tokenFrames != "Frames:") - ThrowException( boost::str( boost::format( "Expected frame count \"Frames:\", but found \"%s\".") % tokenFrames)); - - float numFramesFloat = GetNextTokenAsFloat(); - mAnimNumFrames = (unsigned int) numFramesFloat; - - // Read frame duration - std::string tokenDuration1 = GetNextToken(); - std::string tokenDuration2 = GetNextToken(); - if( tokenDuration1 != "Frame" || tokenDuration2 != "Time:") - ThrowException( boost::str( boost::format( "Expected frame duration \"Frame Time:\", but found \"%s %s\".") % tokenDuration1 % tokenDuration2)); - - mAnimTickDuration = GetNextTokenAsFloat(); - - // resize value vectors for each node - for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it) - it->mChannelValues.reserve( it->mChannels.size() * mAnimNumFrames); - - // now read all the data and store it in the corresponding node's value vector - for( unsigned int frame = 0; frame < mAnimNumFrames; ++frame) - { - // on each line read the values for all nodes - for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it) - { - // get as many values as the node has channels - for( unsigned int c = 0; c < it->mChannels.size(); ++c) - it->mChannelValues.push_back( GetNextTokenAsFloat()); - } - - // after one frame worth of values for all nodes there should be a newline, but we better don't rely on it - } + // Read number of frames + std::string tokenFrames = GetNextToken(); + if( tokenFrames != "Frames:") + ThrowException( format() << "Expected frame count \"Frames:\", but found \"" << tokenFrames << "\"."); + + float numFramesFloat = GetNextTokenAsFloat(); + mAnimNumFrames = (unsigned int) numFramesFloat; + + // Read frame duration + std::string tokenDuration1 = GetNextToken(); + std::string tokenDuration2 = GetNextToken(); + if( tokenDuration1 != "Frame" || tokenDuration2 != "Time:") + ThrowException( format() << "Expected frame duration \"Frame Time:\", but found \"" << tokenDuration1 << " " << tokenDuration2 << "\"." ); + + mAnimTickDuration = GetNextTokenAsFloat(); + + // resize value vectors for each node + for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it) + it->mChannelValues.reserve( it->mChannels.size() * mAnimNumFrames); + + // now read all the data and store it in the corresponding node's value vector + for( unsigned int frame = 0; frame < mAnimNumFrames; ++frame) + { + // on each line read the values for all nodes + for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it) + { + // get as many values as the node has channels + for( unsigned int c = 0; c < it->mChannels.size(); ++c) + it->mChannelValues.push_back( GetNextTokenAsFloat()); + } + + // after one frame worth of values for all nodes there should be a newline, but we better don't rely on it + } } // ------------------------------------------------------------------------------------------------ // Retrieves the next token std::string BVHLoader::GetNextToken() { - // skip any preceeding whitespace - while( mReader != mBuffer.end()) - { - if( !isspace( *mReader)) - break; - - // count lines - if( *mReader == '\n') - mLine++; - - ++mReader; - } - - // collect all chars till the next whitespace. BVH is easy in respect to that. - std::string token; - while( mReader != mBuffer.end()) - { - if( isspace( *mReader)) - break; - - token.push_back( *mReader); - ++mReader; - - // little extra logic to make sure braces are counted correctly - if( token == "{" || token == "}") - break; - } - - // empty token means end of file, which is just fine - return token; + // skip any preceding whitespace + while( mReader != mBuffer.end()) + { + if( !isspace( *mReader)) + break; + + // count lines + if( *mReader == '\n') + mLine++; + + ++mReader; + } + + // collect all chars till the next whitespace. BVH is easy in respect to that. + std::string token; + while( mReader != mBuffer.end()) + { + if( isspace( *mReader)) + break; + + token.push_back( *mReader); + ++mReader; + + // little extra logic to make sure braces are counted correctly + if( token == "{" || token == "}") + break; + } + + // empty token means end of file, which is just fine + return token; } // ------------------------------------------------------------------------------------------------ // Reads the next token as a float float BVHLoader::GetNextTokenAsFloat() { - std::string token = GetNextToken(); - if( token.empty()) - ThrowException( "Unexpected end of file while trying to read a float"); + std::string token = GetNextToken(); + if( token.empty()) + ThrowException( "Unexpected end of file while trying to read a float"); - // check if the float is valid by testing if the atof() function consumed every char of the token - const char* ctoken = token.c_str(); - float result = 0.0f; - ctoken = fast_atoreal_move<float>( ctoken, result); + // check if the float is valid by testing if the atof() function consumed every char of the token + const char* ctoken = token.c_str(); + float result = 0.0f; + ctoken = fast_atoreal_move<float>( ctoken, result); - if( ctoken != token.c_str() + token.length()) - ThrowException( boost::str( boost::format( "Expected a floating point number, but found \"%s\".") % token)); + if( ctoken != token.c_str() + token.length()) + ThrowException( format() << "Expected a floating point number, but found \"" << token << "\"." ); - return result; + return result; } // ------------------------------------------------------------------------------------------------ // Aborts the file reading with an exception -void BVHLoader::ThrowException( const std::string& pError) +AI_WONT_RETURN void BVHLoader::ThrowException( const std::string& pError) { - throw DeadlyImportError( boost::str( boost::format( "%s:%d - %s") % mFileName % mLine % pError)); + throw DeadlyImportError( format() << mFileName << ":" << mLine << " - " << pError); } // ------------------------------------------------------------------------------------------------ // Constructs an animation for the motion data and stores it in the given scene void BVHLoader::CreateAnimation( aiScene* pScene) { - // create the animation - pScene->mNumAnimations = 1; - pScene->mAnimations = new aiAnimation*[1]; - aiAnimation* anim = new aiAnimation; - pScene->mAnimations[0] = anim; - - // put down the basic parameters - anim->mName.Set( "Motion"); - anim->mTicksPerSecond = 1.0 / double( mAnimTickDuration); - anim->mDuration = double( mAnimNumFrames - 1); - - // now generate the tracks for all nodes - anim->mNumChannels = mNodes.size(); - anim->mChannels = new aiNodeAnim*[anim->mNumChannels]; - - // FIX: set the array elements to NULL to ensure proper deletion if an exception is thrown - for (unsigned int i = 0; i < anim->mNumChannels;++i) - anim->mChannels[i] = NULL; - - for( unsigned int a = 0; a < anim->mNumChannels; a++) - { - const Node& node = mNodes[a]; - const std::string nodeName = std::string( node.mNode->mName.data ); - aiNodeAnim* nodeAnim = new aiNodeAnim; - anim->mChannels[a] = nodeAnim; - nodeAnim->mNodeName.Set( nodeName); - - // translational part, if given - if( node.mChannels.size() == 6) - { - nodeAnim->mNumPositionKeys = mAnimNumFrames; - nodeAnim->mPositionKeys = new aiVectorKey[mAnimNumFrames]; - aiVectorKey* poskey = nodeAnim->mPositionKeys; - for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr) - { - poskey->mTime = double( fr); - - // Now compute all translations in the right order - for( unsigned int channel = 0; channel < 3; ++channel) - { - switch( node.mChannels[channel]) - { - case Channel_PositionX: poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + channel]; break; - case Channel_PositionY: poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + channel]; break; - case Channel_PositionZ: poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + channel]; break; - default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName ); - } - } - ++poskey; - } - } else - { - // if no translation part is given, put a default sequence - aiVector3D nodePos( node.mNode->mTransformation.a4, node.mNode->mTransformation.b4, node.mNode->mTransformation.c4); - nodeAnim->mNumPositionKeys = 1; - nodeAnim->mPositionKeys = new aiVectorKey[1]; - nodeAnim->mPositionKeys[0].mTime = 0.0; - nodeAnim->mPositionKeys[0].mValue = nodePos; - } - - // rotation part. Always present. First find value offsets - { - unsigned int rotOffset = 0; - if( node.mChannels.size() == 6) - { - // Offset all further calculations - rotOffset = 3; - } - - // Then create the number of rotation keys - nodeAnim->mNumRotationKeys = mAnimNumFrames; - nodeAnim->mRotationKeys = new aiQuatKey[mAnimNumFrames]; - aiQuatKey* rotkey = nodeAnim->mRotationKeys; - for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr) - { - aiMatrix4x4 temp; - aiMatrix3x3 rotMatrix; - - for( unsigned int channel = 0; channel < 3; ++channel) - { - // translate ZXY euler angels into a quaternion - const float angle = node.mChannelValues[fr * node.mChannels.size() + rotOffset + channel] * float( AI_MATH_PI) / 180.0f; - - // Compute rotation transformations in the right order - switch (node.mChannels[rotOffset+channel]) - { - case Channel_RotationX: aiMatrix4x4::RotationX( angle, temp); rotMatrix *= aiMatrix3x3( temp); break; - case Channel_RotationY: aiMatrix4x4::RotationY( angle, temp); rotMatrix *= aiMatrix3x3( temp); break; - case Channel_RotationZ: aiMatrix4x4::RotationZ( angle, temp); rotMatrix *= aiMatrix3x3( temp); break; - default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName ); - } - } - - rotkey->mTime = double( fr); - rotkey->mValue = aiQuaternion( rotMatrix); - ++rotkey; - } - } - - // scaling part. Always just a default track - { - nodeAnim->mNumScalingKeys = 1; - nodeAnim->mScalingKeys = new aiVectorKey[1]; - nodeAnim->mScalingKeys[0].mTime = 0.0; - nodeAnim->mScalingKeys[0].mValue.Set( 1.0f, 1.0f, 1.0f); - } - } + // create the animation + pScene->mNumAnimations = 1; + pScene->mAnimations = new aiAnimation*[1]; + aiAnimation* anim = new aiAnimation; + pScene->mAnimations[0] = anim; + + // put down the basic parameters + anim->mName.Set( "Motion"); + anim->mTicksPerSecond = 1.0 / double( mAnimTickDuration); + anim->mDuration = double( mAnimNumFrames - 1); + + // now generate the tracks for all nodes + anim->mNumChannels = mNodes.size(); + anim->mChannels = new aiNodeAnim*[anim->mNumChannels]; + + // FIX: set the array elements to NULL to ensure proper deletion if an exception is thrown + for (unsigned int i = 0; i < anim->mNumChannels;++i) + anim->mChannels[i] = NULL; + + for( unsigned int a = 0; a < anim->mNumChannels; a++) + { + const Node& node = mNodes[a]; + const std::string nodeName = std::string( node.mNode->mName.data ); + aiNodeAnim* nodeAnim = new aiNodeAnim; + anim->mChannels[a] = nodeAnim; + nodeAnim->mNodeName.Set( nodeName); + + // translational part, if given + if( node.mChannels.size() == 6) + { + nodeAnim->mNumPositionKeys = mAnimNumFrames; + nodeAnim->mPositionKeys = new aiVectorKey[mAnimNumFrames]; + aiVectorKey* poskey = nodeAnim->mPositionKeys; + for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr) + { + poskey->mTime = double( fr); + + // Now compute all translations in the right order + for( unsigned int channel = 0; channel < 3; ++channel) + { + switch( node.mChannels[channel]) + { + case Channel_PositionX: poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + channel]; break; + case Channel_PositionY: poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + channel]; break; + case Channel_PositionZ: poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + channel]; break; + default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName ); + } + } + ++poskey; + } + } else + { + // if no translation part is given, put a default sequence + aiVector3D nodePos( node.mNode->mTransformation.a4, node.mNode->mTransformation.b4, node.mNode->mTransformation.c4); + nodeAnim->mNumPositionKeys = 1; + nodeAnim->mPositionKeys = new aiVectorKey[1]; + nodeAnim->mPositionKeys[0].mTime = 0.0; + nodeAnim->mPositionKeys[0].mValue = nodePos; + } + + // rotation part. Always present. First find value offsets + { + unsigned int rotOffset = 0; + if( node.mChannels.size() == 6) + { + // Offset all further calculations + rotOffset = 3; + } + + // Then create the number of rotation keys + nodeAnim->mNumRotationKeys = mAnimNumFrames; + nodeAnim->mRotationKeys = new aiQuatKey[mAnimNumFrames]; + aiQuatKey* rotkey = nodeAnim->mRotationKeys; + for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr) + { + aiMatrix4x4 temp; + aiMatrix3x3 rotMatrix; + + for( unsigned int channel = 0; channel < 3; ++channel) + { + // translate ZXY euler angels into a quaternion + const float angle = node.mChannelValues[fr * node.mChannels.size() + rotOffset + channel] * float( AI_MATH_PI) / 180.0f; + + // Compute rotation transformations in the right order + switch (node.mChannels[rotOffset+channel]) + { + case Channel_RotationX: aiMatrix4x4::RotationX( angle, temp); rotMatrix *= aiMatrix3x3( temp); break; + case Channel_RotationY: aiMatrix4x4::RotationY( angle, temp); rotMatrix *= aiMatrix3x3( temp); break; + case Channel_RotationZ: aiMatrix4x4::RotationZ( angle, temp); rotMatrix *= aiMatrix3x3( temp); break; + default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName ); + } + } + + rotkey->mTime = double( fr); + rotkey->mValue = aiQuaternion( rotMatrix); + ++rotkey; + } + } + + // scaling part. Always just a default track + { + nodeAnim->mNumScalingKeys = 1; + nodeAnim->mScalingKeys = new aiVectorKey[1]; + nodeAnim->mScalingKeys[0].mTime = 0.0; + nodeAnim->mScalingKeys[0].mValue.Set( 1.0f, 1.0f, 1.0f); + } + } } #endif // !! ASSIMP_BUILD_NO_BVH_IMPORTER |