Model loading and texturing
This commit is contained in:
578
thirdparty/assimp/code/BVH/BVHLoader.cpp
vendored
Normal file
578
thirdparty/assimp/code/BVH/BVHLoader.cpp
vendored
Normal file
@@ -0,0 +1,578 @@
|
||||
/** Implementation of the BVH loader */
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, 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
|
||||
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 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.
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_BVH_IMPORTER
|
||||
|
||||
#include "BVHLoader.h"
|
||||
#include <assimp/fast_atof.h>
|
||||
#include <assimp/SkeletonMeshBuilder.h>
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <memory>
|
||||
#include <assimp/TinyFormatter.h>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <map>
|
||||
|
||||
using namespace Assimp;
|
||||
using namespace Assimp::Formatter;
|
||||
|
||||
static const aiImporterDesc desc = {
|
||||
"BVH Importer (MoCap)",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
aiImporterFlags_SupportTextFlavour,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
"bvh"
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
BVHLoader::BVHLoader()
|
||||
: mLine(),
|
||||
mAnimTickDuration(),
|
||||
mAnimNumFrames(),
|
||||
noSkeletonMesh()
|
||||
{}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
BVHLoader::~BVHLoader()
|
||||
{}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// 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;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BVHLoader::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Loader meta information
|
||||
const aiImporterDesc* BVHLoader::GetInfo () const
|
||||
{
|
||||
return &desc;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Imports the given file into the given scene structure.
|
||||
void BVHLoader::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
|
||||
{
|
||||
mFileName = 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.");
|
||||
|
||||
mBuffer.resize( fileSize);
|
||||
file->Read( &mBuffer.front(), 1, fileSize);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads the hierarchy
|
||||
void BVHLoader::ReadHierarchy( aiScene* pScene)
|
||||
{
|
||||
std::string root = GetNextToken();
|
||||
if( root != "ROOT")
|
||||
ThrowException( "Expected root node \"ROOT\".");
|
||||
|
||||
// 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( 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
|
||||
std::string siteToken;
|
||||
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
|
||||
siteToken.clear();
|
||||
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 = static_cast<unsigned int>(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( 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"
|
||||
std::string token;
|
||||
while( 1) {
|
||||
token.clear();
|
||||
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);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// 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( 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( 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 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");
|
||||
|
||||
// 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( format() << "Expected a floating point number, but found \"" << token << "\"." );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Aborts the file reading with an exception
|
||||
AI_WONT_RETURN void BVHLoader::ThrowException( const std::string& 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 = static_cast<unsigned int>(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);
|
||||
std::map<BVHLoader::ChannelType, int> channelMap;
|
||||
|
||||
//Build map of channels
|
||||
for (unsigned int channel = 0; channel < node.mChannels.size(); ++channel)
|
||||
{
|
||||
channelMap[node.mChannels[channel]] = channel;
|
||||
}
|
||||
|
||||
// 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
|
||||
for(BVHLoader::ChannelType channel = Channel_PositionX; channel <= Channel_PositionZ; channel = (BVHLoader::ChannelType)(channel +1))
|
||||
{
|
||||
//Find channel in node
|
||||
std::map<BVHLoader::ChannelType, int>::iterator mapIter = channelMap.find(channel);
|
||||
|
||||
if (mapIter == channelMap.end())
|
||||
throw DeadlyImportError("Missing position channel in node " + nodeName);
|
||||
else {
|
||||
int channelIdx = mapIter->second;
|
||||
switch (channel) {
|
||||
case Channel_PositionX:
|
||||
poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + channelIdx];
|
||||
break;
|
||||
case Channel_PositionY:
|
||||
poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + channelIdx];
|
||||
break;
|
||||
case Channel_PositionZ:
|
||||
poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + channelIdx];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
++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
|
||||
{
|
||||
|
||||
// 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 (BVHLoader::ChannelType channel = Channel_RotationX; channel <= Channel_RotationZ; channel = (BVHLoader::ChannelType)(channel + 1))
|
||||
{
|
||||
//Find channel in node
|
||||
std::map<BVHLoader::ChannelType, int>::iterator mapIter = channelMap.find(channel);
|
||||
|
||||
if (mapIter == channelMap.end())
|
||||
throw DeadlyImportError("Missing rotation channel in node " + nodeName);
|
||||
else {
|
||||
int channelIdx = mapIter->second;
|
||||
// translate ZXY euler angels into a quaternion
|
||||
const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f;
|
||||
|
||||
// Compute rotation transformations in the right order
|
||||
switch (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:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
176
thirdparty/assimp/code/BVH/BVHLoader.h
vendored
Normal file
176
thirdparty/assimp/code/BVH/BVHLoader.h
vendored
Normal file
@@ -0,0 +1,176 @@
|
||||
/** Defines the BHV motion capturing loader class */
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, 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 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 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 BVHLoader.h
|
||||
* @brief Biovision BVH import
|
||||
*/
|
||||
|
||||
#ifndef AI_BVHLOADER_H_INC
|
||||
#define AI_BVHLOADER_H_INC
|
||||
|
||||
#include <assimp/BaseImporter.h>
|
||||
|
||||
struct aiNode;
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
/** Loader class to read Motion Capturing data from a .bvh file.
|
||||
*
|
||||
* This format only contains a hierarchy of joints and a series of keyframes for
|
||||
* the hierarchy. It contains no actual mesh data, but we generate a dummy mesh
|
||||
* inside the loader just to be able to see something.
|
||||
*/
|
||||
class BVHLoader : public BaseImporter
|
||||
{
|
||||
|
||||
/** Possible animation channels for which the motion data holds the values */
|
||||
enum ChannelType
|
||||
{
|
||||
Channel_PositionX,
|
||||
Channel_PositionY,
|
||||
Channel_PositionZ,
|
||||
Channel_RotationX,
|
||||
Channel_RotationY,
|
||||
Channel_RotationZ
|
||||
};
|
||||
|
||||
/** Collected list of node. Will be bones of the dummy mesh some day, addressed by their array index */
|
||||
struct Node
|
||||
{
|
||||
const aiNode* mNode;
|
||||
std::vector<ChannelType> mChannels;
|
||||
std::vector<float> mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames
|
||||
|
||||
Node()
|
||||
: mNode(nullptr)
|
||||
{ }
|
||||
|
||||
explicit Node( const aiNode* pNode) : mNode( pNode) { }
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
BVHLoader();
|
||||
~BVHLoader();
|
||||
|
||||
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, bool cs) const;
|
||||
|
||||
void SetupProperties(const Importer* pImp);
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
/** 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:
|
||||
/** Reads the file */
|
||||
void ReadStructure( aiScene* pScene);
|
||||
|
||||
/** Reads the hierarchy */
|
||||
void ReadHierarchy( aiScene* pScene);
|
||||
|
||||
/** Reads a node and recursively its childs and returns the created node. */
|
||||
aiNode* ReadNode();
|
||||
|
||||
/** Reads an end node and returns the created node. */
|
||||
aiNode* ReadEndSite( const std::string& pParentName);
|
||||
|
||||
/** Reads a node offset for the given node */
|
||||
void ReadNodeOffset( aiNode* pNode);
|
||||
|
||||
/** Reads the animation channels into the given node */
|
||||
void ReadNodeChannels( BVHLoader::Node& pNode);
|
||||
|
||||
/** Reads the motion data */
|
||||
void ReadMotion( aiScene* pScene);
|
||||
|
||||
/** Retrieves the next token */
|
||||
std::string GetNextToken();
|
||||
|
||||
/** Reads the next token as a float */
|
||||
float GetNextTokenAsFloat();
|
||||
|
||||
/** Aborts the file reading with an exception */
|
||||
AI_WONT_RETURN void ThrowException( const std::string& pError) AI_WONT_RETURN_SUFFIX;
|
||||
|
||||
/** Constructs an animation for the motion data and stores it in the given scene */
|
||||
void CreateAnimation( aiScene* pScene);
|
||||
|
||||
protected:
|
||||
/** Filename, for a verbose error message */
|
||||
std::string mFileName;
|
||||
|
||||
/** Buffer to hold the loaded file */
|
||||
std::vector<char> mBuffer;
|
||||
|
||||
/** Next char to read from the buffer */
|
||||
std::vector<char>::const_iterator mReader;
|
||||
|
||||
/** Current line, for error messages */
|
||||
unsigned int mLine;
|
||||
|
||||
/** Collected list of nodes. Will be bones of the dummy mesh some day, addressed by their array index.
|
||||
* Also contain the motion data for the node's channels
|
||||
*/
|
||||
std::vector<Node> mNodes;
|
||||
|
||||
/** basic Animation parameters */
|
||||
float mAnimTickDuration;
|
||||
unsigned int mAnimNumFrames;
|
||||
|
||||
bool noSkeletonMesh;
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
||||
#endif // AI_BVHLOADER_H_INC
|
||||
Reference in New Issue
Block a user