Added ScenePreProcessor helper class to add missing dummy animation channels.

Modified FindInvalidData's behaviour regarding animation channels
Futher work on the IRR scene and IRRMESH loaders. Q3D fix. 
Updated aiNodeAnim documentation.

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@218 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
pull/1/head
aramis_acg 2008-11-02 16:58:31 +00:00
parent 4daa0294a2
commit ac200212a9
18 changed files with 713 additions and 139 deletions

View File

@ -134,30 +134,11 @@ void FindInvalidDataProcess::Execute( aiScene* pScene)
// Process animations
for (unsigned int a = 0; a < pScene->mNumAnimations;++a)
{
int result;
if ((result = ProcessAnimation( pScene->mAnimations[a])))
{
out = true;
ProcessAnimation( pScene->mAnimations[a]);
if (2 == result)
{
// remove this animation
delete pScene->mAnimations[a];
AI_DEBUG_INVALIDATE_PTR(pScene->mAnimations[a]);
continue;
}
}
pScene->mAnimations[realAnimations++] = pScene->mAnimations[a];
}
if (out)
{
if(!(pScene->mNumAnimations = realAnimations))
{
delete[] pScene->mAnimations;
pScene->mAnimations = NULL;
}
if ( real != pScene->mNumMeshes)
{
if (!real)
@ -237,55 +218,60 @@ inline bool AllIdentical(T* in, unsigned int num)
// ------------------------------------------------------------------------------------------------
// Search an animation for invalid content
int FindInvalidDataProcess::ProcessAnimation (aiAnimation* anim)
void FindInvalidDataProcess::ProcessAnimation (aiAnimation* anim)
{
bool out = false;
unsigned int real = 0;
// Process all animation channels
for (unsigned int a = 0; a < anim->mNumChannels;++a)
{
int result;
if ((result = ProcessAnimationChannel( anim->mChannels[a])))
{
out = true;
// remove this animation channel
delete anim->mChannels[a];
AI_DEBUG_INVALIDATE_PTR(anim->mChannels[a]);
continue;
}
anim->mChannels[real++] = anim->mChannels[a];
}
if (out)
{
anim->mNumChannels = real;
if (!real)
{
DefaultLogger::get()->error("Deleting anim: it consists of dummy tracks");
return 2;
}
return 1;
}
return 0;
ProcessAnimationChannel( anim->mChannels[a]);
}
// ------------------------------------------------------------------------------------------------
int FindInvalidDataProcess::ProcessAnimationChannel (aiNodeAnim* anim)
void FindInvalidDataProcess::ProcessAnimationChannel (aiNodeAnim* anim)
{
// TODO: (thom) For some reason, even proper channels are deleted as well. Therefore deactivated it for the moment.
//return 0;
int i = 0;
// Check whether all values are identical or whether there is just one keyframe
if ((anim->mNumPositionKeys < 1 || AllIdentical(anim->mPositionKeys,anim->mNumPositionKeys)) &&
(anim->mNumScalingKeys < 1 || AllIdentical(anim->mRotationKeys,anim->mNumRotationKeys)) &&
(anim->mNumRotationKeys < 1 || AllIdentical(anim->mScalingKeys,anim->mNumScalingKeys)))
// ScenePreprocessor's work ...
ai_assert(0 != anim->mPositionKeys && 0 != anim->mRotationKeys && 0 != anim->mScalingKeys);
// Check whether all values in a tracks are identical - in this case
// we can remove al keys except one.
// POSITIONS
if (anim->mNumPositionKeys > 1 && AllIdentical(anim->mPositionKeys,anim->mNumPositionKeys))
{
DefaultLogger::get()->error("Deleting dummy position animation channel");
return 1;
aiVectorKey v = anim->mPositionKeys[0];
// Reallocate ... we need just ONE element, it makes no sense to reuse the array
delete[] anim->mPositionKeys;
anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys = 1];
anim->mPositionKeys[0] = v;
i = 1;
}
return 0;
// ROTATIONS
if (anim->mNumRotationKeys > 1 && AllIdentical(anim->mRotationKeys,anim->mNumRotationKeys))
{
aiQuatKey v = anim->mRotationKeys[0];
// Reallocate ... we need just ONE element, it makes no sense to reuse the array
delete[] anim->mRotationKeys;
anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys = 1];
anim->mRotationKeys[0] = v;
i = 1;
}
// SCALINGS
if (anim->mNumScalingKeys > 1 && AllIdentical(anim->mScalingKeys,anim->mNumScalingKeys))
{
aiVectorKey v = anim->mScalingKeys[0];
// Reallocate ... we need just ONE element, it makes no sense to reuse the array
delete[] anim->mScalingKeys;
anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys = 1];
anim->mScalingKeys[0] = v;
i = 1;
}
if (1 == i)
DefaultLogger::get()->warn("Simplified dummy tracks with just one key");
}
// ------------------------------------------------------------------------------------------------

View File

@ -97,16 +97,14 @@ protected:
// -------------------------------------------------------------------
/** Executes the postprocessing step on the given animation
* @param anim The animation to process.
* @return 0 - nothing, 1 - removed sth, 2 - please delete me
*/
int ProcessAnimation (aiAnimation* anim);
void ProcessAnimation (aiAnimation* anim);
// -------------------------------------------------------------------
/** Executes the postprocessing step on the given anim channel
* @param anim The animation channel to process.
* @return 0 - nothing, 1 - removed sth, 2 - please delete me
*/
int ProcessAnimationChannel (aiNodeAnim* anim);
void ProcessAnimationChannel (aiNodeAnim* anim);
};
} // end of namespace Assimp

View File

@ -46,7 +46,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "IRRLoader.h"
#include "ParsingUtils.h"
#include "fast_atof.h"
#include "GenericProperty.h"
#include "SceneCombiner.h"
#include "StandardShapes.h"
using namespace Assimp;
@ -131,20 +133,14 @@ void IRRImporter::InternReadFile( const std::string& pFile,
// List of output lights
std::vector<aiLight*> lights;
// List of output meshes
std::vector<aiMesh*> meshes;
// List of output animation channels
std::vector<aiNodeAnim*> animations;
BatchLoader batch(pIOHandler);
cameras.reserve(5);
lights.reserve(5);
animations.reserve(5);
meshes.reserve(5);
bool inMaterials = false;
bool inMaterials = false, inAnimator = false;
unsigned int guessedAnimCnt = 0, guessedMeshCnt = 0;
// Parse the XML file
while (reader->read())
@ -179,11 +175,13 @@ void IRRImporter::InternReadFile( const std::string& pFile,
else if (!ASSIMP_stricmp(sz,"cube"))
{
nd = new Node(Node::CUBE);
meshes.push_back(StandardShapes::MakeMesh(&StandardShapes::MakeHexahedron));
++guessedMeshCnt;
// meshes.push_back(StandardShapes::MakeMesh(&StandardShapes::MakeHexahedron));
}
else if (!ASSIMP_stricmp(sz,"skybox"))
{
nd = new Node(Node::SKYBOX);
++guessedMeshCnt;
}
else if (!ASSIMP_stricmp(sz,"camera"))
{
@ -206,6 +204,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
else if (!ASSIMP_stricmp(sz,"sphere"))
{
nd = new Node(Node::SPHERE);
++guessedMeshCnt;
}
else if (!ASSIMP_stricmp(sz,"animatedMesh"))
{
@ -236,6 +235,10 @@ void IRRImporter::InternReadFile( const std::string& pFile,
{
inMaterials = true;
}
else if (!ASSIMP_stricmp(reader->getNodeName(),"animators"))
{
inAnimator = true;
}
else if (!ASSIMP_stricmp(reader->getNodeName(),"attributes"))
{
/* We should have a valid node here
@ -247,6 +250,8 @@ void IRRImporter::InternReadFile( const std::string& pFile,
continue;
}
Animator* curAnim = NULL;
if (inMaterials && curNode->type == Node::ANIMMESH ||
curNode->type == Node::MESH )
{
@ -258,6 +263,16 @@ void IRRImporter::InternReadFile( const std::string& pFile,
p.first = ParseMaterial(p.second);
continue;
}
else if (inAnimator)
{
/* This is an animation path - add a new animator
* to the list.
*/
curNode->animators.push_back(Animator());
curAnim = & curNode->animators.back();
++guessedAnimCnt;
}
/* Parse all elements in the attributes block
* and process them.
@ -274,29 +289,90 @@ void IRRImporter::InternReadFile( const std::string& pFile,
// Convert to our coordinate system
std::swap( (float&)prop.value.z, (float&)prop.value.y );
prop.value.y *= -1.f;
if (prop.name == "Position")
if (inAnimator)
{
curNode->position = prop.value;
}
else if (prop.name == "Rotation")
{
curNode->rotation = prop.value;
}
else if (prop.name == "Scale")
{
curNode->scaling = prop.value;
}
else if (Node::CAMERA == curNode->type)
{
aiCamera* cam = cameras.back();
if (prop.name == "Target")
if (curAnim->type == Animator::ROTATION && prop.name == "Rotation")
{
cam->mLookAt = prop.value;
// We store the rotation euler angles in 'direction'
curAnim->direction = prop.value;
}
else if (prop.name == "UpVector")
else if (curAnim->type == Animator::FOLLOW_SPLINE)
{
cam->mUp = prop.value;
// Check whether the vector follows the PointN naming scheme,
// here N is the ONE-based index of the point
if (prop.name.length() >= 6 && prop.name.substr(0,5) == "Point")
{
// Add a new key to the list
curAnim->splineKeys.push_back(aiVectorKey());
aiVectorKey& key = curAnim->splineKeys.back();
// and parse its properties
key.mValue = prop.value;
key.mTime = strtol10(&prop.name.c_str()[5]);
}
}
else if (curAnim->type == Animator::FLY_CIRCLE)
{
if (prop.name == "Center")
{
curAnim->circleCenter = prop.value;
}
else if (prop.name == "Direction")
{
curAnim->direction = prop.value;
}
}
else if (curAnim->type == Animator::FLY_STRAIGHT)
{
if (prop.name == "Start")
{
// We reuse the field here
curAnim->circleCenter = prop.value;
}
else if (prop.name == "End")
{
// We reuse the field here
curAnim->direction = prop.value;
}
}
}
else
{
if (prop.name == "Position")
{
curNode->position = prop.value;
}
else if (prop.name == "Rotation")
{
curNode->rotation = prop.value;
}
else if (prop.name == "Scale")
{
curNode->scaling = prop.value;
}
else if (Node::CAMERA == curNode->type)
{
aiCamera* cam = cameras.back();
if (prop.name == "Target")
{
cam->mLookAt = prop.value;
}
else if (prop.name == "UpVector")
{
cam->mUp = prop.value;
}
}
}
}
else if (!ASSIMP_stricmp(reader->getNodeName(),"bool"))
{
BoolProperty prop;
ReadBoolProperty(prop);
if (inAnimator && curAnim->type == Animator::FLY_CIRCLE && prop.name == "Loop")
{
curAnim->loop = prop.value;
}
}
else if (!ASSIMP_stricmp(reader->getNodeName(),"float"))
@ -304,36 +380,105 @@ void IRRImporter::InternReadFile( const std::string& pFile,
FloatProperty prop;
ReadFloatProperty(prop);
if (prop.name == "FramesPerSecond" &&
Node::ANIMMESH == curNode->type)
if (inAnimator)
{
curNode->framesPerSecond = prop.value;
// The speed property exists for several animators
if (prop.name == "Speed")
{
curAnim->speed = prop.value;
}
else if (curAnim->type == Animator::FLY_CIRCLE && prop.name == "Radius")
{
curAnim->circleRadius = prop.value;
}
}
else if (Node::CAMERA == curNode->type)
{
/* This is the vertical, not the horizontal FOV.
* We need to compute the right FOV from the
* screen aspect which we don't know yet.
else
{
if (prop.name == "FramesPerSecond" &&
Node::ANIMMESH == curNode->type)
{
curNode->framesPerSecond = prop.value;
}
else if (Node::CAMERA == curNode->type)
{
/* This is the vertical, not the horizontal FOV.
* We need to compute the right FOV from the
* screen aspect which we don't know yet.
*/
if (prop.name == "Fovy")
{
cameras.back()->mHorizontalFOV = prop.value;
}
else if (prop.name == "Aspect")
{
cameras.back()->mAspect = prop.value;
}
else if (prop.name == "ZNear")
{
cameras.back()->mClipPlaneNear = prop.value;
}
else if (prop.name == "ZFar")
{
cameras.back()->mClipPlaneFar = prop.value;
}
}
else if (Node::LIGHT == curNode->type)
{
/* Additional light information
*/
if (prop.name == "Fovy")
{
cameras.back()->mHorizontalFOV = prop.value;
if (prop.name == "Attenuation")
{
lights.back()->mAttenuationLinear = prop.value;
}
else if (prop.name == "OuterCone")
{
lights.back()->mAngleOuterCone = AI_DEG_TO_RAD( prop.value );
}
else if (prop.name == "InnerCone")
{
lights.back()->mAngleInnerCone = AI_DEG_TO_RAD( prop.value );
}
}
else if (prop.name == "Aspect")
// radius of the sphere to be generated
else if (Node::SPHERE == curNode->type)
{
cameras.back()->mAspect = prop.value;
}
else if (prop.name == "ZNear")
{
cameras.back()->mClipPlaneNear = prop.value;
}
else if (prop.name == "ZFar")
{
cameras.back()->mClipPlaneFar = prop.value;
if (prop.name == "Radius")
{
curNode->sphereRadius = prop.value;
}
}
}
}
else if (!ASSIMP_stricmp(reader->getNodeName(),"string"))
else if (!ASSIMP_stricmp(reader->getNodeName(),"int"))
{
IntProperty prop;
ReadIntProperty(prop);
if (inAnimator)
{
if (curAnim->type == Animator::FLY_STRAIGHT && prop.name == "TimeForWay")
{
curAnim->timeForWay = prop.value;
}
}
else
{
// sphere polgon numbers in each direction
if (Node::SPHERE == curNode->type)
{
if (prop.name == "PolyCountX")
{
curNode->spherePolyCountX = prop.value;
}
else if (prop.name == "PolyCountY")
{
curNode->spherePolyCountY = prop.value;
}
}
}
}
else if (!ASSIMP_stricmp(reader->getNodeName(),"string") ||
!ASSIMP_stricmp(reader->getNodeName(),"enum"))
{
StringProperty prop;
ReadStringProperty(prop);
@ -356,17 +501,29 @@ void IRRImporter::InternReadFile( const std::string& pFile,
lights.back()->mName.Set(prop.value);
}
}
else if (Node::LIGHT == curNode->type && "LightType" == prop.name)
{
}
else if (prop.name == "Mesh" && Node::MESH == curNode->type ||
Node::ANIMMESH == curNode->type)
{
/* This is the file name of the mesh - either
* animated or not. We don't need any postprocessing
* steps here. However, it would be useful it we'd
* be able to use RemoveVC to remove animations
* if this isn't an animated mesh. But that's not
* possible at the moment.
* animated or not. We need to make sure we setup
* the correct postprocessing settings here.
*/
batch.AddLoadRequest(prop.value);
unsigned int pp = 0;
BatchLoader::PropertyMap map;
/* If the mesh is a static one remove all animations
*/
if (Node::ANIMMESH != curNode->type)
{
pp |= aiProcess_RemoveComponent;
SetGenericProperty<int>(map.ints,AI_CONFIG_PP_RVC_FLAGS,
aiComponent_ANIMATIONS | aiComponent_BONEWEIGHTS);
}
batch.AddLoadRequest(prop.value,pp,&map);
}
}
}
@ -382,6 +539,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
case EXN_ELEMENT_END:
// If we reached the end of a node, we need to continue processing its parent
if (!ASSIMP_stricmp(reader->getNodeName(),"node"))
{
if (!curNode)
@ -397,10 +555,15 @@ void IRRImporter::InternReadFile( const std::string& pFile,
}
else curNode = NULL;
}
// clear all flags
else if (!ASSIMP_stricmp(reader->getNodeName(),"materials"))
{
inMaterials = false;
}
else if (!ASSIMP_stricmp(reader->getNodeName(),"animators"))
{
inAnimator = false;
}
break;
default:
@ -421,4 +584,69 @@ void IRRImporter::InternReadFile( const std::string& pFile,
}
else DefaultLogger::get()->warn("IRR: Camera aspect is not given, can't compute horizontal FOV");
}
/* Allocate a tempoary scene data structure
*/
aiScene* tempScene = new aiScene();
tempScene->mRootNode = new aiNode();
tempScene->mRootNode->mName.Set("<IRRRoot>");
/* Copy the cameras to the output array
*/
tempScene->mNumCameras = (unsigned int)cameras.size();
tempScene->mCameras = new aiCamera*[tempScene->mNumCameras];
::memcpy(tempScene->mCameras,&cameras[0],sizeof(void*)*tempScene->mNumCameras);
/* Copy the light sources to the output array
*/
tempScene->mNumLights = (unsigned int)lights.size();
tempScene->mLights = new aiLight*[tempScene->mNumLights];
::memcpy(tempScene->mLights,&lights[0],sizeof(void*)*tempScene->mNumLights);
// temporary data
std::vector< aiNodeAnim*> anims;
std::vector< AttachmentInfo > attach;
std::vector<aiMesh*> meshes;
anims.reserve(guessedAnimCnt + (guessedAnimCnt >> 2));
meshes.reserve(guessedMeshCnt + (guessedMeshCnt >> 2));
/* Now process our scenegraph recursively: generate final
* meshes and generate animation channels for all nodes.
*/
// GenerateGraph(root,tempScene->mRootNode, tempScene,
// batch, meshes, anims, attach);
if (!anims.empty())
{
tempScene->mNumAnimations = 1;
tempScene->mAnimations = new aiAnimation*[tempScene->mNumAnimations];
aiAnimation* an = tempScene->mAnimations[0] = new aiAnimation();
// ***********************************************************
// This is only the global animation channel of the scene.
// If there are animated models, they will have separate
// animation channels in the scene. To display IRR scenes
// correctly, users will need to combine the global anim
// channel with all the local animations they want to play
// ***********************************************************
an->mName.Set("Irr_GlobalAnimChannel");
// copy all node animation channels to the global channel
an->mNumChannels = (unsigned int)anims.size();
an->mChannels = new aiNodeAnim*[an->mNumChannels];
::memcpy(an->mChannels, & anims [0], sizeof(void*)*an->mNumChannels);
}
if (meshes.empty())
{
// There are no meshes in the scene - the scene is incomplete
pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
DefaultLogger::get()->info("IRR: No Meshes loaded, setting AI_SCENE_FLAGS_INCOMPLETE flag");
}
/* Now merge all sub scenes and attach them to the correct
* attachment points in the scenegraph.
*/
SceneCombiner::MergeScenes(pScene,tempScene,attach);
}

View File

@ -100,6 +100,54 @@ protected:
private:
/** Data structure for a scenegraph node animator
*/
struct Animator
{
// Type of the animator
enum AT
{
UNKNOWN = 0x0,
ROTATION = 0x1,
FLY_CIRCLE = 0x2,
FLY_STRAIGHT = 0x3,
FOLLOW_SPLINE = 0x4,
OTHER = 0x5
} type;
Animator(AT t = UNKNOWN)
: type (t)
, speed (0.001f)
, direction (0.f,1.f,0.f)
, circleRadius (1.f)
, tightness (0.5f)
, loop (true)
, timeForWay (100)
{
}
// common parameters
float speed;
aiVector3D direction;
// FLY_CIRCLE
aiVector3D circleCenter;
float circleRadius;
// FOLLOW_SPLINE
float tightness;
std::vector<aiVectorKey> splineKeys;
// ROTATION (angles given in direction)
// FLY STRAIGHT
// circleCenter = start, direction = end
bool loop;
int timeForWay;
};
/** Data structure for a scenegraph node in an IRR file
*/
struct Node
@ -119,10 +167,13 @@ private:
} type;
Node(ET t)
: type (t)
, scaling (1.f,1.f,1.f) // assume uniform scaling by default
, animation (NULL)
, framesPerSecond (0.f)
: type (t)
, scaling (1.f,1.f,1.f) // assume uniform scaling by default
, animation (NULL)
, framesPerSecond (0.f)
, sphereRadius (1.f)
, spherePolyCountX (100)
, spherePolyCountY (100)
{
// Generate a default name for the node
@ -157,9 +208,18 @@ private:
// 0.f if not specified
float framesPerSecond;
//! Meshes: List of materials to be assigned
//! along with their corresponding material flags
// Meshes: List of materials to be assigned
// along with their corresponding material flags
std::vector< std::pair<aiMaterial*, unsigned int> > materials;
// Spheres: radius of the sphere to be generates
float sphereRadius;
// Spheres: Number of polygons in the x,y direction
unsigned int spherePolyCountX,spherePolyCountY;
// List of all animators assigned to the node
std::list<Animator> animators;
};
};

View File

@ -70,6 +70,24 @@ void IrrlichtBase::ReadHexProperty (HexProperty& out)
}
}
// ------------------------------------------------------------------------------------------------
// read a decimal property
void IrrlichtBase::ReadIntProperty (IntProperty& out)
{
for (int i = 0; i < reader->getAttributeCount();++i)
{
if (!ASSIMP_stricmp(reader->getAttributeName(i),"name"))
{
out.name = std::string( reader->getAttributeValue(i) );
}
else if (!ASSIMP_stricmp(reader->getAttributeName(i),"value"))
{
// parse the ecimal value
out.value = strtol10s(reader->getAttributeValue(i));
}
}
}
// ------------------------------------------------------------------------------------------------
// read a string property
void IrrlichtBase::ReadStringProperty (StringProperty& out)

View File

@ -73,6 +73,7 @@ protected:
typedef Property<bool> BoolProperty;
typedef Property<float> FloatProperty;
typedef Property<aiVector3D> VectorProperty;
typedef Property<int> IntProperty;
/** XML reader instance
*/
@ -95,7 +96,8 @@ protected:
void ReadStringProperty (StringProperty& out);
void ReadBoolProperty (BoolProperty& out);
void ReadFloatProperty (FloatProperty& out);
void ReadVectorProperty (VectorProperty& out);
void ReadVectorProperty (VectorProperty& out);
void ReadIntProperty (IntProperty& out);
};
// ---------------------------------------------------------------------------

View File

@ -51,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "DefaultIOSystem.h"
#include "GenericProperty.h"
#include "ProcessHelper.h"
#include "ScenePreprocessor.h"
// Importers
#ifndef AI_BUILD_NO_X_IMPORTER
@ -565,6 +566,10 @@ const aiScene* Importer::ReadFile( const std::string& pFile, unsigned int pFlags
// if successful, apply all active post processing steps to the imported data
if( mScene)
{
// FIRST of all - preprocess the scene
ScenePreprocessor pre;
pre.ProcessScene(mScene);
DefaultLogger::get()->info("Import successful, entering postprocessing-steps");
#ifdef _DEBUG
if (bExtraVerbose)

View File

@ -436,8 +436,8 @@ outer:
mat->AddProperty(&srcMat.specular, 1,AI_MATKEY_COLOR_SPECULAR);
mat->AddProperty(&srcMat.ambient, 1,AI_MATKEY_COLOR_AMBIENT);
//if (!(minor > '0' && major == '3'))
// srcMat.transparency = 1.0f - srcMat.transparency;
if (!(minor > '0' && major == '3'))
srcMat.transparency = 1.0f - srcMat.transparency;
mat->AddProperty(&srcMat.transparency, 1, AI_MATKEY_OPACITY);
// add shininess - Quick3D seems to use it ins its viewer

View File

@ -274,6 +274,14 @@ void SceneCombiner::MergeScenes(aiScene* dest,std::vector<aiScene*>& src,
}
// ------------------------------------------------------------------------------------------------
void SceneCombiner::MergeScenes(aiScene* dest, const aiScene* master,
std::vector<AttachmentInfo>& src,
unsigned int flags)
{
}
// ------------------------------------------------------------------------------------------------
void SceneCombiner::MergeMeshes(aiMesh* dest,std::vector<aiMesh*>& src,
unsigned int flags)

View File

@ -48,6 +48,26 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp {
// ---------------------------------------------------------------------------
/** \brief Helper data structure for SceneCombiner.
*
* Describes to which node a scene must be attached to.
*/
struct AttachmentInfo
{
AttachmentInfo()
: scene (NULL)
, attachToNode (NULL)
{}
AttachmentInfo(aiScene* _scene, aiNode* _attachToNode)
: scene (_scene)
, attachToNode (_attachToNode)
{}
aiScene* scene;
aiNode* attachToNode;
};
// ---------------------------------------------------------------------------
/** \brief Static helper class providing various utilities to merge two
@ -73,7 +93,24 @@ public:
* @param flags Combination of the AI_INT_MERGE_SCENE flags defined above
*/
static void MergeScenes(aiScene* dest,std::vector<aiScene*>& src,
unsigned int flags);
unsigned int flags = 0);
// -------------------------------------------------------------------
/** Merges two or more scenes and attaches all sceenes to a specific
* position in the node graph of the masteer scene.
*
* @param dest Destination scene. Must be empty.
* @param master Master scene. It will be deleted afterwards. All
* other scenes will be inserted in its node graph.
* @param src Non-empty list of scenes to be merged along with their
* corresponding attachment points in the master scene. The function
* deletes the input scenes afterwards.
* @param flags Combination of the AI_INT_MERGE_SCENE flags defined above
*/
static void MergeScenes(aiScene* dest, const aiScene* master,
std::vector<AttachmentInfo>& src,
unsigned int flags = 0);
// -------------------------------------------------------------------

View File

@ -0,0 +1,129 @@
/*
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 "ScenePreprocessor.h"
using namespace Assimp;
// ---------------------------------------------------------------------------
void ScenePreprocessor::ProcessScene (aiScene* _scene)
{
scene = _scene;
// - nothing to do for meshes for the moment
// - nothing to do for materials for the moment
// - nothing to do for nodes for the moment
// - nothing to do for textures for the moment
// - nothing to do for lights for the moment
// - nothing to do for cameras for the moment
// Process all animations
for (unsigned int i = 0; i < scene->mNumAnimations;++i)
ProcessAnimation(scene->mAnimations[i]);
}
// ---------------------------------------------------------------------------
void ScenePreprocessor::ProcessAnimation (aiAnimation* anim)
{
for (unsigned int i = 0; i < anim->mNumChannels;++i)
{
aiNodeAnim* channel = anim->mChannels[i];
/* Check whether the animation channel has no rotation
* or position tracks. In this case we generate a dummy
* track from the information we have in the transformation
* matrix of the corresponding node.
*/
if (!channel->mNumRotationKeys || !channel->mNumPositionKeys || !channel->mNumScalingKeys)
{
// Find the node that belongs to this animation
aiNode* node = scene->mRootNode->FindNode(channel->mNodeName);
if (node) // ValidateDS will complain later if 'node' is NULL
{
// Decompose the transformation matrix of the node
aiVector3D scaling, position;
aiQuaternion rotation;
node->mTransformation.Decompose(scaling, rotation,position);
// No rotation keys? Generate a dummy track
if (!channel->mNumRotationKeys)
{
channel->mNumRotationKeys = 1;
channel->mRotationKeys = new aiQuatKey[1];
aiQuatKey& q = channel->mRotationKeys[0];
q.mTime = 0.;
q.mValue = rotation;
DefaultLogger::get()->debug("ScenePreprocessor: Dummy rotation track has been generated");
}
// No scaling keys? Generate a dummy track
if (!channel->mNumScalingKeys)
{
channel->mNumScalingKeys = 1;
channel->mScalingKeys = new aiVectorKey[1];
aiVectorKey& q = channel->mScalingKeys[0];
q.mTime = 0.;
q.mValue = scaling;
DefaultLogger::get()->debug("ScenePreprocessor: Dummy scaling track has been generated");
}
// No position keys? Generate a dummy track
if (!channel->mNumPositionKeys)
{
channel->mNumPositionKeys = 1;
channel->mPositionKeys = new aiVectorKey[1];
aiVectorKey& q = channel->mPositionKeys[0];
q.mTime = 0.;
q.mValue = position;
DefaultLogger::get()->debug("ScenePreprocessor: Dummy position track has been generated");
}
}
}
}
}

View File

@ -0,0 +1,77 @@
/*
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.
----------------------------------------------------------------------
*/
/** @file Defines a post processing step to search all meshes for
degenerated faces */
#ifndef AI_SCENE_PREPROCESSOR_H_INC
#define AI_SCENE_PREPROCESSOR_H_INC
namespace Assimp {
// ---------------------------------------------------------------------------
/** ScenePreprocessor: Preprocess a scene before any post-processing
* steps are executed.
*/
class ASSIMP_API ScenePreprocessor
{
public:
/** Preprocess a given scene.
*
* @param _scene Scene to be preprocessed
*/
void ProcessScene (aiScene* _scene);
protected:
void ProcessAnimation (aiAnimation* anim);
protected:
//! Scene we're currently working on
aiScene* scene;
};
} // ! end namespace Assimp
#endif // include guard

View File

@ -71,7 +71,8 @@ SOURCES = AssimpPCH.cpp \
./irrXML/irrXML.cpp \
IRRMeshLoader.cpp \
IRRLoader.cpp \
Q3DLoader.cpp
Q3DLoader.cpp \
ScenePreprocessor.cpp
OBJECTS = $(SOURCES:.cpp=.o)

View File

@ -71,7 +71,8 @@ SOURCES = AssimpPCH.cpp \
./irrXML/irrXML.cpp \
IRRMeshLoader.cpp \
IRRLoader.cpp \
Q3DLoader.cpp
Q3DLoader.cpp \
ScenePreprocessor.cpp
OBJECTS = $(SOURCES:.cpp=.o)

View File

@ -66,6 +66,14 @@ struct aiVectorKey
bool operator != (const aiVectorKey& o) const
{return o.mValue != this->mValue;}
// Only time is compared. This operator is defined
// for use with std::sort
bool operator < (const aiVectorKey& o) const
{return mTime < o.mTime;}
#endif
};
@ -86,6 +94,14 @@ struct aiQuatKey
bool operator != (const aiQuatKey& o) const
{return o.mValue != this->mValue;}
// Only time is compared. This operator is defined
// for use with std::sort
bool operator < (const aiQuatKey& o) const
{return mTime < o.mTime;}
#endif
};
@ -126,8 +142,8 @@ struct aiNodeAnim
/** The position keys of this animation channel. Positions are
* specified as 3D vector. The array is mNumPositionKeys in size.
*
* If there are rotation or scaling keys, but no position keys,
* a constant position of 0|0|0 should be assumed.
* If there are position keys, there will also be at least one
* scaling and one rotation key.
*/
C_STRUCT aiVectorKey* mPositionKeys;
@ -138,8 +154,8 @@ struct aiNodeAnim
* given as quaternions, which are 4D vectors. The array is
* mNumRotationKeys in size.
*
* If there are position or scaling keys, but no rotation keys,
* a constant rotation of 0|0|0 should be assumed.
* If there are rotation keys, there will also be at least one
* scaling and one position key.
*/
C_STRUCT aiQuatKey* mRotationKeys;
@ -150,8 +166,8 @@ struct aiNodeAnim
/** The scaling keys of this animation channel. Scalings are
* specified as 3D vector. The array is mNumScalingKeys in size.
*
* If there are position or rotation keys, but no scaling keys,
* a constant scaling of 1|1|1 should be assumed.
* If there are scaling keys, there will also be at least one
* position and one rotation key.
*/
C_STRUCT aiVectorKey* mScalingKeys;

View File

@ -161,7 +161,7 @@ inline void aiMatrix4x4::Decompose (aiVector3D& scaling, aiQuaternion& rotation,
// extract the rows of the matrix
aiVector3D vRows[3] = {
aiVector3D(_this[0][0],_this[1][1],_this[2][0]),
aiVector3D(_this[0][0],_this[1][0],_this[2][0]),
aiVector3D(_this[0][1],_this[1][1],_this[2][1]),
aiVector3D(_this[0][2],_this[1][2],_this[2][2])
};
@ -186,9 +186,9 @@ inline void aiMatrix4x4::Decompose (aiVector3D& scaling, aiQuaternion& rotation,
}
// build a 3x3 rotation matrix
aiMatrix3x3 m(vRows[0].x,vRows[0].y,vRows[0].z,
vRows[1].x,vRows[1].y,vRows[1].z,
vRows[2].x,vRows[2].y,vRows[2].z);
aiMatrix3x3 m(vRows[0].x,vRows[1].x,vRows[2].x,
vRows[0].y,vRows[1].y,vRows[2].y,
vRows[0].z,vRows[1].z,vRows[2].z);
// and generate the rotation quaternion from it
rotation = aiQuaternion(m);

Binary file not shown.

View File

@ -839,6 +839,14 @@
RelativePath="..\..\code\SceneCombiner.h"
>
</File>
<File
RelativePath="..\..\code\ScenePreprocessor.cpp"
>
</File>
<File
RelativePath="..\..\code\ScenePreprocessor.h"
>
</File>
<File
RelativePath="..\..\code\SGSpatialSort.cpp"
>