Externalize Assimp
This commit is contained in:
		
							
								
								
									
										578
									
								
								thirdparty/assimp/code/BVH/BVHLoader.cpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										578
									
								
								thirdparty/assimp/code/BVH/BVHLoader.cpp
									
									
									
									
										vendored
									
									
								
							@@ -1,578 +0,0 @@
 | 
			
		||||
/** 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
									
									
								
							
							
						
						
									
										176
									
								
								thirdparty/assimp/code/BVH/BVHLoader.h
									
									
									
									
										vendored
									
									
								
							@@ -1,176 +0,0 @@
 | 
			
		||||
/** 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