Also did a quick workaround to allow different camera UP. This demo stuff really needs to be cleaned up now!
419 lines
14 KiB
C++
419 lines
14 KiB
C++
/*
|
|
Copyright (C) 2005-2006 Feeling Software Inc.
|
|
MIT License: http://www.opensource.org/licenses/mit-license.php
|
|
*/
|
|
/*
|
|
Based on the FS Import classes:
|
|
Copyright (C) 2005-2006 Feeling Software Inc
|
|
Copyright (C) 2005-2006 Autodesk Media Entertainment
|
|
MIT License: http://www.opensource.org/licenses/mit-license.php
|
|
*/
|
|
|
|
#include "StdAfx.h"
|
|
#include "FCDocument/FCDocument.h"
|
|
#include "FCDocument/FCDAnimated.h"
|
|
#include "FCDocument/FCDTransform.h"
|
|
#include "FUtils/FUDaeParser.h"
|
|
#include "FUtils/FUDaeWriter.h"
|
|
#include "FUtils/FUStringConversion.h"
|
|
|
|
#ifdef HAS_MAYATYPES
|
|
#include <maya/MTransformationMatrix.h>
|
|
#endif
|
|
|
|
FCDTTranslation::FCDTTranslation(FCDocument* document, FCDSceneNode* parent) : FCDTransform(document, parent) {}
|
|
FCDTTranslation::~FCDTTranslation() {}
|
|
|
|
FCDTransform* FCDTTranslation::Clone(FCDSceneNode* newParent)
|
|
{
|
|
FCDTTranslation* t = new FCDTTranslation(GetDocument(), newParent);
|
|
t->translation = translation;
|
|
if(IsAnimated())
|
|
GetAnimated()->Clone(GetDocument());
|
|
return t;
|
|
}
|
|
|
|
// Parse a <translate> node from the COLLADA document
|
|
FUStatus FCDTTranslation::LoadFromXML(xmlNode* node)
|
|
{
|
|
float lengthFactor = GetDocument()->GetLengthUnitConversion();
|
|
|
|
const char* content = FUDaeParser::ReadNodeContentDirect(node);
|
|
FloatList factors;
|
|
factors.reserve(3);
|
|
FUStringConversion::ToFloatList(content, factors);
|
|
if (factors.size() != 3) return FUStatus(false);
|
|
|
|
translation.x = factors[0] * lengthFactor;
|
|
translation.y = factors[1] * lengthFactor;
|
|
translation.z = factors[2] * lengthFactor;
|
|
FCDAnimatedPoint3::Create(GetDocument(), node, &translation);
|
|
return FUStatus(true);
|
|
}
|
|
|
|
// Write the <translate> node to the COLLADA xml document
|
|
xmlNode* FCDTTranslation::WriteToXML(xmlNode* parentNode) const
|
|
{
|
|
string content = FUStringConversion::ToString(translation);
|
|
xmlNode* transformNode = FUDaeWriter::AddChild(parentNode, DAE_TRANSLATE_ELEMENT, content);
|
|
GetDocument()->WriteAnimatedValueToXML(&translation.x, transformNode, "translation");
|
|
return transformNode;
|
|
}
|
|
|
|
FMMatrix44 FCDTTranslation::ToMatrix() const
|
|
{
|
|
return FMMatrix44::TranslationMatrix(translation);
|
|
}
|
|
|
|
FCDAnimated* FCDTTranslation::GetAnimated()
|
|
{
|
|
// Returns a FCDAnimatedAngleAxis
|
|
return GetDocument()->FindAnimatedValue(&translation.x);
|
|
}
|
|
|
|
bool FCDTTranslation::IsAnimated() const
|
|
{
|
|
// Only need to check against the first value, because we created a FCDAnimatedPoint3
|
|
return GetDocument()->IsValueAnimated(&translation.x);
|
|
}
|
|
|
|
bool FCDTTranslation::IsInverse(const FCDTransform* transform) const
|
|
{
|
|
return transform->GetType() == FCDTransform::TRANSLATION
|
|
&& IsEquivalent(-1.0f * translation, ((const FCDTTranslation*)transform)->translation);
|
|
}
|
|
|
|
FCDTRotation::FCDTRotation(FCDocument* document, FCDSceneNode* parent) : FCDTransform(document, parent) {}
|
|
FCDTRotation::~FCDTRotation() {}
|
|
|
|
FCDTransform* FCDTRotation::Clone(FCDSceneNode* newParent)
|
|
{
|
|
FCDTRotation* t = new FCDTRotation(GetDocument(), newParent);
|
|
t->angle = angle;
|
|
t->axis = axis;
|
|
if(IsAnimated())
|
|
GetAnimated()->Clone(GetDocument());
|
|
return t;
|
|
}
|
|
// Parse a <rotate> node from the COLLADA document
|
|
FUStatus FCDTRotation::LoadFromXML(xmlNode* node)
|
|
{
|
|
const char* content = FUDaeParser::ReadNodeContentDirect(node);
|
|
FloatList factors;
|
|
factors.reserve(4);
|
|
FUStringConversion::ToFloatList(content, factors);
|
|
if (factors.size() != 4) return FUStatus(false);
|
|
|
|
axis.x = factors[0]; axis.y = factors[1]; axis.z = factors[2];
|
|
angle = factors[3];
|
|
FCDAnimatedAngleAxis::Create(GetDocument(), node, &axis, &angle);
|
|
return FUStatus(true);
|
|
}
|
|
|
|
// Write the <rotate> node to the COLLADA xml document
|
|
xmlNode* FCDTRotation::WriteToXML(xmlNode* parent) const
|
|
{
|
|
globalSBuilder.clear();
|
|
FUStringConversion::ToString(globalSBuilder, axis); globalSBuilder += ' '; globalSBuilder += angle;
|
|
xmlNode* transformNode = FUDaeWriter::AddChild(parent, DAE_ROTATE_ELEMENT, globalSBuilder);
|
|
GetDocument()->WriteAnimatedValueToXML(&axis.x, transformNode, "rotation");
|
|
return transformNode;
|
|
}
|
|
|
|
FMMatrix44 FCDTRotation::ToMatrix() const
|
|
{
|
|
return FMMatrix44::AxisRotationMatrix(axis, FMath::DegToRad(angle));
|
|
}
|
|
|
|
FCDAnimated* FCDTRotation::GetAnimated()
|
|
{
|
|
// Returns a FCDAnimatedAngleAxis
|
|
return GetDocument()->FindAnimatedValue(&axis.x);
|
|
}
|
|
|
|
bool FCDTRotation::IsAnimated() const
|
|
{
|
|
// For the axis, we only need to check against the first value, because we created a FCDAnimatedAngleAxis
|
|
return GetDocument()->IsValueAnimated(&axis.x);
|
|
}
|
|
|
|
bool FCDTRotation::IsInverse(const FCDTransform* transform) const
|
|
{
|
|
return transform->GetType() == FCDTransform::TRANSLATION
|
|
&& IsEquivalent(axis, ((const FCDTRotation*)transform)->axis)
|
|
&& IsEquivalent(-angle, ((const FCDTRotation*)transform)->angle);
|
|
}
|
|
|
|
FCDTScale::FCDTScale(FCDocument* document, FCDSceneNode* parent) : FCDTransform(document, parent) {}
|
|
FCDTScale::~FCDTScale() {}
|
|
|
|
FCDTransform* FCDTScale::Clone(FCDSceneNode* newParent)
|
|
{
|
|
FCDTScale* t = new FCDTScale(GetDocument(), newParent);
|
|
t->scale = scale;
|
|
if(IsAnimated())
|
|
GetAnimated()->Clone(GetDocument());
|
|
return t;
|
|
}
|
|
|
|
// Parse a <scale> node from the COLLADA document
|
|
FUStatus FCDTScale::LoadFromXML(xmlNode* node)
|
|
{
|
|
const char* content = FUDaeParser::ReadNodeContentDirect(node);
|
|
FloatList factors;
|
|
factors.reserve(3);
|
|
FUStringConversion::ToFloatList(content, factors);
|
|
if (factors.size() != 3) return FUStatus(false);
|
|
|
|
scale.x = factors[0]; scale.y = factors[1]; scale.z = factors[2];
|
|
|
|
// Register the animated values
|
|
FCDAnimatedPoint3::Create(GetDocument(), node, &scale);
|
|
|
|
return FUStatus(true);
|
|
}
|
|
|
|
// Write the <scale> node to the COLLADA xml document
|
|
xmlNode* FCDTScale::WriteToXML(xmlNode* parentNode) const
|
|
{
|
|
string content = FUStringConversion::ToString(scale);
|
|
xmlNode* transformNode = FUDaeWriter::AddChild(parentNode, DAE_SCALE_ELEMENT, content);
|
|
GetDocument()->WriteAnimatedValueToXML(&scale.x, transformNode, "scale");
|
|
return transformNode;
|
|
}
|
|
|
|
FMMatrix44 FCDTScale::ToMatrix() const
|
|
{
|
|
FMMatrix44 mx = FMMatrix44::Identity;
|
|
mx[0][0] = scale.x; mx[1][1] = scale.y; mx[2][2] = scale.z;
|
|
return mx;
|
|
}
|
|
|
|
FCDAnimated* FCDTScale::GetAnimated()
|
|
{
|
|
// Returns a FCDAnimatedPoint3
|
|
return GetDocument()->FindAnimatedValue(&scale.x);
|
|
}
|
|
|
|
bool FCDTScale::IsAnimated() const
|
|
{
|
|
// We only need to check against the first value, because we created a FCDAnimatedPoint3
|
|
return GetDocument()->IsValueAnimated(&scale.x);
|
|
}
|
|
|
|
FCDTMatrix::FCDTMatrix(FCDocument* document, FCDSceneNode* parent) : FCDTransform(document, parent) {}
|
|
FCDTMatrix::~FCDTMatrix() {}
|
|
|
|
FCDTransform* FCDTMatrix::Clone(FCDSceneNode* newParent)
|
|
{
|
|
FCDTMatrix* t = new FCDTMatrix(GetDocument(), newParent);
|
|
t->transform = transform;
|
|
if(IsAnimated())
|
|
GetAnimated()->Clone(GetDocument());
|
|
return t;
|
|
}
|
|
// Parse a <matrix> node from the COLLADA document
|
|
FUStatus FCDTMatrix::LoadFromXML(xmlNode* node)
|
|
{
|
|
const char* content = FUDaeParser::ReadNodeContentDirect(node);
|
|
FUStringConversion::ToMatrix(&content, transform, GetDocument()->GetLengthUnitConversion());
|
|
|
|
// Register the matrix in the animation system for transform animations
|
|
FCDAnimatedMatrix::Create(GetDocument(), node, &transform);
|
|
|
|
return FUStatus(true);
|
|
}
|
|
|
|
// Write the <matrix> node to the COLLADA xml document
|
|
xmlNode* FCDTMatrix::WriteToXML(xmlNode* parentNode) const
|
|
{
|
|
string content = FUStringConversion::ToString(transform);
|
|
xmlNode* transformNode = FUDaeWriter::AddChild(parentNode, DAE_MATRIX_ELEMENT, content);
|
|
GetDocument()->WriteAnimatedValueToXML(&transform[0][0], transformNode, "transform");
|
|
return transformNode;
|
|
}
|
|
|
|
FCDAnimated* FCDTMatrix::GetAnimated()
|
|
{
|
|
// Returns a FCDAnimatedMatrix
|
|
return GetDocument()->FindAnimatedValue(&transform[0][0]);
|
|
}
|
|
|
|
bool FCDTMatrix::IsAnimated() const
|
|
{
|
|
// We only need to check against the first value, because we created a FCDAnimatedMatrix
|
|
return GetDocument()->IsValueAnimated(&transform[0][0]);
|
|
}
|
|
|
|
FCDTLookAt::FCDTLookAt(FCDocument* document, FCDSceneNode* parent) : FCDTransform(document, parent) {}
|
|
FCDTLookAt::~FCDTLookAt() {}
|
|
|
|
FCDTransform* FCDTLookAt::Clone(FCDSceneNode* newParent)
|
|
{
|
|
FCDTLookAt* t = new FCDTLookAt(GetDocument(), newParent);
|
|
t->position = position;
|
|
t->target = target;
|
|
t->up = up;
|
|
return t;
|
|
}
|
|
// Parse a <lookat> node from the COLLADA document
|
|
FUStatus FCDTLookAt::LoadFromXML(xmlNode* lookAtNode)
|
|
{
|
|
float lengthFactor = GetDocument()->GetLengthUnitConversion();
|
|
const char* content = FUDaeParser::ReadNodeContentDirect(lookAtNode);
|
|
FloatList factors;
|
|
factors.reserve(9);
|
|
FUStringConversion::ToFloatList(content, factors);
|
|
if (factors.size() != 9) return FUStatus(false);
|
|
|
|
position.x = factors[0] * lengthFactor; position.y = factors[1] * lengthFactor; position.z = factors[2] * lengthFactor;
|
|
target.x = factors[3] * lengthFactor; target.y = factors[4] * lengthFactor; target.z = factors[5] * lengthFactor;
|
|
up.x = factors[6]; up.y = factors[7]; up.z = factors[8];
|
|
|
|
return FUStatus(true);
|
|
}
|
|
|
|
// Write the <lookat> node to the COLLADA xml document
|
|
xmlNode* FCDTLookAt::WriteToXML(xmlNode* parentNode) const
|
|
{
|
|
globalSBuilder.clear();
|
|
FUStringConversion::ToString(globalSBuilder, position); globalSBuilder += ' ';
|
|
FUStringConversion::ToString(globalSBuilder, target); globalSBuilder += ' ';
|
|
FUStringConversion::ToString(globalSBuilder, up);
|
|
xmlNode* transformNode = FUDaeWriter::AddChild(parentNode, DAE_LOOKAT_ELEMENT, globalSBuilder);
|
|
return transformNode;
|
|
}
|
|
|
|
FMMatrix44 FCDTLookAt::ToMatrix() const
|
|
{
|
|
FMMatrix44 mx = FMMatrix44::Identity;
|
|
FMVector3 front = ((FMVector3)(position - target)).Normalize();
|
|
FMVector3 side = ((FMVector3)(up ^ front)).Normalize();
|
|
|
|
mx[0][0] = side.x; mx[0][1] = side.y; mx[0][2] = side.z;
|
|
mx[1][0] = up.x; mx[1][1] = up.y; mx[1][2] = up.z;
|
|
mx[2][0] = front.x; mx[2][1] = front.y; mx[2][2] = front.z;
|
|
mx[3][0] = position.x; mx[3][1] = position.y; mx[3][2] = position.z;
|
|
|
|
return mx;
|
|
}
|
|
|
|
FCDAnimated* FCDTLookAt::GetAnimated()
|
|
{
|
|
// Does not support animations
|
|
return NULL;
|
|
}
|
|
|
|
bool FCDTLookAt::IsAnimated() const
|
|
{
|
|
// Does not support animations
|
|
return false;
|
|
}
|
|
|
|
FCDTSkew::FCDTSkew(FCDocument* document, FCDSceneNode* parent) : FCDTransform(document, parent) {}
|
|
FCDTSkew::~FCDTSkew() {}
|
|
FCDTransform* FCDTSkew::Clone(FCDSceneNode* newParent)
|
|
{
|
|
FCDTSkew* t = new FCDTSkew(GetDocument(), newParent);
|
|
t->rotateAxis = rotateAxis;
|
|
t->aroundAxis = aroundAxis;
|
|
t->angle = angle;
|
|
return t;
|
|
}
|
|
|
|
// Parse a <skew> element from the COLLADA document
|
|
FUStatus FCDTSkew::LoadFromXML(xmlNode* skewNode)
|
|
{
|
|
const char* content = FUDaeParser::ReadNodeContentDirect(skewNode);
|
|
FloatList factors;
|
|
factors.reserve(7);
|
|
FUStringConversion::ToFloatList(content, factors);
|
|
if (factors.size() != 7) return FUStatus(false);
|
|
|
|
angle = factors[0];
|
|
rotateAxis.x = factors[1]; rotateAxis.y = factors[2]; rotateAxis.z = factors[3];
|
|
aroundAxis.x = factors[4]; aroundAxis.y = factors[5]; aroundAxis.z = factors[6];
|
|
|
|
// Check and pre-process the axises
|
|
if (IsEquivalent(rotateAxis, FMVector3::Origin) || IsEquivalent(aroundAxis, FMVector3::Origin)) return FUStatus(false);
|
|
rotateAxis = rotateAxis.Normalize();
|
|
aroundAxis = aroundAxis.Normalize();
|
|
|
|
// Register the animated values
|
|
FCDAnimatedAngle::Create(GetDocument(), skewNode, &angle);
|
|
|
|
return FUStatus(true);
|
|
}
|
|
|
|
// Write the <lookat> node to the COLLADA xml document
|
|
xmlNode* FCDTSkew::WriteToXML(xmlNode* parentNode) const
|
|
{
|
|
globalSBuilder.clear();
|
|
globalSBuilder.set(angle); globalSBuilder += ' ';
|
|
FUStringConversion::ToString(globalSBuilder, rotateAxis); globalSBuilder += ' ';
|
|
FUStringConversion::ToString(globalSBuilder, aroundAxis);
|
|
xmlNode* transformNode = FUDaeWriter::AddChild(parentNode, DAE_SKEW_ELEMENT, globalSBuilder);
|
|
GetDocument()->WriteAnimatedValueToXML(&angle, transformNode, "skew");
|
|
return transformNode;
|
|
}
|
|
|
|
FMMatrix44 FCDTSkew::ToMatrix() const
|
|
{
|
|
float v[4][4];
|
|
|
|
float s = tanf(FMath::DegToRad(angle));
|
|
|
|
for (int row = 0; row < 3; ++row)
|
|
{
|
|
for (int col = 0; col < 3; ++col)
|
|
{
|
|
v[col][row] = ((row == col) ? 1.0f : 0.0f) + s * rotateAxis[col] * aroundAxis[row];
|
|
}
|
|
}
|
|
|
|
v[0][3] = v[1][3] = v[2][3] = 0.0f;
|
|
v[3][0] = v[3][1] = v[3][2] = 0.0f;
|
|
v[3][3] = 1.0f;
|
|
|
|
return FMMatrix44((float*) v);
|
|
}
|
|
|
|
FCDAnimated* FCDTSkew::GetAnimated()
|
|
{
|
|
return GetDocument()->FindAnimatedValue(&angle);
|
|
}
|
|
|
|
bool FCDTSkew::IsAnimated() const
|
|
{
|
|
// Only angle may be animated for now.
|
|
return GetDocument()->IsValueAnimated(&angle);
|
|
}
|
|
|
|
// Creates a new COLLADA transform, given a transform type.
|
|
FCDTransform* FCDTFactory::CreateTransform(FCDocument* document, FCDSceneNode* parent, FCDTransform::Type type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case FCDTransform::TRANSLATION: return new FCDTTranslation(document, parent);
|
|
case FCDTransform::ROTATION: return new FCDTRotation(document, parent);
|
|
case FCDTransform::SCALE: return new FCDTScale(document, parent);
|
|
case FCDTransform::SKEW: return new FCDTSkew(document, parent);
|
|
case FCDTransform::MATRIX: return new FCDTMatrix(document, parent);
|
|
case FCDTransform::LOOKAT: return new FCDTLookAt(document, parent);
|
|
default: return NULL;
|
|
}
|
|
}
|
|
|
|
// Imports a COLLADA transform, given an XML tree node.
|
|
FCDTransform* FCDTFactory::CreateTransform(FCDocument* document, FCDSceneNode* parent, xmlNode* node)
|
|
{
|
|
FCDTransform* transform = NULL;
|
|
if (IsEquivalent(node->name, DAE_ROTATE_ELEMENT)) transform = new FCDTRotation(document, parent);
|
|
else if (IsEquivalent(node->name, DAE_TRANSLATE_ELEMENT)) transform = new FCDTTranslation(document, parent);
|
|
else if (IsEquivalent(node->name, DAE_SCALE_ELEMENT)) transform = new FCDTScale(document, parent);
|
|
else if (IsEquivalent(node->name, DAE_SKEW_ELEMENT)) transform = new FCDTSkew(document, parent);
|
|
else if (IsEquivalent(node->name, DAE_MATRIX_ELEMENT)) transform = new FCDTMatrix(document, parent);
|
|
else if (IsEquivalent(node->name, DAE_LOOKAT_ELEMENT)) transform = new FCDTLookAt(document, parent);
|
|
return transform;
|
|
}
|