- Further work at the BVH loader. Still work in progress.
- Added a helper class to build a mesh for a meshless node hierarchy git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@189 67173fc5-114c-0410-ac8e-9d2fd5bffc1fpull/1/head
parent
a34378934d
commit
8271164d74
|
@ -13,18 +13,18 @@ with or without modification, are permitted provided that the following
|
||||||
conditions are met:
|
conditions are met:
|
||||||
|
|
||||||
* Redistributions of source code must retain the above
|
* Redistributions of source code must retain the above
|
||||||
copyright notice, this list of conditions and the
|
copyright notice, this list of conditions and the
|
||||||
following disclaimer.
|
following disclaimer.
|
||||||
|
|
||||||
* Redistributions in binary form must reproduce the above
|
* Redistributions in binary form must reproduce the above
|
||||||
copyright notice, this list of conditions and the
|
copyright notice, this list of conditions and the
|
||||||
following disclaimer in the documentation and/or other
|
following disclaimer in the documentation and/or other
|
||||||
materials provided with the distribution.
|
materials provided with the distribution.
|
||||||
|
|
||||||
* Neither the name of the ASSIMP team, nor the names of its
|
* Neither the name of the ASSIMP team, nor the names of its
|
||||||
contributors may be used to endorse or promote products
|
contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior
|
derived from this software without specific prior
|
||||||
written permission of the ASSIMP Development Team.
|
written permission of the ASSIMP Development Team.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
@ -41,8 +41,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "AssimpPCH.h"
|
#include "AssimpPCH.h"
|
||||||
|
#include "../include/aiAnim.h"
|
||||||
#include "BVHLoader.h"
|
#include "BVHLoader.h"
|
||||||
#include "fast_atof.h"
|
#include "fast_atof.h"
|
||||||
|
#include "SkeletonMeshBuilder.h"
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
|
||||||
|
@ -99,6 +101,12 @@ void BVHLoader::InternReadFile( const std::string& pFile, aiScene* pScene, IOSys
|
||||||
mReader = mBuffer.begin();
|
mReader = mBuffer.begin();
|
||||||
mLine = 1;
|
mLine = 1;
|
||||||
ReadStructure( pScene);
|
ReadStructure( pScene);
|
||||||
|
|
||||||
|
// 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -139,10 +147,6 @@ aiNode* BVHLoader::ReadNode()
|
||||||
if( nodeName.empty() || nodeName == "{")
|
if( nodeName.empty() || nodeName == "{")
|
||||||
ThrowException( boost::str( boost::format( "Expected node name, but found \"%s\".") % nodeName));
|
ThrowException( boost::str( boost::format( "Expected node name, but found \"%s\".") % nodeName));
|
||||||
|
|
||||||
// HACK: (thom) end nodes are called "End Site". If the name of the node is "Site", we know it's going to be an end node
|
|
||||||
if( nodeName == "Site")
|
|
||||||
nodeName = "End Site";
|
|
||||||
|
|
||||||
// then an opening brace should follow
|
// then an opening brace should follow
|
||||||
std::string openBrace = GetNextToken();
|
std::string openBrace = GetNextToken();
|
||||||
if( openBrace != "{")
|
if( openBrace != "{")
|
||||||
|
@ -152,30 +156,39 @@ aiNode* BVHLoader::ReadNode()
|
||||||
aiNode* node = new aiNode( nodeName);
|
aiNode* node = new aiNode( nodeName);
|
||||||
std::vector<aiNode*> childNodes;
|
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
|
// now read the node's contents
|
||||||
while( 1)
|
while( 1)
|
||||||
{
|
{
|
||||||
std::string token = GetNextToken();
|
std::string token = GetNextToken();
|
||||||
|
|
||||||
// node offset to parent node
|
// node offset to parent node
|
||||||
if( token == "OFFSET")
|
if( token == "OFFSET")
|
||||||
ReadNodeOffset( node);
|
ReadNodeOffset( node);
|
||||||
else if( token == "CHANNELS")
|
else if( token == "CHANNELS")
|
||||||
ReadNodeChannels( node);
|
ReadNodeChannels( internNode);
|
||||||
else if( token == "JOINT")
|
else if( token == "JOINT")
|
||||||
{
|
{
|
||||||
// child node follows
|
// child node follows
|
||||||
aiNode* child = ReadNode();
|
aiNode* child = ReadNode();
|
||||||
|
child->mParent = node;
|
||||||
childNodes.push_back( child);
|
childNodes.push_back( child);
|
||||||
} else
|
}
|
||||||
if( token == "End")
|
else if( token == "End")
|
||||||
{
|
{
|
||||||
// HACK: (thom) end child node follows. Full token is "End Site", then no name, then a node.
|
// The real symbol is "End Site". Second part comes in a separate token
|
||||||
// But I don't want to write another function for this, so I simply leave the "Site" for ReadNode() as a node name
|
std::string siteToken = GetNextToken();
|
||||||
aiNode* child = ReadNode();
|
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);
|
childNodes.push_back( child);
|
||||||
} else
|
}
|
||||||
if( token == "}")
|
else if( token == "}")
|
||||||
{
|
{
|
||||||
// we're done with that part of the hierarchy
|
// we're done with that part of the hierarchy
|
||||||
break;
|
break;
|
||||||
|
@ -198,6 +211,42 @@ aiNode* BVHLoader::ReadNode()
|
||||||
return node;
|
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;
|
||||||
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Reads a node offset for the given node
|
// Reads a node offset for the given node
|
||||||
void BVHLoader::ReadNodeOffset( aiNode* pNode)
|
void BVHLoader::ReadNodeOffset( aiNode* pNode)
|
||||||
|
@ -215,15 +264,31 @@ void BVHLoader::ReadNodeOffset( aiNode* pNode)
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Reads the animation channels for the given node
|
// Reads the animation channels for the given node
|
||||||
void BVHLoader::ReadNodeChannels( aiNode* pNode)
|
void BVHLoader::ReadNodeChannels( BVHLoader::Node& pNode)
|
||||||
{
|
{
|
||||||
// number of channels. Use the float reader because we're lazy
|
// number of channels. Use the float reader because we're lazy
|
||||||
float numChannelsFloat = GetNextTokenAsFloat();
|
float numChannelsFloat = GetNextTokenAsFloat();
|
||||||
unsigned int numChannels = (unsigned int) numChannelsFloat;
|
unsigned int numChannels = (unsigned int) numChannelsFloat;
|
||||||
|
|
||||||
// TODO: (thom) proper channel parsing. For the moment I just skip the number of tokens
|
|
||||||
for( unsigned int a = 0; a < numChannels; a++)
|
for( unsigned int a = 0; a < numChannels; a++)
|
||||||
GetNextToken();
|
{
|
||||||
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -236,7 +301,7 @@ void BVHLoader::ReadMotion( aiScene* pScene)
|
||||||
ThrowException( boost::str( boost::format( "Expected frame count \"Frames:\", but found \"%s\".") % tokenFrames));
|
ThrowException( boost::str( boost::format( "Expected frame count \"Frames:\", but found \"%s\".") % tokenFrames));
|
||||||
|
|
||||||
float numFramesFloat = GetNextTokenAsFloat();
|
float numFramesFloat = GetNextTokenAsFloat();
|
||||||
unsigned int numFrames = (unsigned int) numFramesFloat;
|
mAnimNumFrames = (unsigned int) numFramesFloat;
|
||||||
|
|
||||||
// Read frame duration
|
// Read frame duration
|
||||||
std::string tokenDuration1 = GetNextToken();
|
std::string tokenDuration1 = GetNextToken();
|
||||||
|
@ -244,11 +309,25 @@ void BVHLoader::ReadMotion( aiScene* pScene)
|
||||||
if( tokenDuration1 != "Frame" || tokenDuration2 != "Time:")
|
if( tokenDuration1 != "Frame" || tokenDuration2 != "Time:")
|
||||||
ThrowException( boost::str( boost::format( "Expected frame duration \"Frame Time:\", but found \"%s %s\".") % tokenDuration1 % tokenDuration2));
|
ThrowException( boost::str( boost::format( "Expected frame duration \"Frame Time:\", but found \"%s %s\".") % tokenDuration1 % tokenDuration2));
|
||||||
|
|
||||||
float frameDuration = GetNextTokenAsFloat();
|
mAnimTickDuration = GetNextTokenAsFloat();
|
||||||
|
|
||||||
// resize value array accordingly
|
// resize value vectors for each node
|
||||||
// ************* Continue here ********
|
for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
|
||||||
//mMotionValues.resize( boost::extents[numFrames][numChannels]);
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -312,3 +391,118 @@ void BVHLoader::ThrowException( const std::string& pError)
|
||||||
{
|
{
|
||||||
throw new ImportErrorException( boost::str( boost::format( "%s:%d - %s") % mFileName % mLine % pError));
|
throw new ImportErrorException( boost::str( boost::format( "%s:%d - %s") % 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];
|
||||||
|
for( unsigned int a = 0; a < anim->mNumChannels; a++)
|
||||||
|
{
|
||||||
|
const Node& node = mNodes[a];
|
||||||
|
const char* nodeName = node.mNode->mName.data;
|
||||||
|
aiNodeAnim* nodeAnim = new aiNodeAnim;
|
||||||
|
anim->mChannels[a] = nodeAnim;
|
||||||
|
nodeAnim->mNodeName.Set( std::string( nodeName));
|
||||||
|
|
||||||
|
// translational part, if given
|
||||||
|
if( node.mChannels.size() == 6)
|
||||||
|
{
|
||||||
|
if( node.mChannels[0] != Channel_PositionX || node.mChannels[1] != Channel_PositionY
|
||||||
|
|| node.mChannels[2] != Channel_PositionZ)
|
||||||
|
{
|
||||||
|
throw new ImportErrorException( boost::str( boost::format( "Unexpected animation "
|
||||||
|
"channel setup at node \"%s\".") % nodeName));
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeAnim->mNumPositionKeys = mAnimNumFrames;
|
||||||
|
nodeAnim->mPositionKeys = new aiVectorKey[mAnimNumFrames];
|
||||||
|
aiVectorKey* poskey = nodeAnim->mPositionKeys;
|
||||||
|
for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr)
|
||||||
|
{
|
||||||
|
poskey->mTime = double( fr);
|
||||||
|
poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + 0];
|
||||||
|
poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + 1];
|
||||||
|
poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + 2];
|
||||||
|
++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 = 2;
|
||||||
|
nodeAnim->mPositionKeys = new aiVectorKey[2];
|
||||||
|
nodeAnim->mPositionKeys[0].mTime = 0.0;
|
||||||
|
nodeAnim->mPositionKeys[0].mValue = nodePos;
|
||||||
|
nodeAnim->mPositionKeys[1].mTime = anim->mDuration;
|
||||||
|
nodeAnim->mPositionKeys[1].mValue = nodePos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rotation part. Always present. First find value offsets
|
||||||
|
{
|
||||||
|
unsigned int rotOffset = 0;
|
||||||
|
if( node.mChannels.size() == 6)
|
||||||
|
{
|
||||||
|
if( node.mChannels[3] != Channel_RotationZ || node.mChannels[4] != Channel_RotationX
|
||||||
|
|| node.mChannels[5] != Channel_RotationY)
|
||||||
|
{
|
||||||
|
throw new ImportErrorException( boost::str( boost::format( "Unexpected animation "
|
||||||
|
"channel setup at node \"%s\".") % nodeName));
|
||||||
|
}
|
||||||
|
rotOffset = 3;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
if( node.mChannels[0] != Channel_RotationZ || node.mChannels[1] != Channel_RotationX
|
||||||
|
|| node.mChannels[2] != Channel_RotationY || node.mChannels.size() != 3)
|
||||||
|
{
|
||||||
|
throw new ImportErrorException( boost::str( boost::format( "Unexpected animation "
|
||||||
|
"channel setup at node \"%s\".") % nodeName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
// translate ZXY euler angels into a quaternion
|
||||||
|
float angleZ = node.mChannelValues[fr * node.mChannels.size() + rotOffset + 0] * float( AI_MATH_PI) / 180.0f;
|
||||||
|
float angleX = node.mChannelValues[fr * node.mChannels.size() + rotOffset + 1] * float( AI_MATH_PI) / 180.0f;
|
||||||
|
float angleY = node.mChannelValues[fr * node.mChannels.size() + rotOffset + 2] * float( AI_MATH_PI) / 180.0f;
|
||||||
|
aiMatrix4x4 temp;
|
||||||
|
aiMatrix3x3 rotMatrix;
|
||||||
|
aiMatrix4x4::RotationX( angleX, temp); rotMatrix *= aiMatrix3x3( temp);
|
||||||
|
aiMatrix4x4::RotationY( angleY, temp); rotMatrix *= aiMatrix3x3( temp);
|
||||||
|
aiMatrix4x4::RotationZ( angleZ, temp); rotMatrix *= aiMatrix3x3( temp);
|
||||||
|
|
||||||
|
rotkey->mTime = double( fr);
|
||||||
|
rotkey->mValue = aiQuaternion( rotMatrix);
|
||||||
|
++rotkey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// scaling part. Always just a default track
|
||||||
|
{
|
||||||
|
nodeAnim->mNumScalingKeys = 2;
|
||||||
|
nodeAnim->mScalingKeys = new aiVectorKey[2];
|
||||||
|
nodeAnim->mScalingKeys[0].mTime = 0.0;
|
||||||
|
nodeAnim->mScalingKeys[0].mValue.Set( 1.0f, 1.0f, 1.0f);
|
||||||
|
nodeAnim->mScalingKeys[1].mTime = anim->mDuration;
|
||||||
|
nodeAnim->mScalingKeys[1].mValue.Set( 1.0f, 1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -44,7 +44,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#define AI_BVHLOADER_H_INC
|
#define AI_BVHLOADER_H_INC
|
||||||
|
|
||||||
#include "BaseImporter.h"
|
#include "BaseImporter.h"
|
||||||
#include <boost/multi_array.hpp>
|
|
||||||
|
|
||||||
namespace Assimp
|
namespace Assimp
|
||||||
{
|
{
|
||||||
|
@ -57,6 +56,28 @@ class BVHLoader : public BaseImporter
|
||||||
{
|
{
|
||||||
friend class Importer;
|
friend class Importer;
|
||||||
|
|
||||||
|
/** 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() { }
|
||||||
|
Node( const aiNode* pNode) : mNode( pNode) { }
|
||||||
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** Constructor to be privately used by Importer */
|
/** Constructor to be privately used by Importer */
|
||||||
BVHLoader();
|
BVHLoader();
|
||||||
|
@ -93,11 +114,14 @@ protected:
|
||||||
/** Reads a node and recursively its childs and returns the created node. */
|
/** Reads a node and recursively its childs and returns the created node. */
|
||||||
aiNode* ReadNode();
|
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 */
|
/** Reads a node offset for the given node */
|
||||||
void ReadNodeOffset( aiNode* pNode);
|
void ReadNodeOffset( aiNode* pNode);
|
||||||
|
|
||||||
/** Reads the animation channels for the given node */
|
/** Reads the animation channels into the given node */
|
||||||
void ReadNodeChannels( aiNode* pNode);
|
void ReadNodeChannels( BVHLoader::Node& pNode);
|
||||||
|
|
||||||
/** Reads the motion data */
|
/** Reads the motion data */
|
||||||
void ReadMotion( aiScene* pScene);
|
void ReadMotion( aiScene* pScene);
|
||||||
|
@ -111,6 +135,9 @@ protected:
|
||||||
/** Aborts the file reading with an exception */
|
/** Aborts the file reading with an exception */
|
||||||
void ThrowException( const std::string& pError);
|
void ThrowException( const std::string& pError);
|
||||||
|
|
||||||
|
/** Constructs an animation for the motion data and stores it in the given scene */
|
||||||
|
void CreateAnimation( aiScene* pScene);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** Filename, for a verbose error message */
|
/** Filename, for a verbose error message */
|
||||||
std::string mFileName;
|
std::string mFileName;
|
||||||
|
@ -124,8 +151,14 @@ protected:
|
||||||
/** Current line, for error messages */
|
/** Current line, for error messages */
|
||||||
unsigned int mLine;
|
unsigned int mLine;
|
||||||
|
|
||||||
/** motion values per frame */
|
/** Collected list of nodes. Will be bones of the dummy mesh some day, addressed by their array index.
|
||||||
boost::multi_array<float, 2> mMotionValues;
|
* Also contain the motion data for the node's channels
|
||||||
|
*/
|
||||||
|
std::vector<Node> mNodes;
|
||||||
|
|
||||||
|
/** basic Animation parameters */
|
||||||
|
float mAnimTickDuration;
|
||||||
|
unsigned int mAnimNumFrames;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end of namespace Assimp
|
} // end of namespace Assimp
|
||||||
|
|
|
@ -0,0 +1,238 @@
|
||||||
|
/** Implementation of a little class to construct a dummy mesh for a skeleton */
|
||||||
|
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (ASSIMP)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2008, ASSIMP Development 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 Development 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.
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "AssimpPCH.h"
|
||||||
|
#include "../include/aiScene.h"
|
||||||
|
#include "SkeletonMeshBuilder.h"
|
||||||
|
|
||||||
|
using namespace Assimp;
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// The constructor processes the given scene and adds a mesh there.
|
||||||
|
SkeletonMeshBuilder::SkeletonMeshBuilder( aiScene* pScene)
|
||||||
|
{
|
||||||
|
// nothing to do if there's mesh data already present at the scene
|
||||||
|
if( pScene->mNumMeshes > 0 || pScene->mRootNode == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// build some faces around each node
|
||||||
|
CreateGeometry( pScene->mRootNode);
|
||||||
|
|
||||||
|
// create a mesh to hold all the generated faces
|
||||||
|
pScene->mNumMeshes = 1;
|
||||||
|
pScene->mMeshes = new aiMesh*[1];
|
||||||
|
pScene->mMeshes[0] = CreateMesh();
|
||||||
|
// and install it at the root node
|
||||||
|
pScene->mRootNode->mNumMeshes = 1;
|
||||||
|
pScene->mRootNode->mMeshes = new unsigned int[1];
|
||||||
|
pScene->mRootNode->mMeshes[0] = 0;
|
||||||
|
|
||||||
|
// create a dummy material for the mesh
|
||||||
|
pScene->mNumMaterials = 1;
|
||||||
|
pScene->mMaterials = new aiMaterial*[1];
|
||||||
|
pScene->mMaterials[0] = CreateMaterial();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// Recursively builds a simple mesh representation for the given node
|
||||||
|
void SkeletonMeshBuilder::CreateGeometry( const aiNode* pNode)
|
||||||
|
{
|
||||||
|
// add a joint entry for the node.
|
||||||
|
const unsigned int boneIndex = mBones.size();
|
||||||
|
const unsigned int vertexStartIndex = mVertices.size();
|
||||||
|
|
||||||
|
// now build the geometry.
|
||||||
|
if( pNode->mNumChildren > 0)
|
||||||
|
{
|
||||||
|
// If the node has childs, we build little pointers to each of them
|
||||||
|
for( unsigned int a = 0; a < pNode->mNumChildren; a++)
|
||||||
|
{
|
||||||
|
// find a suitable coordinate system
|
||||||
|
const aiMatrix4x4& childTransform = pNode->mChildren[a]->mTransformation;
|
||||||
|
aiVector3D childpos( childTransform.a4, childTransform.b4, childTransform.c4);
|
||||||
|
float distanceToChild = childpos.Length();
|
||||||
|
aiVector3D up = aiVector3D( childpos).Normalize();
|
||||||
|
|
||||||
|
aiVector3D orth( 1.0f, 0.0f, 0.0f);
|
||||||
|
if( abs( orth * up) > 0.99f)
|
||||||
|
orth.Set( 0.0f, 1.0f, 0.0f);
|
||||||
|
|
||||||
|
aiVector3D front = (up ^ orth).Normalize();
|
||||||
|
aiVector3D side = (front ^ up).Normalize();
|
||||||
|
|
||||||
|
mVertices.push_back( -front * distanceToChild * 0.1f);
|
||||||
|
mVertices.push_back( childpos);
|
||||||
|
mVertices.push_back( -side * distanceToChild * 0.1f);
|
||||||
|
mVertices.push_back( -side * distanceToChild * 0.1f);
|
||||||
|
mVertices.push_back( childpos);
|
||||||
|
mVertices.push_back( front * distanceToChild * 0.1f);
|
||||||
|
mVertices.push_back( front * distanceToChild * 0.1f);
|
||||||
|
mVertices.push_back( childpos);
|
||||||
|
mVertices.push_back( side * distanceToChild * 0.1f);
|
||||||
|
mVertices.push_back( side * distanceToChild * 0.1f);
|
||||||
|
mVertices.push_back( childpos);
|
||||||
|
mVertices.push_back( -front * distanceToChild * 0.1f);
|
||||||
|
|
||||||
|
unsigned localVertexStart = vertexStartIndex + a * 12;
|
||||||
|
mFaces.push_back( Face( localVertexStart + 0, localVertexStart + 1, localVertexStart + 2));
|
||||||
|
mFaces.push_back( Face( localVertexStart + 3, localVertexStart + 4, localVertexStart + 5));
|
||||||
|
mFaces.push_back( Face( localVertexStart + 6, localVertexStart + 7, localVertexStart + 8));
|
||||||
|
mFaces.push_back( Face( localVertexStart + 9, localVertexStart + 10, localVertexStart + 11));
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
// if the node has no children, it's an end node. Put a little knob there instead
|
||||||
|
aiVector3D ownpos( pNode->mTransformation.a4, pNode->mTransformation.b4, pNode->mTransformation.c4);
|
||||||
|
float sizeEstimate = ownpos.Length() * 0.2f;
|
||||||
|
|
||||||
|
mVertices.push_back( aiVector3D( -sizeEstimate, 0.0f, 0.0f));
|
||||||
|
mVertices.push_back( aiVector3D( 0.0f, sizeEstimate, 0.0f));
|
||||||
|
mVertices.push_back( aiVector3D( 0.0f, 0.0f, -sizeEstimate));
|
||||||
|
mVertices.push_back( aiVector3D( 0.0f, sizeEstimate, 0.0f));
|
||||||
|
mVertices.push_back( aiVector3D( sizeEstimate, 0.0f, 0.0f));
|
||||||
|
mVertices.push_back( aiVector3D( 0.0f, 0.0f, -sizeEstimate));
|
||||||
|
mVertices.push_back( aiVector3D( sizeEstimate, 0.0f, 0.0f));
|
||||||
|
mVertices.push_back( aiVector3D( 0.0f, -sizeEstimate, 0.0f));
|
||||||
|
mVertices.push_back( aiVector3D( 0.0f, 0.0f, -sizeEstimate));
|
||||||
|
mVertices.push_back( aiVector3D( 0.0f, -sizeEstimate, 0.0f));
|
||||||
|
mVertices.push_back( aiVector3D( -sizeEstimate, 0.0f, 0.0f));
|
||||||
|
mVertices.push_back( aiVector3D( 0.0f, 0.0f, -sizeEstimate));
|
||||||
|
|
||||||
|
mVertices.push_back( aiVector3D( -sizeEstimate, 0.0f, 0.0f));
|
||||||
|
mVertices.push_back( aiVector3D( 0.0f, 0.0f, sizeEstimate));
|
||||||
|
mVertices.push_back( aiVector3D( 0.0f, sizeEstimate, 0.0f));
|
||||||
|
mVertices.push_back( aiVector3D( 0.0f, sizeEstimate, 0.0f));
|
||||||
|
mVertices.push_back( aiVector3D( 0.0f, 0.0f, sizeEstimate));
|
||||||
|
mVertices.push_back( aiVector3D( sizeEstimate, 0.0f, 0.0f));
|
||||||
|
mVertices.push_back( aiVector3D( sizeEstimate, 0.0f, 0.0f));
|
||||||
|
mVertices.push_back( aiVector3D( 0.0f, 0.0f, sizeEstimate));
|
||||||
|
mVertices.push_back( aiVector3D( 0.0f, -sizeEstimate, 0.0f));
|
||||||
|
mVertices.push_back( aiVector3D( 0.0f, -sizeEstimate, 0.0f));
|
||||||
|
mVertices.push_back( aiVector3D( 0.0f, 0.0f, sizeEstimate));
|
||||||
|
mVertices.push_back( aiVector3D( -sizeEstimate, 0.0f, 0.0f));
|
||||||
|
|
||||||
|
mFaces.push_back( Face( vertexStartIndex + 0, vertexStartIndex + 1, vertexStartIndex + 2));
|
||||||
|
mFaces.push_back( Face( vertexStartIndex + 3, vertexStartIndex + 4, vertexStartIndex + 5));
|
||||||
|
mFaces.push_back( Face( vertexStartIndex + 6, vertexStartIndex + 7, vertexStartIndex + 8));
|
||||||
|
mFaces.push_back( Face( vertexStartIndex + 9, vertexStartIndex + 10, vertexStartIndex + 11));
|
||||||
|
mFaces.push_back( Face( vertexStartIndex + 12, vertexStartIndex + 13, vertexStartIndex + 14));
|
||||||
|
mFaces.push_back( Face( vertexStartIndex + 15, vertexStartIndex + 16, vertexStartIndex + 17));
|
||||||
|
mFaces.push_back( Face( vertexStartIndex + 18, vertexStartIndex + 19, vertexStartIndex + 20));
|
||||||
|
mFaces.push_back( Face( vertexStartIndex + 21, vertexStartIndex + 22, vertexStartIndex + 23));
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a bone affecting all the newly created vertices
|
||||||
|
aiBone* bone = new aiBone;
|
||||||
|
mBones.push_back( bone);
|
||||||
|
bone->mName = pNode->mName;
|
||||||
|
|
||||||
|
// calculate the bone offset matrix by concatenating the inverse transformations of all parents
|
||||||
|
bone->mOffsetMatrix = aiMatrix4x4( pNode->mTransformation).Inverse();
|
||||||
|
for( aiNode* parent = pNode->mParent; parent != NULL; parent = parent->mParent)
|
||||||
|
bone->mOffsetMatrix = aiMatrix4x4( parent->mTransformation).Inverse() * bone->mOffsetMatrix;
|
||||||
|
|
||||||
|
// add all the vertices to the bone's influences
|
||||||
|
unsigned int numVertices = mVertices.size() - vertexStartIndex;
|
||||||
|
bone->mNumWeights = numVertices;
|
||||||
|
bone->mWeights = new aiVertexWeight[numVertices];
|
||||||
|
for( unsigned int a = 0; a < numVertices; a++)
|
||||||
|
bone->mWeights[a] = aiVertexWeight( vertexStartIndex + a, 1.0f);
|
||||||
|
|
||||||
|
// HACK: (thom) transform all vertices to the bone's local space. Should be done before adding
|
||||||
|
// them to the array, but I'm tired now and I'm annoyed.
|
||||||
|
aiMatrix4x4 boneToMeshTransform = aiMatrix4x4( bone->mOffsetMatrix).Inverse();
|
||||||
|
for( unsigned int a = vertexStartIndex; a < mVertices.size(); a++)
|
||||||
|
mVertices[a] = boneToMeshTransform * mVertices[a];
|
||||||
|
|
||||||
|
// and finally recurse into the children list
|
||||||
|
for( unsigned int a = 0; a < pNode->mNumChildren; a++)
|
||||||
|
CreateGeometry( pNode->mChildren[a]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// Creates the mesh from the internally accumulated stuff and returns it.
|
||||||
|
aiMesh* SkeletonMeshBuilder::CreateMesh()
|
||||||
|
{
|
||||||
|
aiMesh* mesh = new aiMesh();
|
||||||
|
|
||||||
|
// add points
|
||||||
|
mesh->mNumVertices = mVertices.size();
|
||||||
|
mesh->mVertices = new aiVector3D[mesh->mNumVertices];
|
||||||
|
std::copy( mVertices.begin(), mVertices.end(), mesh->mVertices);
|
||||||
|
|
||||||
|
// add faces
|
||||||
|
mesh->mNumFaces = mFaces.size();
|
||||||
|
mesh->mFaces = new aiFace[mesh->mNumFaces];
|
||||||
|
for( unsigned int a = 0; a < mesh->mNumFaces; a++)
|
||||||
|
{
|
||||||
|
const Face& inface = mFaces[a];
|
||||||
|
aiFace& outface = mesh->mFaces[a];
|
||||||
|
outface.mNumIndices = 3;
|
||||||
|
outface.mIndices = new unsigned int[3];
|
||||||
|
outface.mIndices[0] = inface.mIndices[0];
|
||||||
|
outface.mIndices[1] = inface.mIndices[1];
|
||||||
|
outface.mIndices[2] = inface.mIndices[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the bones
|
||||||
|
mesh->mNumBones = mBones.size();
|
||||||
|
mesh->mBones = new aiBone*[mesh->mNumBones];
|
||||||
|
std::copy( mBones.begin(), mBones.end(), mesh->mBones);
|
||||||
|
|
||||||
|
// default
|
||||||
|
mesh->mMaterialIndex = 0;
|
||||||
|
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// Creates a dummy material and returns it.
|
||||||
|
aiMaterial* SkeletonMeshBuilder::CreateMaterial()
|
||||||
|
{
|
||||||
|
Assimp::MaterialHelper* matHelper = new Assimp::MaterialHelper;
|
||||||
|
|
||||||
|
// Name
|
||||||
|
aiString matName( std::string( "Material"));
|
||||||
|
matHelper->AddProperty( &matName, AI_MATKEY_NAME);
|
||||||
|
|
||||||
|
return matHelper;
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
/** Helper class to construct a dummy mesh for file formats containing only motion data */
|
||||||
|
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (ASSIMP)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2008, ASSIMP Development 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 Development 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 AI_SKELETONMESHBUILDER_H_INC
|
||||||
|
#define AI_SKELETONMESHBUILDER_H_INC
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include "../include/aiMesh.h"
|
||||||
|
|
||||||
|
struct aiScene;
|
||||||
|
struct aiNode;
|
||||||
|
|
||||||
|
namespace Assimp
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This little helper class constructs a dummy mesh for a given scene
|
||||||
|
* the resembles the node hierarchy. This is useful for file formats
|
||||||
|
* that don't carry any mesh data but only animation data.
|
||||||
|
*/
|
||||||
|
class SkeletonMeshBuilder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** The constructor processes the given scene and adds a mesh there. Does nothing
|
||||||
|
* if the scene already has mesh data.
|
||||||
|
* @param pScene The scene for which a skeleton mesh should be constructed.
|
||||||
|
*/
|
||||||
|
SkeletonMeshBuilder( aiScene* pScene);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** Recursively builds a simple mesh representation for the given node and also creates
|
||||||
|
* a joint for the node that affects this part of the mesh.
|
||||||
|
* @param pNode The node to build geometry for.
|
||||||
|
*/
|
||||||
|
void CreateGeometry( const aiNode* pNode);
|
||||||
|
|
||||||
|
/** Creates the mesh from the internally accumulated stuff and returns it. */
|
||||||
|
aiMesh* CreateMesh();
|
||||||
|
|
||||||
|
/** Creates a dummy material and returns it. */
|
||||||
|
aiMaterial* CreateMaterial();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** space to assemble the mesh data: points */
|
||||||
|
std::vector<aiVector3D> mVertices;
|
||||||
|
|
||||||
|
/** faces */
|
||||||
|
struct Face
|
||||||
|
{
|
||||||
|
unsigned int mIndices[3];
|
||||||
|
Face();
|
||||||
|
Face( unsigned int p0, unsigned int p1, unsigned int p2)
|
||||||
|
{ mIndices[0] = p0; mIndices[1] = p1; mIndices[2] = p2; }
|
||||||
|
};
|
||||||
|
std::vector<Face> mFaces;
|
||||||
|
|
||||||
|
/** bones */
|
||||||
|
std::vector<aiBone*> mBones;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end of namespace Assimp
|
||||||
|
|
||||||
|
#endif // AI_SKELETONMESHBUILDER_H_INC
|
|
@ -128,7 +128,6 @@ struct aiMatrix4x4
|
||||||
*/
|
*/
|
||||||
static aiMatrix4x4& RotationX(float a, aiMatrix4x4& out);
|
static aiMatrix4x4& RotationX(float a, aiMatrix4x4& out);
|
||||||
|
|
||||||
|
|
||||||
/** \brief Returns a rotation matrix for a rotation around the y axis
|
/** \brief Returns a rotation matrix for a rotation around the y axis
|
||||||
* \param a Rotation angle, in radians
|
* \param a Rotation angle, in radians
|
||||||
* \param out Receives the output matrix
|
* \param out Receives the output matrix
|
||||||
|
@ -136,7 +135,6 @@ struct aiMatrix4x4
|
||||||
*/
|
*/
|
||||||
static aiMatrix4x4& RotationY(float a, aiMatrix4x4& out);
|
static aiMatrix4x4& RotationY(float a, aiMatrix4x4& out);
|
||||||
|
|
||||||
|
|
||||||
/** \brief Returns a rotation matrix for a rotation around the z axis
|
/** \brief Returns a rotation matrix for a rotation around the z axis
|
||||||
* \param a Rotation angle, in radians
|
* \param a Rotation angle, in radians
|
||||||
* \param out Receives the output matrix
|
* \param out Receives the output matrix
|
||||||
|
@ -144,13 +142,12 @@ struct aiMatrix4x4
|
||||||
*/
|
*/
|
||||||
static aiMatrix4x4& RotationZ(float a, aiMatrix4x4& out);
|
static aiMatrix4x4& RotationZ(float a, aiMatrix4x4& out);
|
||||||
|
|
||||||
|
|
||||||
/** \brief Returns a translation matrix
|
/** \brief Returns a translation matrix
|
||||||
* \param v Translation vector
|
* \param v Translation vector
|
||||||
* \param out Receives the output matrix
|
* \param out Receives the output matrix
|
||||||
* \return Reference to the output matrix
|
* \return Reference to the output matrix
|
||||||
*/
|
*/
|
||||||
static aiMatrix4x4& Translation(aiVector3D v, aiMatrix4x4& out);
|
static aiMatrix4x4& Translation( const aiVector3D& v, aiMatrix4x4& out);
|
||||||
|
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
|
|
@ -252,6 +252,7 @@ inline aiMatrix4x4& aiMatrix4x4::RotationX(float a, aiMatrix4x4& out)
|
||||||
out.b3 = -(out.c2 = sin(a));
|
out.b3 = -(out.c2 = sin(a));
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
inline aiMatrix4x4& aiMatrix4x4::RotationY(float a, aiMatrix4x4& out)
|
inline aiMatrix4x4& aiMatrix4x4::RotationY(float a, aiMatrix4x4& out)
|
||||||
{
|
{
|
||||||
|
@ -281,7 +282,7 @@ inline aiMatrix4x4& aiMatrix4x4::RotationZ(float a, aiMatrix4x4& out)
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
inline aiMatrix4x4& aiMatrix4x4::Translation(aiVector3D v, aiMatrix4x4& out)
|
inline aiMatrix4x4& aiMatrix4x4::Translation( const aiVector3D& v, aiMatrix4x4& out)
|
||||||
{
|
{
|
||||||
out = aiMatrix4x4();
|
out = aiMatrix4x4();
|
||||||
out.a4 = v.x;
|
out.a4 = v.x;
|
||||||
|
@ -290,6 +291,5 @@ inline aiMatrix4x4& aiMatrix4x4::Translation(aiVector3D v, aiMatrix4x4& out)
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
#endif // AI_MATRIX4x4_INL_INC
|
#endif // AI_MATRIX4x4_INL_INC
|
||||||
|
|
|
@ -1511,6 +1511,7 @@
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCCLCompilerTool"
|
Name="VCCLCompilerTool"
|
||||||
UsePrecompiledHeader="1"
|
UsePrecompiledHeader="1"
|
||||||
|
PrecompiledHeaderThrough="AssimpPCH.h"
|
||||||
/>
|
/>
|
||||||
</FileConfiguration>
|
</FileConfiguration>
|
||||||
<FileConfiguration
|
<FileConfiguration
|
||||||
|
@ -1519,6 +1520,7 @@
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCCLCompilerTool"
|
Name="VCCLCompilerTool"
|
||||||
UsePrecompiledHeader="1"
|
UsePrecompiledHeader="1"
|
||||||
|
PrecompiledHeaderThrough="AssimpPCH.h"
|
||||||
/>
|
/>
|
||||||
</FileConfiguration>
|
</FileConfiguration>
|
||||||
<FileConfiguration
|
<FileConfiguration
|
||||||
|
@ -1534,7 +1536,8 @@
|
||||||
>
|
>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCCLCompilerTool"
|
Name="VCCLCompilerTool"
|
||||||
UsePrecompiledHeader="0"
|
UsePrecompiledHeader="1"
|
||||||
|
PrecompiledHeaderThrough="AssimpPCH.h"
|
||||||
/>
|
/>
|
||||||
</FileConfiguration>
|
</FileConfiguration>
|
||||||
<FileConfiguration
|
<FileConfiguration
|
||||||
|
@ -1542,7 +1545,8 @@
|
||||||
>
|
>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCCLCompilerTool"
|
Name="VCCLCompilerTool"
|
||||||
UsePrecompiledHeader="0"
|
UsePrecompiledHeader="1"
|
||||||
|
PrecompiledHeaderThrough="AssimpPCH.h"
|
||||||
/>
|
/>
|
||||||
</FileConfiguration>
|
</FileConfiguration>
|
||||||
</File>
|
</File>
|
||||||
|
|
Loading…
Reference in New Issue