vrshoot

annotate libs/assimp/BVHLoader.cpp @ 0:b2f14e535253

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 01 Feb 2014 19:58:19 +0200
parents
children
rev   line source
nuclear@0 1 /** Implementation of the BVH loader */
nuclear@0 2 /*
nuclear@0 3 ---------------------------------------------------------------------------
nuclear@0 4 Open Asset Import Library (assimp)
nuclear@0 5 ---------------------------------------------------------------------------
nuclear@0 6
nuclear@0 7 Copyright (c) 2006-2012, assimp team
nuclear@0 8
nuclear@0 9 All rights reserved.
nuclear@0 10
nuclear@0 11 Redistribution and use of this software in source and binary forms,
nuclear@0 12 with or without modification, are permitted provided that the following
nuclear@0 13 conditions are met:
nuclear@0 14
nuclear@0 15 * Redistributions of source code must retain the above
nuclear@0 16 copyright notice, this list of conditions and the
nuclear@0 17 following disclaimer.
nuclear@0 18
nuclear@0 19 * Redistributions in binary form must reproduce the above
nuclear@0 20 copyright notice, this list of conditions and the
nuclear@0 21 following disclaimer in the documentation and/or other
nuclear@0 22 materials provided with the distribution.
nuclear@0 23
nuclear@0 24 * Neither the name of the assimp team, nor the names of its
nuclear@0 25 contributors may be used to endorse or promote products
nuclear@0 26 derived from this software without specific prior
nuclear@0 27 written permission of the assimp team.
nuclear@0 28
nuclear@0 29 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
nuclear@0 30 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
nuclear@0 31 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
nuclear@0 32 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
nuclear@0 33 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
nuclear@0 34 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
nuclear@0 35 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
nuclear@0 36 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
nuclear@0 37 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
nuclear@0 38 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
nuclear@0 39 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
nuclear@0 40 ---------------------------------------------------------------------------
nuclear@0 41 */
nuclear@0 42
nuclear@0 43 #include "AssimpPCH.h"
nuclear@0 44 #ifndef ASSIMP_BUILD_NO_BVH_IMPORTER
nuclear@0 45
nuclear@0 46 #include "BVHLoader.h"
nuclear@0 47 #include "fast_atof.h"
nuclear@0 48 #include "SkeletonMeshBuilder.h"
nuclear@0 49
nuclear@0 50 using namespace Assimp;
nuclear@0 51
nuclear@0 52 static const aiImporterDesc desc = {
nuclear@0 53 "BVH Importer (MoCap)",
nuclear@0 54 "",
nuclear@0 55 "",
nuclear@0 56 "",
nuclear@0 57 aiImporterFlags_SupportTextFlavour,
nuclear@0 58 0,
nuclear@0 59 0,
nuclear@0 60 0,
nuclear@0 61 0,
nuclear@0 62 "bvh"
nuclear@0 63 };
nuclear@0 64
nuclear@0 65 // ------------------------------------------------------------------------------------------------
nuclear@0 66 // Constructor to be privately used by Importer
nuclear@0 67 BVHLoader::BVHLoader()
nuclear@0 68 : noSkeletonMesh()
nuclear@0 69 {}
nuclear@0 70
nuclear@0 71 // ------------------------------------------------------------------------------------------------
nuclear@0 72 // Destructor, private as well
nuclear@0 73 BVHLoader::~BVHLoader()
nuclear@0 74 {}
nuclear@0 75
nuclear@0 76 // ------------------------------------------------------------------------------------------------
nuclear@0 77 // Returns whether the class can handle the format of the given file.
nuclear@0 78 bool BVHLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const
nuclear@0 79 {
nuclear@0 80 // check file extension
nuclear@0 81 const std::string extension = GetExtension(pFile);
nuclear@0 82
nuclear@0 83 if( extension == "bvh")
nuclear@0 84 return true;
nuclear@0 85
nuclear@0 86 if ((!extension.length() || cs) && pIOHandler) {
nuclear@0 87 const char* tokens[] = {"HIERARCHY"};
nuclear@0 88 return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
nuclear@0 89 }
nuclear@0 90 return false;
nuclear@0 91 }
nuclear@0 92
nuclear@0 93 // ------------------------------------------------------------------------------------------------
nuclear@0 94 void BVHLoader::SetupProperties(const Importer* pImp)
nuclear@0 95 {
nuclear@0 96 noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
nuclear@0 97 }
nuclear@0 98
nuclear@0 99 // ------------------------------------------------------------------------------------------------
nuclear@0 100 // Loader meta information
nuclear@0 101 const aiImporterDesc* BVHLoader::GetInfo () const
nuclear@0 102 {
nuclear@0 103 return &desc;
nuclear@0 104 }
nuclear@0 105
nuclear@0 106 // ------------------------------------------------------------------------------------------------
nuclear@0 107 // Imports the given file into the given scene structure.
nuclear@0 108 void BVHLoader::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
nuclear@0 109 {
nuclear@0 110 mFileName = pFile;
nuclear@0 111
nuclear@0 112 // read file into memory
nuclear@0 113 boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
nuclear@0 114 if( file.get() == NULL)
nuclear@0 115 throw DeadlyImportError( "Failed to open file " + pFile + ".");
nuclear@0 116
nuclear@0 117 size_t fileSize = file->FileSize();
nuclear@0 118 if( fileSize == 0)
nuclear@0 119 throw DeadlyImportError( "File is too small.");
nuclear@0 120
nuclear@0 121 mBuffer.resize( fileSize);
nuclear@0 122 file->Read( &mBuffer.front(), 1, fileSize);
nuclear@0 123
nuclear@0 124 // start reading
nuclear@0 125 mReader = mBuffer.begin();
nuclear@0 126 mLine = 1;
nuclear@0 127 ReadStructure( pScene);
nuclear@0 128
nuclear@0 129 if (!noSkeletonMesh) {
nuclear@0 130 // build a dummy mesh for the skeleton so that we see something at least
nuclear@0 131 SkeletonMeshBuilder meshBuilder( pScene);
nuclear@0 132 }
nuclear@0 133
nuclear@0 134 // construct an animation from all the motion data we read
nuclear@0 135 CreateAnimation( pScene);
nuclear@0 136 }
nuclear@0 137
nuclear@0 138 // ------------------------------------------------------------------------------------------------
nuclear@0 139 // Reads the file
nuclear@0 140 void BVHLoader::ReadStructure( aiScene* pScene)
nuclear@0 141 {
nuclear@0 142 // first comes hierarchy
nuclear@0 143 std::string header = GetNextToken();
nuclear@0 144 if( header != "HIERARCHY")
nuclear@0 145 ThrowException( "Expected header string \"HIERARCHY\".");
nuclear@0 146 ReadHierarchy( pScene);
nuclear@0 147
nuclear@0 148 // then comes the motion data
nuclear@0 149 std::string motion = GetNextToken();
nuclear@0 150 if( motion != "MOTION")
nuclear@0 151 ThrowException( "Expected beginning of motion data \"MOTION\".");
nuclear@0 152 ReadMotion( pScene);
nuclear@0 153 }
nuclear@0 154
nuclear@0 155 // ------------------------------------------------------------------------------------------------
nuclear@0 156 // Reads the hierarchy
nuclear@0 157 void BVHLoader::ReadHierarchy( aiScene* pScene)
nuclear@0 158 {
nuclear@0 159 std::string root = GetNextToken();
nuclear@0 160 if( root != "ROOT")
nuclear@0 161 ThrowException( "Expected root node \"ROOT\".");
nuclear@0 162
nuclear@0 163 // Go read the hierarchy from here
nuclear@0 164 pScene->mRootNode = ReadNode();
nuclear@0 165 }
nuclear@0 166
nuclear@0 167 // ------------------------------------------------------------------------------------------------
nuclear@0 168 // Reads a node and recursively its childs and returns the created node;
nuclear@0 169 aiNode* BVHLoader::ReadNode()
nuclear@0 170 {
nuclear@0 171 // first token is name
nuclear@0 172 std::string nodeName = GetNextToken();
nuclear@0 173 if( nodeName.empty() || nodeName == "{")
nuclear@0 174 ThrowException( boost::str( boost::format( "Expected node name, but found \"%s\".") % nodeName));
nuclear@0 175
nuclear@0 176 // then an opening brace should follow
nuclear@0 177 std::string openBrace = GetNextToken();
nuclear@0 178 if( openBrace != "{")
nuclear@0 179 ThrowException( boost::str( boost::format( "Expected opening brace \"{\", but found \"%s\".") % openBrace));
nuclear@0 180
nuclear@0 181 // Create a node
nuclear@0 182 aiNode* node = new aiNode( nodeName);
nuclear@0 183 std::vector<aiNode*> childNodes;
nuclear@0 184
nuclear@0 185 // and create an bone entry for it
nuclear@0 186 mNodes.push_back( Node( node));
nuclear@0 187 Node& internNode = mNodes.back();
nuclear@0 188
nuclear@0 189 // now read the node's contents
nuclear@0 190 while( 1)
nuclear@0 191 {
nuclear@0 192 std::string token = GetNextToken();
nuclear@0 193
nuclear@0 194 // node offset to parent node
nuclear@0 195 if( token == "OFFSET")
nuclear@0 196 ReadNodeOffset( node);
nuclear@0 197 else if( token == "CHANNELS")
nuclear@0 198 ReadNodeChannels( internNode);
nuclear@0 199 else if( token == "JOINT")
nuclear@0 200 {
nuclear@0 201 // child node follows
nuclear@0 202 aiNode* child = ReadNode();
nuclear@0 203 child->mParent = node;
nuclear@0 204 childNodes.push_back( child);
nuclear@0 205 }
nuclear@0 206 else if( token == "End")
nuclear@0 207 {
nuclear@0 208 // The real symbol is "End Site". Second part comes in a separate token
nuclear@0 209 std::string siteToken = GetNextToken();
nuclear@0 210 if( siteToken != "Site")
nuclear@0 211 ThrowException( boost::str( boost::format( "Expected \"End Site\" keyword, but found \"%s %s\".") % token % siteToken));
nuclear@0 212
nuclear@0 213 aiNode* child = ReadEndSite( nodeName);
nuclear@0 214 child->mParent = node;
nuclear@0 215 childNodes.push_back( child);
nuclear@0 216 }
nuclear@0 217 else if( token == "}")
nuclear@0 218 {
nuclear@0 219 // we're done with that part of the hierarchy
nuclear@0 220 break;
nuclear@0 221 } else
nuclear@0 222 {
nuclear@0 223 // everything else is a parse error
nuclear@0 224 ThrowException( boost::str( boost::format( "Unknown keyword \"%s\".") % token));
nuclear@0 225 }
nuclear@0 226 }
nuclear@0 227
nuclear@0 228 // add the child nodes if there are any
nuclear@0 229 if( childNodes.size() > 0)
nuclear@0 230 {
nuclear@0 231 node->mNumChildren = childNodes.size();
nuclear@0 232 node->mChildren = new aiNode*[node->mNumChildren];
nuclear@0 233 std::copy( childNodes.begin(), childNodes.end(), node->mChildren);
nuclear@0 234 }
nuclear@0 235
nuclear@0 236 // and return the sub-hierarchy we built here
nuclear@0 237 return node;
nuclear@0 238 }
nuclear@0 239
nuclear@0 240 // ------------------------------------------------------------------------------------------------
nuclear@0 241 // Reads an end node and returns the created node.
nuclear@0 242 aiNode* BVHLoader::ReadEndSite( const std::string& pParentName)
nuclear@0 243 {
nuclear@0 244 // check opening brace
nuclear@0 245 std::string openBrace = GetNextToken();
nuclear@0 246 if( openBrace != "{")
nuclear@0 247 ThrowException( boost::str( boost::format( "Expected opening brace \"{\", but found \"%s\".") % openBrace));
nuclear@0 248
nuclear@0 249 // Create a node
nuclear@0 250 aiNode* node = new aiNode( "EndSite_" + pParentName);
nuclear@0 251
nuclear@0 252 // now read the node's contents. Only possible entry is "OFFSET"
nuclear@0 253 while( 1)
nuclear@0 254 {
nuclear@0 255 std::string token = GetNextToken();
nuclear@0 256
nuclear@0 257 // end node's offset
nuclear@0 258 if( token == "OFFSET")
nuclear@0 259 {
nuclear@0 260 ReadNodeOffset( node);
nuclear@0 261 }
nuclear@0 262 else if( token == "}")
nuclear@0 263 {
nuclear@0 264 // we're done with the end node
nuclear@0 265 break;
nuclear@0 266 } else
nuclear@0 267 {
nuclear@0 268 // everything else is a parse error
nuclear@0 269 ThrowException( boost::str( boost::format( "Unknown keyword \"%s\".") % token));
nuclear@0 270 }
nuclear@0 271 }
nuclear@0 272
nuclear@0 273 // and return the sub-hierarchy we built here
nuclear@0 274 return node;
nuclear@0 275 }
nuclear@0 276 // ------------------------------------------------------------------------------------------------
nuclear@0 277 // Reads a node offset for the given node
nuclear@0 278 void BVHLoader::ReadNodeOffset( aiNode* pNode)
nuclear@0 279 {
nuclear@0 280 // Offset consists of three floats to read
nuclear@0 281 aiVector3D offset;
nuclear@0 282 offset.x = GetNextTokenAsFloat();
nuclear@0 283 offset.y = GetNextTokenAsFloat();
nuclear@0 284 offset.z = GetNextTokenAsFloat();
nuclear@0 285
nuclear@0 286 // build a transformation matrix from it
nuclear@0 287 pNode->mTransformation = aiMatrix4x4( 1.0f, 0.0f, 0.0f, offset.x, 0.0f, 1.0f, 0.0f, offset.y,
nuclear@0 288 0.0f, 0.0f, 1.0f, offset.z, 0.0f, 0.0f, 0.0f, 1.0f);
nuclear@0 289 }
nuclear@0 290
nuclear@0 291 // ------------------------------------------------------------------------------------------------
nuclear@0 292 // Reads the animation channels for the given node
nuclear@0 293 void BVHLoader::ReadNodeChannels( BVHLoader::Node& pNode)
nuclear@0 294 {
nuclear@0 295 // number of channels. Use the float reader because we're lazy
nuclear@0 296 float numChannelsFloat = GetNextTokenAsFloat();
nuclear@0 297 unsigned int numChannels = (unsigned int) numChannelsFloat;
nuclear@0 298
nuclear@0 299 for( unsigned int a = 0; a < numChannels; a++)
nuclear@0 300 {
nuclear@0 301 std::string channelToken = GetNextToken();
nuclear@0 302
nuclear@0 303 if( channelToken == "Xposition")
nuclear@0 304 pNode.mChannels.push_back( Channel_PositionX);
nuclear@0 305 else if( channelToken == "Yposition")
nuclear@0 306 pNode.mChannels.push_back( Channel_PositionY);
nuclear@0 307 else if( channelToken == "Zposition")
nuclear@0 308 pNode.mChannels.push_back( Channel_PositionZ);
nuclear@0 309 else if( channelToken == "Xrotation")
nuclear@0 310 pNode.mChannels.push_back( Channel_RotationX);
nuclear@0 311 else if( channelToken == "Yrotation")
nuclear@0 312 pNode.mChannels.push_back( Channel_RotationY);
nuclear@0 313 else if( channelToken == "Zrotation")
nuclear@0 314 pNode.mChannels.push_back( Channel_RotationZ);
nuclear@0 315 else
nuclear@0 316 ThrowException( boost::str( boost::format( "Invalid channel specifier \"%s\".") % channelToken));
nuclear@0 317 }
nuclear@0 318 }
nuclear@0 319
nuclear@0 320 // ------------------------------------------------------------------------------------------------
nuclear@0 321 // Reads the motion data
nuclear@0 322 void BVHLoader::ReadMotion( aiScene* /*pScene*/)
nuclear@0 323 {
nuclear@0 324 // Read number of frames
nuclear@0 325 std::string tokenFrames = GetNextToken();
nuclear@0 326 if( tokenFrames != "Frames:")
nuclear@0 327 ThrowException( boost::str( boost::format( "Expected frame count \"Frames:\", but found \"%s\".") % tokenFrames));
nuclear@0 328
nuclear@0 329 float numFramesFloat = GetNextTokenAsFloat();
nuclear@0 330 mAnimNumFrames = (unsigned int) numFramesFloat;
nuclear@0 331
nuclear@0 332 // Read frame duration
nuclear@0 333 std::string tokenDuration1 = GetNextToken();
nuclear@0 334 std::string tokenDuration2 = GetNextToken();
nuclear@0 335 if( tokenDuration1 != "Frame" || tokenDuration2 != "Time:")
nuclear@0 336 ThrowException( boost::str( boost::format( "Expected frame duration \"Frame Time:\", but found \"%s %s\".") % tokenDuration1 % tokenDuration2));
nuclear@0 337
nuclear@0 338 mAnimTickDuration = GetNextTokenAsFloat();
nuclear@0 339
nuclear@0 340 // resize value vectors for each node
nuclear@0 341 for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
nuclear@0 342 it->mChannelValues.reserve( it->mChannels.size() * mAnimNumFrames);
nuclear@0 343
nuclear@0 344 // now read all the data and store it in the corresponding node's value vector
nuclear@0 345 for( unsigned int frame = 0; frame < mAnimNumFrames; ++frame)
nuclear@0 346 {
nuclear@0 347 // on each line read the values for all nodes
nuclear@0 348 for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
nuclear@0 349 {
nuclear@0 350 // get as many values as the node has channels
nuclear@0 351 for( unsigned int c = 0; c < it->mChannels.size(); ++c)
nuclear@0 352 it->mChannelValues.push_back( GetNextTokenAsFloat());
nuclear@0 353 }
nuclear@0 354
nuclear@0 355 // after one frame worth of values for all nodes there should be a newline, but we better don't rely on it
nuclear@0 356 }
nuclear@0 357 }
nuclear@0 358
nuclear@0 359 // ------------------------------------------------------------------------------------------------
nuclear@0 360 // Retrieves the next token
nuclear@0 361 std::string BVHLoader::GetNextToken()
nuclear@0 362 {
nuclear@0 363 // skip any preceeding whitespace
nuclear@0 364 while( mReader != mBuffer.end())
nuclear@0 365 {
nuclear@0 366 if( !isspace( *mReader))
nuclear@0 367 break;
nuclear@0 368
nuclear@0 369 // count lines
nuclear@0 370 if( *mReader == '\n')
nuclear@0 371 mLine++;
nuclear@0 372
nuclear@0 373 ++mReader;
nuclear@0 374 }
nuclear@0 375
nuclear@0 376 // collect all chars till the next whitespace. BVH is easy in respect to that.
nuclear@0 377 std::string token;
nuclear@0 378 while( mReader != mBuffer.end())
nuclear@0 379 {
nuclear@0 380 if( isspace( *mReader))
nuclear@0 381 break;
nuclear@0 382
nuclear@0 383 token.push_back( *mReader);
nuclear@0 384 ++mReader;
nuclear@0 385
nuclear@0 386 // little extra logic to make sure braces are counted correctly
nuclear@0 387 if( token == "{" || token == "}")
nuclear@0 388 break;
nuclear@0 389 }
nuclear@0 390
nuclear@0 391 // empty token means end of file, which is just fine
nuclear@0 392 return token;
nuclear@0 393 }
nuclear@0 394
nuclear@0 395 // ------------------------------------------------------------------------------------------------
nuclear@0 396 // Reads the next token as a float
nuclear@0 397 float BVHLoader::GetNextTokenAsFloat()
nuclear@0 398 {
nuclear@0 399 std::string token = GetNextToken();
nuclear@0 400 if( token.empty())
nuclear@0 401 ThrowException( "Unexpected end of file while trying to read a float");
nuclear@0 402
nuclear@0 403 // check if the float is valid by testing if the atof() function consumed every char of the token
nuclear@0 404 const char* ctoken = token.c_str();
nuclear@0 405 float result = 0.0f;
nuclear@0 406 ctoken = fast_atoreal_move<float>( ctoken, result);
nuclear@0 407
nuclear@0 408 if( ctoken != token.c_str() + token.length())
nuclear@0 409 ThrowException( boost::str( boost::format( "Expected a floating point number, but found \"%s\".") % token));
nuclear@0 410
nuclear@0 411 return result;
nuclear@0 412 }
nuclear@0 413
nuclear@0 414 // ------------------------------------------------------------------------------------------------
nuclear@0 415 // Aborts the file reading with an exception
nuclear@0 416 void BVHLoader::ThrowException( const std::string& pError)
nuclear@0 417 {
nuclear@0 418 throw DeadlyImportError( boost::str( boost::format( "%s:%d - %s") % mFileName % mLine % pError));
nuclear@0 419 }
nuclear@0 420
nuclear@0 421 // ------------------------------------------------------------------------------------------------
nuclear@0 422 // Constructs an animation for the motion data and stores it in the given scene
nuclear@0 423 void BVHLoader::CreateAnimation( aiScene* pScene)
nuclear@0 424 {
nuclear@0 425 // create the animation
nuclear@0 426 pScene->mNumAnimations = 1;
nuclear@0 427 pScene->mAnimations = new aiAnimation*[1];
nuclear@0 428 aiAnimation* anim = new aiAnimation;
nuclear@0 429 pScene->mAnimations[0] = anim;
nuclear@0 430
nuclear@0 431 // put down the basic parameters
nuclear@0 432 anim->mName.Set( "Motion");
nuclear@0 433 anim->mTicksPerSecond = 1.0 / double( mAnimTickDuration);
nuclear@0 434 anim->mDuration = double( mAnimNumFrames - 1);
nuclear@0 435
nuclear@0 436 // now generate the tracks for all nodes
nuclear@0 437 anim->mNumChannels = mNodes.size();
nuclear@0 438 anim->mChannels = new aiNodeAnim*[anim->mNumChannels];
nuclear@0 439
nuclear@0 440 // FIX: set the array elements to NULL to ensure proper deletion if an exception is thrown
nuclear@0 441 for (unsigned int i = 0; i < anim->mNumChannels;++i)
nuclear@0 442 anim->mChannels[i] = NULL;
nuclear@0 443
nuclear@0 444 for( unsigned int a = 0; a < anim->mNumChannels; a++)
nuclear@0 445 {
nuclear@0 446 const Node& node = mNodes[a];
nuclear@0 447 const std::string nodeName = std::string( node.mNode->mName.data );
nuclear@0 448 aiNodeAnim* nodeAnim = new aiNodeAnim;
nuclear@0 449 anim->mChannels[a] = nodeAnim;
nuclear@0 450 nodeAnim->mNodeName.Set( nodeName);
nuclear@0 451
nuclear@0 452 // translational part, if given
nuclear@0 453 if( node.mChannels.size() == 6)
nuclear@0 454 {
nuclear@0 455 nodeAnim->mNumPositionKeys = mAnimNumFrames;
nuclear@0 456 nodeAnim->mPositionKeys = new aiVectorKey[mAnimNumFrames];
nuclear@0 457 aiVectorKey* poskey = nodeAnim->mPositionKeys;
nuclear@0 458 for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr)
nuclear@0 459 {
nuclear@0 460 poskey->mTime = double( fr);
nuclear@0 461
nuclear@0 462 // Now compute all translations in the right order
nuclear@0 463 for( unsigned int channel = 0; channel < 3; ++channel)
nuclear@0 464 {
nuclear@0 465 switch( node.mChannels[channel])
nuclear@0 466 {
nuclear@0 467 case Channel_PositionX: poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + channel]; break;
nuclear@0 468 case Channel_PositionY: poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + channel]; break;
nuclear@0 469 case Channel_PositionZ: poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + channel]; break;
nuclear@0 470 default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName );
nuclear@0 471 }
nuclear@0 472 }
nuclear@0 473 ++poskey;
nuclear@0 474 }
nuclear@0 475 } else
nuclear@0 476 {
nuclear@0 477 // if no translation part is given, put a default sequence
nuclear@0 478 aiVector3D nodePos( node.mNode->mTransformation.a4, node.mNode->mTransformation.b4, node.mNode->mTransformation.c4);
nuclear@0 479 nodeAnim->mNumPositionKeys = 1;
nuclear@0 480 nodeAnim->mPositionKeys = new aiVectorKey[1];
nuclear@0 481 nodeAnim->mPositionKeys[0].mTime = 0.0;
nuclear@0 482 nodeAnim->mPositionKeys[0].mValue = nodePos;
nuclear@0 483 }
nuclear@0 484
nuclear@0 485 // rotation part. Always present. First find value offsets
nuclear@0 486 {
nuclear@0 487 unsigned int rotOffset = 0;
nuclear@0 488 if( node.mChannels.size() == 6)
nuclear@0 489 {
nuclear@0 490 // Offset all further calculations
nuclear@0 491 rotOffset = 3;
nuclear@0 492 }
nuclear@0 493
nuclear@0 494 // Then create the number of rotation keys
nuclear@0 495 nodeAnim->mNumRotationKeys = mAnimNumFrames;
nuclear@0 496 nodeAnim->mRotationKeys = new aiQuatKey[mAnimNumFrames];
nuclear@0 497 aiQuatKey* rotkey = nodeAnim->mRotationKeys;
nuclear@0 498 for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr)
nuclear@0 499 {
nuclear@0 500 aiMatrix4x4 temp;
nuclear@0 501 aiMatrix3x3 rotMatrix;
nuclear@0 502
nuclear@0 503 for( unsigned int channel = 0; channel < 3; ++channel)
nuclear@0 504 {
nuclear@0 505 // translate ZXY euler angels into a quaternion
nuclear@0 506 const float angle = node.mChannelValues[fr * node.mChannels.size() + rotOffset + channel] * float( AI_MATH_PI) / 180.0f;
nuclear@0 507
nuclear@0 508 // Compute rotation transformations in the right order
nuclear@0 509 switch (node.mChannels[rotOffset+channel])
nuclear@0 510 {
nuclear@0 511 case Channel_RotationX: aiMatrix4x4::RotationX( angle, temp); rotMatrix *= aiMatrix3x3( temp); break;
nuclear@0 512 case Channel_RotationY: aiMatrix4x4::RotationY( angle, temp); rotMatrix *= aiMatrix3x3( temp); break;
nuclear@0 513 case Channel_RotationZ: aiMatrix4x4::RotationZ( angle, temp); rotMatrix *= aiMatrix3x3( temp); break;
nuclear@0 514 default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName );
nuclear@0 515 }
nuclear@0 516 }
nuclear@0 517
nuclear@0 518 rotkey->mTime = double( fr);
nuclear@0 519 rotkey->mValue = aiQuaternion( rotMatrix);
nuclear@0 520 ++rotkey;
nuclear@0 521 }
nuclear@0 522 }
nuclear@0 523
nuclear@0 524 // scaling part. Always just a default track
nuclear@0 525 {
nuclear@0 526 nodeAnim->mNumScalingKeys = 1;
nuclear@0 527 nodeAnim->mScalingKeys = new aiVectorKey[1];
nuclear@0 528 nodeAnim->mScalingKeys[0].mTime = 0.0;
nuclear@0 529 nodeAnim->mScalingKeys[0].mValue.Set( 1.0f, 1.0f, 1.0f);
nuclear@0 530 }
nuclear@0 531 }
nuclear@0 532 }
nuclear@0 533
nuclear@0 534 #endif // !! ASSIMP_BUILD_NO_BVH_IMPORTER