moved files around

This commit is contained in:
ejcoumans
2006-05-25 19:18:29 +00:00
commit e061ec1ebf
1024 changed files with 349445 additions and 0 deletions

View File

@@ -0,0 +1,544 @@
/*
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/FCDAnimationChannel.h"
#include "FCDocument/FCDAnimationCurve.h"
#include "FCDocument/FCDAnimationMultiCurve.h"
#include "FCDocument/FCDAnimated.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDAnimated::FCDAnimated(FCDocument* document, size_t valueCount) : FCDObject(document, "FCDAnimated")
{
arrayElement = -1;
// Allocate the values/qualifiers/curves arrays
values.resize(valueCount, NULL);
qualifiers.resize(valueCount, "");
curves.resize(valueCount, NULL);
}
FCDAnimated::~FCDAnimated()
{
values.clear();
qualifiers.clear();
curves.clear();
}
// Assigns a curve to a value of the animated element.
bool FCDAnimated::SetCurve(size_t index, FCDAnimationCurve* curve)
{
FUAssert(index < GetValueCount(), return false);
curves.at(index) = curve;
return true;
}
// Removes the curve affecting a value of the animated element.
bool FCDAnimated::RemoveCurve(size_t index)
{
FUAssert(index < GetValueCount(), return false);
bool hasCurve = curves[index] != NULL;
curves[index] = NULL;
return hasCurve;
}
bool FCDAnimated::Link(xmlNode* node)
{
bool linked = false;
if (node != NULL)
{
// Write down the expected target string for the given node
FUDaeParser::CalculateNodeTargetPointer(node, pointer);
// Check if this animated value is used as a driver
linked |= GetDocument()->LinkDriver(this);
// Retrieve the list of the channels pointing to this node
FCDAnimationChannelList channels;
GetDocument()->FindAnimationChannels(pointer, channels);
linked |= ProcessChannels(channels);
}
else linked = true;
if (linked)
{
// Register this animated value with the document
GetDocument()->RegisterAnimatedValue(this);
}
return linked;
}
bool FCDAnimated::ProcessChannels(FCDAnimationChannelList& channels)
{
bool linked = false;
for (FCDAnimationChannelList::iterator it = channels.begin(); it != channels.end(); ++it)
{
FCDAnimationChannel* channel = *it;
const FCDAnimationCurveList& channelCurves = channel->GetCurves();
if (channelCurves.empty()) continue;
// Retrieve the channel's qualifier and check for a requested matrix element
string qualifier = channel->GetTargetQualifier();
if (arrayElement != -1)
{
int32 element = ReadTargetMatrixElement(qualifier);
if (arrayElement != element) continue;
}
if (qualifier.empty())
{
// An empty qualifier implies that the channel should provide ALL the curves
for (size_t i = 0; i < channelCurves.size() && i < curves.size(); ++i)
{
curves[i] = channelCurves[i];
linked = true;
}
}
else
{
// Attempt to match the qualifier with this animated qualifiers
size_t index;
for (index = 0; index < qualifiers.size(); ++index)
{
if (qualifiers[index] == qualifier) break;
}
// Check for a matrix element instead
if (index == qualifiers.size()) index = ReadTargetMatrixElement(qualifier);
if (index < qualifiers.size())
{
curves[index] = channelCurves.front();
linked = true;
}
/* else return status.Fail(FS("Invalid qualifier for animation channel target: ") + TO_FSTRING(pointer)); */
}
}
if (linked)
{
// Now that the curves are imported: set their target information
for (size_t i = 0; i < curves.size(); ++i)
{
if (curves[i] != NULL)
{
curves[i]->SetTargetElement(arrayElement);
curves[i]->SetTargetQualifier(qualifiers[i]);
}
}
}
return linked;
}
const string& FCDAnimated::GetQualifier(size_t index) const
{
FUAssert(index < GetValueCount(), return emptyString);
return qualifiers.at(index);
}
// Retrieves an animated value, given a valid qualifier
float* FCDAnimated::FindValue(const string& qualifier)
{
for (size_t i = 0; i < qualifiers.size(); ++i)
{
if (qualifiers[i] == qualifier) return values[i];
}
return NULL;
}
const float* FCDAnimated::FindValue(const string& qualifier) const
{
for (size_t i = 0; i < qualifiers.size(); ++i)
{
if (qualifiers[i] == qualifier) return values[i];
}
return NULL;
}
// Retrieve the index of a given qualifier
size_t FCDAnimated::FindQualifier(const char* qualifier) const
{
for (size_t i = 0; i < qualifiers.size(); ++i)
{
if (qualifiers[i] == qualifier) return i;
}
// Otherwise, check for a matrix element
string q = qualifier;
int32 matrixElement = FUDaeParser::ReadTargetMatrixElement(q);
if (matrixElement >= 0 && matrixElement < (int32) qualifiers.size()) return matrixElement;
return size_t(-1);
}
// Retrieve the index of a given value pointer
size_t FCDAnimated::FindValue(const float* value) const
{
for (size_t i = 0; i < values.size(); ++i)
{
if (values[i] == value) return i;
}
return size_t(-1);
}
// Returns whether any of the contained curves are non-NULL
bool FCDAnimated::HasCurve() const
{
FCDAnimationCurveList::const_iterator cit;
for (cit = curves.begin(); cit != curves.end() && (*cit) == NULL; ++cit) {}
return cit != curves.end();
}
// Create one multi-curve out of this animated value's single curves
FCDAnimationMultiCurve* FCDAnimated::CreateMultiCurve() const
{
FloatList defaultValues;
size_t count = values.size();
defaultValues.resize(count);
for (size_t i = 0; i < count; ++i) defaultValues[i] = (*values[i]);
vector<const FCDAnimationCurve*> toMerge;
toMerge.resize(count);
for (size_t i = 0; i < count; ++i) toMerge[i] = curves[i];
return FCDAnimationMultiCurve::MergeCurves(toMerge, defaultValues);
}
// Create one multi-curve out of the single curves from many FCDAnimated objects
FCDAnimationMultiCurve* FCDAnimated::CreateMultiCurve(const FCDAnimatedList& toMerge)
{
// Calculate the total dimension of the curve to create
size_t count = 0;
for (FCDAnimatedList::const_iterator cit = toMerge.begin(); cit != toMerge.end(); ++cit)
{
count += (*cit)->GetValueCount();
}
// Generate the list of default values and the list of curves
FloatList defaultValues(count, 0.0f);
vector<const FCDAnimationCurve*> curves(count, NULL);
size_t offset = 0;
for (FCDAnimatedList::const_iterator cit = toMerge.begin(); cit != toMerge.end(); ++cit)
{
size_t localCount = (*cit)->GetValueCount();
for (size_t i = 0; i < localCount; ++i)
{
defaultValues[offset + i] = *(*cit)->GetValue(i);
curves[offset + i] = (*cit)->GetCurve(i);
}
offset += localCount;
}
return FCDAnimationMultiCurve::MergeCurves(curves, defaultValues);
}
// Sample the animated values for a given time
void FCDAnimated::Evaluate(float time)
{
size_t valueCount = values.size();
size_t curveCount = curves.size();
size_t count = min(curveCount, valueCount);
for (size_t i = 0; i < count; ++i)
{
// Retrieve the curve and the corresponding value
FCDAnimationCurve* curve = curves[i];
if (curve == NULL) continue;
float* value = values[i];
if (value == NULL) continue;
// Evaluate the curve at this time
(*value) = curve->Evaluate(time);
}
}
FCDAnimated* FCDAnimated::Clone(FCDocument* document)
{
FCDAnimated* clone = new FCDAnimated(document, GetValueCount());
clone->arrayElement = arrayElement;
for(size_t i = 0; i < curves.size(); ++i)
{
clone->curves[i] = curves[i]->Clone();
}
clone->pointer = pointer;
clone->qualifiers = qualifiers;
clone->values = values;
document->RegisterAnimatedValue(clone);
return clone;
}
// Clones the whole animated associated with a given value.
FCDAnimated* FCDAnimated::Clone(FCDocument* document, const float* animatedValue, FloatPtrList& newAnimatedValues)
{
const FCDAnimated* toClone = document->FindAnimatedValue(animatedValue);
if (toClone == NULL) return NULL;
FCDAnimated* clone = new FCDAnimated(document, toClone->GetValueCount());
clone->arrayElement = toClone->arrayElement;
for(size_t i = 0; i < toClone->curves.size(); ++i)
{
clone->curves[i] = toClone->curves[i];
}
clone->pointer = toClone->pointer;
clone->qualifiers = toClone->qualifiers;
clone->values = newAnimatedValues;
document->RegisterAnimatedValue(clone);
return clone;
}
FCDAnimatedFloat::FCDAnimatedFloat(FCDocument* document, float* value, int32 _arrayElement) : FCDAnimated(document, 1)
{
values[0] = value;
qualifiers[0] = "";
arrayElement = _arrayElement;
}
FCDAnimatedFloat* FCDAnimatedFloat::Create(FCDocument* document, float* value, int32 arrayElement)
{
FCDAnimatedFloat* animated = new FCDAnimatedFloat(document, value, arrayElement);
if (!animated->Link(NULL)) SAFE_DELETE(animated);
return animated;
}
FCDAnimatedFloat* FCDAnimatedFloat::Create(FCDocument* document, xmlNode* node, float* value, int32 arrayElement)
{
FCDAnimatedFloat* animated = new FCDAnimatedFloat(document, value, arrayElement);
if (!animated->Link(node)) SAFE_DELETE(animated);
return animated;
}
FCDAnimated* FCDAnimatedFloat::Clone(FCDocument* document, const float* oldValue, float* newValue)
{
FloatPtrList newValues;
newValues.push_back(newValue);
return FCDAnimated::Clone(document, oldValue, newValues);
}
FCDAnimatedPoint3::FCDAnimatedPoint3(FCDocument* document, FMVector3* value, int32 _arrayElement) : FCDAnimated(document, 3)
{
values[0] = &value->x; values[1] = &value->y; values[2] = &value->z;
qualifiers[0] = ".X"; qualifiers[1] = ".Y"; qualifiers[2] = ".Z";
arrayElement = _arrayElement;
}
FCDAnimatedPoint3* FCDAnimatedPoint3::Create(FCDocument* document, FMVector3* value, int32 arrayElement)
{
FCDAnimatedPoint3* animated = new FCDAnimatedPoint3(document, value, arrayElement);
if (!animated->Link(NULL)) SAFE_DELETE(animated);
return animated;
}
FCDAnimatedPoint3* FCDAnimatedPoint3::Create(FCDocument* document, xmlNode* node, FMVector3* value, int32 arrayElement)
{
FCDAnimatedPoint3* animated = new FCDAnimatedPoint3(document, value, arrayElement);
if (!animated->Link(node)) SAFE_DELETE(animated);
return animated;
}
FCDAnimated* FCDAnimatedPoint3::Clone(FCDocument* document, const FMVector3* oldValue, FMVector3* newValue)
{
FloatPtrList newValues;
newValues.push_back(&newValue->x); newValues.push_back(&newValue->y); newValues.push_back(&newValue->z);
return FCDAnimated::Clone(document, &oldValue->x, newValues);
}
FCDAnimatedColor::FCDAnimatedColor(FCDocument* document, FMVector3* value, int32 _arrayElement) : FCDAnimated(document, 3)
{
values[0] = &value->x; values[1] = &value->y; values[2] = &value->z;
qualifiers[0] = ".R"; qualifiers[1] = ".G"; qualifiers[2] = ".B";
arrayElement = _arrayElement;
}
FCDAnimatedColor* FCDAnimatedColor::Create(FCDocument* document, FMVector3* value, int32 arrayElement)
{
FCDAnimatedColor* animated = new FCDAnimatedColor(document, value, arrayElement);
if (!animated->Link(NULL)) SAFE_DELETE(animated);
return animated;
}
FCDAnimatedColor* FCDAnimatedColor::Create(FCDocument* document, xmlNode* node, FMVector3* value, int32 arrayElement)
{
FCDAnimatedColor* animated = new FCDAnimatedColor(document, value, arrayElement);
if (!animated->Link(node)) SAFE_DELETE(animated);
return animated;
}
FCDAnimated* FCDAnimatedColor::Clone(FCDocument* document, const FMVector3* oldValue, FMVector3* newValue)
{
FloatPtrList newValues; newValues.push_back(&newValue->x); newValues.push_back(&newValue->y); newValues.push_back(&newValue->z);
return FCDAnimated::Clone(document, &oldValue->x, newValues);
}
FCDAnimatedAngle::FCDAnimatedAngle(FCDocument* document, float* value, int32 _arrayElement) : FCDAnimated(document, 1)
{
values[0] = value;
qualifiers[0] = ".ANGLE";
arrayElement = _arrayElement;
}
FCDAnimatedAngle* FCDAnimatedAngle::Create(FCDocument* document, float* value, int32 arrayElement)
{
FCDAnimatedAngle* animated = new FCDAnimatedAngle(document, value, arrayElement);
if (!animated->Link(NULL)) SAFE_DELETE(animated);
return animated;
}
FCDAnimatedAngle* FCDAnimatedAngle::Create(FCDocument* document, xmlNode* node, float* value, int32 arrayElement)
{
FCDAnimatedAngle* animated = new FCDAnimatedAngle(document, value, arrayElement);
if (!animated->Link(node)) SAFE_DELETE(animated);
return animated;
}
FCDAnimated* FCDAnimatedAngle::Clone(FCDocument* document, const float* oldValue, float* newValue)
{
FloatPtrList newValues;
newValues.push_back(newValue);
return FCDAnimated::Clone(document, oldValue, newValues);
}
FCDAnimatedAngleAxis::FCDAnimatedAngleAxis(FCDocument* document, FMVector3* axis, float* angle, int32 _arrayElement) : FCDAnimated(document, 4)
{
values[0] = &axis->x; values[1] = &axis->y; values[2] = &axis->z; values[3] = angle;
qualifiers[0] = ".X"; qualifiers[1] = ".Y"; qualifiers[2] = ".Z"; qualifiers[3] = ".ANGLE";
arrayElement = _arrayElement;
}
FCDAnimatedAngleAxis* FCDAnimatedAngleAxis::Create(FCDocument* document, FMVector3* axis, float* angle, int32 arrayElement)
{
FCDAnimatedAngleAxis* animated = new FCDAnimatedAngleAxis(document, axis, angle, arrayElement);
if (!animated->Link(NULL)) SAFE_DELETE(animated);
return animated;
}
FCDAnimatedAngleAxis* FCDAnimatedAngleAxis::Create(FCDocument* document, xmlNode* node, FMVector3* axis, float* angle, int32 arrayElement)
{
FCDAnimatedAngleAxis* animated = new FCDAnimatedAngleAxis(document, axis, angle, arrayElement);
if (!animated->Link(node)) SAFE_DELETE(animated);
return animated;
}
FCDAnimated* FCDAnimatedAngleAxis::Clone(FCDocument* document, const float* oldAngle, FMVector3* newAxis, float* newAngle)
{
FloatPtrList newValues;
newValues.push_back(&newAxis->x); newValues.push_back(&newAxis->y); newValues.push_back(&newAxis->z);
newValues.push_back(newAngle);
return FCDAnimated::Clone(document, oldAngle, newValues);
}
FCDAnimatedMatrix::FCDAnimatedMatrix(FCDocument* document, FMMatrix44* value, int32 _arrayElement) : FCDAnimated(document, 16)
{
arrayElement = _arrayElement;
#define MX_V(a,b) values[b*4+a] = (&(*value)[a][b])
MX_V(0,0); MX_V(1,0); MX_V(2,0); MX_V(3,0);
MX_V(0,1); MX_V(1,1); MX_V(2,1); MX_V(3,1);
MX_V(0,2); MX_V(1,2); MX_V(2,2); MX_V(3,2);
MX_V(0,3); MX_V(1,3); MX_V(2,3); MX_V(3,3);
#undef MX_V
#define MX_V(a,b) qualifiers[b*4+a] = ("(" #a ")(" #b ")");
MX_V(0,0); MX_V(0,1); MX_V(0,2); MX_V(0,3);
MX_V(1,0); MX_V(1,1); MX_V(1,2); MX_V(1,3);
MX_V(2,0); MX_V(2,1); MX_V(2,2); MX_V(2,3);
MX_V(3,0); MX_V(3,1); MX_V(3,2); MX_V(3,3);
#undef MX_V
}
FCDAnimatedMatrix* FCDAnimatedMatrix::Create(FCDocument* document, FMMatrix44* value, int32 arrayElement)
{
FCDAnimatedMatrix* animated = new FCDAnimatedMatrix(document, value, arrayElement);
if (!animated->Link(NULL)) SAFE_DELETE(animated);
return animated;
}
FCDAnimatedMatrix* FCDAnimatedMatrix::Create(FCDocument* document, xmlNode* node, FMMatrix44* value, int32 arrayElement)
{
FCDAnimatedMatrix* animated = new FCDAnimatedMatrix(document, value, arrayElement);
if (!animated->Link(node)) SAFE_DELETE(animated);
return animated;
}
FCDAnimated* FCDAnimatedMatrix::Clone(FCDocument* document, const FMMatrix44* oldMx, FMMatrix44* newMx)
{
FloatPtrList newValues;
#define MX_V(a,b) newValues.push_back(&(*newMx)[a][b]);
MX_V(0,0); MX_V(0,1); MX_V(0,2); MX_V(0,3);
MX_V(1,0); MX_V(1,1); MX_V(1,2); MX_V(1,3);
MX_V(2,0); MX_V(2,1); MX_V(2,2); MX_V(2,3);
MX_V(3,0); MX_V(3,1); MX_V(3,2); MX_V(3,3);
#undef MX_V
return FCDAnimated::Clone(document, &(*oldMx)[0][0], newValues);
}
FCDAnimatedCustom::FCDAnimatedCustom(FCDocument* document) : FCDAnimated(document, 1)
{
dummy = 0.0f;
}
bool FCDAnimatedCustom::Link(xmlNode* node)
{
bool linked = false;
// Retrieve the list of the channels pointing to this node
FUDaeParser::CalculateNodeTargetPointer(node, pointer);
FCDAnimationChannelList channels;
GetDocument()->FindAnimationChannels(pointer, channels);
// Extract all the qualifiers needed to hold these channels
for (FCDAnimationChannelList::iterator itC = channels.begin(); itC != channels.end(); ++itC)
{
FCDAnimationChannel* channel = *itC;
const FCDAnimationCurveList& channelCurves = channel->GetCurves();
if (channelCurves.empty()) continue;
// Retrieve the channel's qualifier
string qualifier = channel->GetTargetQualifier();
if (qualifier.empty())
{
// Implies one channel holding multiple curves
qualifiers.clear();
qualifiers.resize(channels.size());
break;
}
else
{
qualifiers.push_back(qualifier);
}
}
// Link the curves and check if this animated value is used as a driver
values.resize(qualifiers.size());
curves.resize(values.size());
for (size_t i = 0; i < qualifiers.size(); ++i) { values[i] = &dummy; curves[i] = NULL; }
linked |= ProcessChannels(channels);
linked |= GetDocument()->LinkDriver(this);
if (linked)
{
// Register this animated value with the document
GetDocument()->RegisterAnimatedValue(this);
}
return linked;
}
FCDAnimatedCustom* FCDAnimatedCustom::Create(FCDocument* document)
{
FCDAnimatedCustom* animated = new FCDAnimatedCustom(document);
if (!animated->Link(NULL)) SAFE_DELETE(animated);
return animated;
}
FCDAnimatedCustom* FCDAnimatedCustom::Create(FCDocument* document, xmlNode* node)
{
FCDAnimatedCustom* animated = new FCDAnimatedCustom(document);
if (!animated->Link(node)) SAFE_DELETE(animated);
return animated;
}

View File

@@ -0,0 +1,488 @@
/*
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
*/
/**
@file FCDAnimated.h
This file contains the FCDAnimated class.
*/
#ifndef _FCD_ANIMATED_H_
#define _FCD_ANIMATED_H_
#include "FCDocument/FCDObject.h"
class FCDocument;
class FCDAnimated;
class FCDAnimationCurve;
class FCDAnimationChannel;
class FCDAnimationMultiCurve;
typedef vector<float*> FloatPtrList; /**< A dynamically-sized array of floating-point value pointers. */
typedef vector<FCDAnimationCurve*> FCDAnimationCurveList; /**< A dynamically-sized array of animation curves. */
typedef vector<FCDAnimationChannel*> FCDAnimationChannelList; /**< A dynamically-sized array of animation channels. */
typedef vector<FCDAnimated*> FCDAnimatedList; /**< A dynamically-sized array of animated values. */
/**
An animated element.
An animated element encapsulates a set of floating-point values that are
marked as animated.
For this purpose, an animated element holds a list of floating-point values,
their animation curves and their COLLADA qualifiers for the generation of
COLLADA targets. For animated list elements, an animated element holds an array index.
There are many classes built on top of this class. They represent
the different element types that may be animated, such as 3D points,
colors and matrices.
@ingroup FCDocument
*/
class FCOLLADA_EXPORT FCDAnimated : public FCDObject
{
protected:
/** The list of value pointers. */
FloatPtrList values;
/** The list of target qualifiers.
There is always one qualifier for one value pointer. */
StringList qualifiers;
/** The list of animation curves.
There is always one curve for one value pointer, although
that curve may be the NULL pointer to indicate a non-animated value. */
FCDAnimationCurveList curves;
/** The array index for animated element that belong
to a list of animated elements. This value may be -1
to indicate that the element does not belong to a list.
Otherwise, the index should always be unsigned. */
int32 arrayElement;
/** [INTERNAL] The target pointer prefix. */
string pointer;
public:
/** Constructor.
In most cases, it is preferable to create objects of the up-classes.
@param document The COLLADA document that owns this animated element.
@param valueCount The number of values inside the animated element. */
FCDAnimated(FCDocument* document, size_t valueCount);
/** Destructor. */
virtual ~FCDAnimated();
/** Retrieves the number of values contained within this animated element.
@return The number of values. */
inline size_t GetValueCount() const { return values.size(); }
/** Retrieves the animation curve affecting the value of an animated element.
@param index The value index.
@return The curve affecting the value at the given index. This pointer will
be NULL if the index is out-of-bounds or if the value is not animated. */
inline FCDAnimationCurve* GetCurve(size_t index) { FUAssert(index < GetValueCount(), return NULL); return curves.at(index); }
inline const FCDAnimationCurve* GetCurve(size_t index) const { FUAssert(index < GetValueCount(), return NULL); return curves.at(index); } /**< See above. */
/** Retrieves the list of the curves affecting the values of an animated element.
This list may contain the NULL pointer, where a value is not animated.
@return The list of animation curves. */
inline FCDAnimationCurveList& GetCurves() { return curves; }
inline const FCDAnimationCurveList& GetCurves() const { return curves; } /**< See above. */
/** Assigns a curve to a value of the animated element.
The previously assigned curve will be deleted.
@param index The value index.
@param curve The new curve that will affect the value at the given index.
@return Whether the curve was successfully assigned. Will return false if
the index is out-of-bounds. */
bool SetCurve(size_t index, FCDAnimationCurve* curve);
/** Removes the curve affecting a value of the animated element.
@param index The value index.
@return Whether a curve was successfully removed. Will return false
if there was no curve to release or the index is out-of-bounds. */
bool RemoveCurve(size_t index);
/** Retrieves the value of an animated element.
@param index The value index.
@return The value at the given index. This pointer will
be NULL if the index is out-of-boudns. */
inline float* GetValue(size_t index) { FUAssert(index < GetValueCount(), return NULL); return values.at(index); }
inline const float* GetValue(size_t index) const { FUAssert(index < GetValueCount(), return NULL); return values.at(index); } /**< See above. */
/** Retrieves the qualifier of the value of an animated element.
@param index The value index.
@return The qualifier for the value. The value returned will be an
empty string when the index is out-of-bounds. */
inline const string& GetQualifier(size_t index) const;
/** Retrieves an animated value given a valid qualifier.
@param qualifier A valid qualifier.
@return The animated value for this qualifier. This pointer will be
NULL if the given qualifier is not used within this animated element. */
float* FindValue(const string& qualifier);
const float* FindValue(const string& qualifier) const; /**< See above. */
/** Retrieves an animation curve given a valid qualifier.
@param qualifier A valid qualifier.
@return The animation curve for this qualifier. This pointer will be
NULL if the given qualifier is not used within this animated element
or if the value for the given qualifier is not animated. */
inline FCDAnimationCurve* FindCurve(const char* qualifier) { return GetCurve(FindQualifier(qualifier)); }
inline FCDAnimationCurve* FindCurve(const string& qualifier) { return FindCurve(qualifier.c_str()); } /**< See above. */
inline const FCDAnimationCurve* FindCurve(const char* qualifier) const { return GetCurve(FindQualifier(qualifier)); } /**< See above. */
inline const FCDAnimationCurve* FindCurve(const string& qualifier) const { return FindCurve(qualifier.c_str()); } /**< See above. */
/** Retrieves an animation curve given a value pointer.
@param value A value pointer contained within the animated element.
@return The animation curve for this qualifier. This pointer will be
NULL if the value pointer is not contained by this animated element
or if the value is not animated. */
inline FCDAnimationCurve* FindCurve(const float* value) { return GetCurve(FindValue(value)); }
inline const FCDAnimationCurve* FindCurve(const float* value) const { return GetCurve(FindValue(value)); } /**< See above. */
/** Retrieves the value index for a given qualifier.
@param qualifier A valid qualifier.
@return The value index. This value will be -1 to indicate that the
qualifier does not belong to this animated element. */
size_t FindQualifier(const char* qualifier) const;
inline size_t FindQualifier(const string& qualifier) const { return FindQualifier(qualifier.c_str()); } /**< See above. */
/** Retrieves the value index for a given value pointer.
@param value A value pointer contained within the animated element.
@return The value index. This value will be -1 to indicate that the
value pointer is not contained by this animated element. */
size_t FindValue(const float* value) const;
/** Retrieves the array index for an animated element.
This value is used only for animated elements that belong
to a list of animated elements within the COLLADA document.
@return The array index. This value will be -1 to indicate that
the animated element does not belong to a list. */
inline int32 GetArrayElement() const { return arrayElement; }
/** Sets the array index for an animated element.
This value is used only for animated elements that belong
to a list of animated elements within the COLLADA document.
@param index The array index. This value should be -1 to indicate that
the animated element does not belong to a list. */
inline void SetArrayElement(int32 index) { arrayElement = index; }
/** Retrieves whether this animated element has any animation curves
affecting its values.
@return Whether any curves affect this animated element. */
bool HasCurve() const;
/** Creates one multi-dimensional animation curve from this animated element.
This function is useful is your application does not handle animations
per-values, but instead needs one animation per-element.
@return The multi-dimensional animation curve. */
FCDAnimationMultiCurve* CreateMultiCurve() const;
/** Creates one multi-dimensional animation curve from a list of animated element.
This function is useful is your application does not handle animations
per-values. For example, we use this function is ColladaMax for animated scale values,
where one scale value is two rotations for the scale rotation pivot and one
3D point for the scale factors.
@param toMerge The list of animated elements to merge
@return The multi-dimensional animation curve. */
static FCDAnimationMultiCurve* CreateMultiCurve(const FCDAnimatedList& toMerge);
/** Evaluates the animated element at a given time.
This function directly and <b>permanently</b> modifies the values
of the animated element according to the curves affecting them.
@param time The evaluation time. */
void Evaluate(float time);
/** [INTERNAL] Clones an animated element.
@param document The COLLADA document that owns the cloned animated element.
@param animatedValue One animated value contained within the original animated element.
@param newAnimatedValues The list of value pointers to be contained by the cloned animated element.
@return The cloned animated element. */
static FCDAnimated* Clone(FCDocument* document, const float* animatedValue, FloatPtrList& newAnimatedValues);
/** [INTERNAL] Clones an animated element.
@param document The COLLADA document that owns the cloned animated element.
@return The cloned animated element. */
FCDAnimated* Clone(FCDocument* document);
/** [INTERNAL] Retrieves the target pointer that prefixes the
fully-qualified target for the element.
@return The target pointer prefix. */
const string& GetTargetPointer() const { return pointer; }
/** [INTERNAL] Links this animated element with a given XML tree node.
This function is solely used within the import of a COLLADA document.
The floating-point values held within the XML tree node will be linked
with the list of floating-point value pointers held by the animated entity.
@param node The XML tree node.
@return Whether there was any linkage done. */
bool Link(xmlNode* node);
/** [INTERNAL] Links the animated element with the imported animation curves.
This compares the animation channel targets with the animated element target
and qualifiers to assign curves unto the value pointers.
@param channels A list of animation channels with the correct target pointer.
@return Whether any animation curves were assigned to the animation element. */
bool ProcessChannels(FCDAnimationChannelList& channels);
};
/** A COLLADA animated single floating-point value element.
Use this animated element class for all generic-purpose single floating-point values.
For angles, use the FCDAnimatedAngle class.
@ingroup FCDocument */
class FCOLLADA_EXPORT FCDAnimatedFloat : public FCDAnimated
{
private:
// Don't build directly, use the Create function instead
FCDAnimatedFloat(FCDocument* document, float* value, int32 arrayElement);
public:
/** Creates a new animated element.
@param document The COLLADA document that owns the animated element.
@param value The value pointer for the single floating-point value.
@param arrayElement The optional array index for animated element
that belong to an animated element list.
@return The new animated element. */
static FCDAnimatedFloat* Create(FCDocument* document, float* value, int32 arrayElement=-1);
/** [INTERNAL] Creates a new animated element.
This function is used during the import of a COLLADA document.
@param document The COLLADA document that owns the animated element.
@param node The XML tree node that contains the animated values.
@param value The value pointer for the single floating-point value.
@param arrayElement The optional array index for animated element
that belong to an animated element list.
@return The new animated element. */
static FCDAnimatedFloat* Create(FCDocument* document, xmlNode* node, float* value, int32 arrayElement=-1);
/** [INTERNAL] Clones an animated element.
@param document The COLLADA document that owns the cloned animated element.
@param oldValue The single floating-point value pointer contained within the original animated element.
@param newValue The single floating-point value pointer for the cloned animated element.
@return The cloned animated value. */
static FCDAnimated* Clone(FCDocument* document, const float* oldValue, float* newValue);
};
/** A COLLADA animated 3D vector element.
@ingroup FCDocument */
class FCOLLADA_EXPORT FCDAnimatedPoint3 : public FCDAnimated
{
private:
// Don't build directly, use the Create function instead
FCDAnimatedPoint3(FCDocument* document, FMVector3* value, int32 arrayElement);
public:
/** Creates a new animated element.
@param document The COLLADA document that owns the animated element.
@param value The value pointer for the 3D vector.
@param arrayElement The optional array index for animated element
that belong to an animated element list.
@return The new animated element. */
static FCDAnimatedPoint3* Create(FCDocument* document, FMVector3* value, int32 arrayElement=-1);
/** [INTERNAL] Creates a new animated element.
This function is used during the import of a COLLADA document.
@param document The COLLADA document that owns the animated element.
@param node The XML tree node that contains the animated values.
@param value The value pointer for the 3D vector.
@param arrayElement The optional array index for animated element
that belong to an animated element list.
@return The new animated element. */
static FCDAnimatedPoint3* Create(FCDocument* document, xmlNode* node, FMVector3* value, int32 arrayElement=-1);
/** [INTERNAL] Clones an animated element.
@param document The COLLADA document that owns the cloned animated element.
@param oldValue The 3D vector contained within the original animated element.
@param newValue The 3D vector for the cloned animated element.
@return The cloned animated value. */
static FCDAnimated* Clone(FCDocument* document, const FMVector3* oldValue, FMVector3* newValue);
};
/** A COLLADA animated RGB color element.
@ingroup FCDocument */
class FCOLLADA_EXPORT FCDAnimatedColor : public FCDAnimated
{
private:
// Don't build directly, use the Create function instead
FCDAnimatedColor(FCDocument* document, FMVector3* value, int32 arrayElement);
public:
/** Creates a new animated element.
@param document The COLLADA document that owns the animated element.
@param value The value pointer for the RGB color.
@param arrayElement The optional array index for animated element
that belong to an animated element list.
@return The new animated element. */
static FCDAnimatedColor* Create(FCDocument* document, FMVector3* value, int32 arrayElement=-1);
/** [INTERNAL] Creates a new animated element.
This function is used during the import of a COLLADA document.
@param document The COLLADA document that owns the animated element.
@param node The XML tree node that contains the animated values.
@param value The value pointer for the RGB color.
@param arrayElement The optional array index for animated element
that belong to an animated element list.
@return The new animated element. */
static FCDAnimatedColor* Create(FCDocument* document, xmlNode* node, FMVector3* value, int32 arrayElement=-1);
/** [INTERNAL] Clones an animated element.
@param document The COLLADA document that owns the cloned animated element.
@param oldValue The RGB color contained within the original animated element.
@param newValue The RGB color for the cloned animated element.
@return The cloned animated value. */
static FCDAnimated* Clone(FCDocument* document, const FMVector3* oldValue, FMVector3* newValue);
};
/** A COLLADA floating-point value that represents an angle.
@ingroup FCDocument */
class FCOLLADA_EXPORT FCDAnimatedAngle : public FCDAnimated
{
private:
// Don't build directly, use the Create function instead
FCDAnimatedAngle(FCDocument* document, float* value, int32 arrayElement);
public:
/** Creates a new animated element.
@param document The COLLADA document that owns the animated element.
@param value The value pointer for the angle.
@param arrayElement The optional array index for animated element
that belong to an animated element list.
@return The new animated element. */
static FCDAnimatedAngle* Create(FCDocument* document, float* value, int32 arrayElement=-1);
/** [INTERNAL] Creates a new animated element.
This function is used during the import of a COLLADA document.
@param document The COLLADA document that owns the animated element.
@param node The XML tree node that contains the animated values.
@param value The value pointer for the angle.
@param arrayElement The optional array index for animated element
that belong to an animated element list.
@return The new animated element. */
static FCDAnimatedAngle* Create(FCDocument* document, xmlNode* node, float* value, int32 arrayElement=-1);
/** [INTERNAL] Clones an animated element.
@param document The COLLADA document that owns the cloned animated element.
@param oldValue The angle value pointer contained within the original animated element.
@param newValue The angle value pointer for the cloned animated element.
@return The cloned animated value. */
static FCDAnimated* Clone(FCDocument* document, const float* oldValue, float* newValue);
};
/** A COLLADA animated angle-axis.
Used for rotations, takes in a 3D vector for the axis and
a single floating-point value for the angle.
@ingroup FCDocument */
class FCOLLADA_EXPORT FCDAnimatedAngleAxis : public FCDAnimated
{
private:
// Don't build directly, use the Create function instead
FCDAnimatedAngleAxis(FCDocument* document, FMVector3* axis, float* angle, int32 arrayElement);
public:
/** Creates a new animated element.
@param document The COLLADA document that owns the animated element.
@param value The value pointer for the axis.
@param angle The value pointer for the angle.
@param arrayElement The optional array index for animated element
that belong to an animated element list.
@return The new animated element. */
static FCDAnimatedAngleAxis* Create(FCDocument* document, FMVector3* value, float* angle, int32 arrayElement=-1);
/** [INTERNAL] Creates a new animated element.
This function is used during the import of a COLLADA document.
@param document The COLLADA document that owns the animated element.
@param node The XML tree node that contains the animated values.
@param axis The value pointer for the axis.
@param angle The value pointer for the angle.
@param arrayElement The optional array index for animated element
that belong to an animated element list.
@return The new animated element. */
static FCDAnimatedAngleAxis* Create(FCDocument* document, xmlNode* node, FMVector3* axis, float* angle, int32 arrayElement=-1);
/** [INTERNAL] Clones an animated element.
@param document The COLLADA document that owns the cloned animated element.
@param oldAngle The angle value pointer contained within the original animated element.
@param newAxis The axis value pointer for the cloned animated element.
@param newAngle The angle value pointer for the cloned animated element.
@return The cloned animated value. */
static FCDAnimated* Clone(FCDocument* document, const float* oldAngle, FMVector3* newAxis, float* newAngle);
};
/** A COLLADA animated matrix.
Used for animated transforms, takes in a 16 floating-point values.
@ingroup FCDocument */
class FCOLLADA_EXPORT FCDAnimatedMatrix : public FCDAnimated
{
private:
// Don't build directly, use the Create function instead
FCDAnimatedMatrix(FCDocument* document, FMMatrix44* value, int32 arrayElement);
public:
/** Creates a new animated element.
@param document The COLLADA document that owns the animated element.
@param value The value pointer for the matrix.
@param arrayElement The optional array index for animated element
that belong to an animated element list.
@return The new animated element. */
static FCDAnimatedMatrix* Create(FCDocument* document, FMMatrix44* value, int32 arrayElement=-1);
/** [INTERNAL] Creates a new animated element.
This function is used during the import of a COLLADA document.
@param document The COLLADA document that owns the animated element.
@param node The XML tree node that contains the animated values.
@param value The value pointer for the matrix.
@param arrayElement The optional array index for animated element
that belong to an animated element list.
@return The new animated element. */
static FCDAnimatedMatrix* Create(FCDocument* document, xmlNode* node, FMMatrix44* value, int32 arrayElement=-1);
/** [INTERNAL] Clones an animated element.
@param document The COLLADA document that owns the cloned animated element.
@param oldMx The matrix value pointer contained within the original animated element.
@param newMx The matrix value pointer for the cloned animated element.
@return The cloned animated value. */
static FCDAnimated* Clone(FCDocument* document, const FMMatrix44* oldMx, FMMatrix44* newMx);
};
/** A COLLADA custom animated value.
Used for animated extra elements. A single value is used multiple times to hold
as many value pointers are necessary to hold the animation curves.
@ingroup FCDocument */
class FCOLLADA_EXPORT FCDAnimatedCustom : public FCDAnimated
{
private:
float dummy;
// Don't build directly, use the Create function instead
FCDAnimatedCustom(FCDocument* document);
bool Link(xmlNode* node);
public:
/** Creates a new animated element.
@param document The COLLADA document that owns the animated element.
@return The new animated element. */
static FCDAnimatedCustom* Create(FCDocument* document);
/** [INTERNAL] Creates a new animated element.
This function is used during the import of a COLLADA document.
@param document The COLLADA document that owns the animated element.
@param node The XML tree node that contains the animated values.
@return The new animated element. */
static FCDAnimatedCustom* Create(FCDocument* document, xmlNode* node);
/** Retrieves the floating-point value used for all the value pointers.
@return The dummy floating-point value. */
const float& GetDummy() const { return dummy; }
};
#endif // _FCD_ANIMATED_H_

View File

@@ -0,0 +1,224 @@
/*
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/FCDAnimation.h"
#include "FCDocument/FCDAnimationChannel.h"
#include "FUtils/FUDaeParser.h"
using namespace FUDaeParser;
FCDAnimation::FCDAnimation(FCDocument* document) : FCDEntity(document, "Animation")
{
}
FCDAnimation::~FCDAnimation()
{
CLEAR_POINTER_VECTOR(channels);
CLEAR_POINTER_VECTOR(children);
childNodes.clear();
}
// Creates a new animation entity sub-tree contained within this animation entity tree.
FCDAnimation* FCDAnimation::AddChild()
{
FCDAnimation* animation = new FCDAnimation(GetDocument());
children.push_back(animation);
return animation;
}
// Releases an animation entity sub-tree contained by this animation entity tree.
void FCDAnimation::ReleaseChild(FCDAnimation* animation)
{
FCDAnimationList::iterator itA = std::find(children.begin(), children.end(), animation);
if (itA != children.end())
{
delete *itA;
children.erase(itA);
}
}
// Adds a new animation channel to this animation entity.
FCDAnimationChannel* FCDAnimation::AddChannel()
{
FCDAnimationChannel* channel = new FCDAnimationChannel(GetDocument(), this);
channels.push_back(channel);
return channel;
}
// Releases an animation channel contained within this animation entity.
void FCDAnimation::ReleaseChannel(FCDAnimationChannel* channel)
{
FCDAnimationChannelList::iterator itC = std::find(channels.begin(), channels.end(), channel);
if (itC != channels.end())
{
delete *itC;
channels.erase(itC);
}
}
// Optimization: Look for the xml child node with the given id
xmlNode* FCDAnimation::FindChildById(const string& _id)
{
FUCrc32::crc32 id = FUCrc32::CRC32(_id.c_str() + ((_id[0] == '#') ? 1 : 0));
for (FUXmlNodeIdPairList::iterator it = childNodes.begin(); it != childNodes.end(); ++it)
{
if ((*it).id == id) return (*it).node;
}
return NULL;
}
// Look for an animation children with the given COLLADA Id.
FCDEntity* FCDAnimation::FindDaeId(const string& daeId)
{
if (GetDaeId() == daeId) return this;
for (FCDAnimationList::iterator it = children.begin(); it != children.end(); ++it)
{
FCDEntity* found = (*it)->FindDaeId(daeId);
if (found != NULL) return found;
}
return NULL;
}
// Retrieve all the curves created under this animation element, in the animation tree
void FCDAnimation::GetCurves(FCDAnimationCurveList& curves)
{
// Retrieve the curves for this animation tree element
for (FCDAnimationChannelList::iterator it = channels.begin(); it != channels.end(); ++it)
{
const FCDAnimationCurveList& channelCurves = (*it)->GetCurves();
for (FCDAnimationCurveList::const_iterator itC = channelCurves.begin(); itC != channelCurves.end(); ++itC)
{
curves.push_back(*itC);
}
}
// Retrieve the curves for the animation nodes under this one in the animation tree
for (FCDAnimationList::iterator it = children.begin(); it != children.end(); ++it)
{
(*it)->GetCurves(curves);
}
}
FUStatus FCDAnimation::Link()
{
FUStatus status;
// Link the child nodes and check the curves for their drivers
for (FCDAnimationChannelList::iterator it = channels.begin(); it != channels.end(); ++it)
{
status.AppendStatus((*it)->CheckDriver());
}
for (FCDAnimationList::iterator it = children.begin(); it != children.end(); ++it)
{
status.AppendStatus((*it)->Link());
}
return status;
}
// Check for animation curves that need this animated as a driver
bool FCDAnimation::LinkDriver(FCDAnimated* animated)
{
bool driver = false;
// Link the child curves and child nodes
for (FCDAnimationChannelList::iterator it = channels.begin(); it != channels.end(); ++it)
{
driver |= (*it)->LinkDriver(animated);
}
for (FCDAnimationList::iterator it = children.begin(); it != children.end(); ++it)
{
driver |= (*it)->LinkDriver(animated);
}
return driver;
}
// Load a Collada animation node from the XML document
FUStatus FCDAnimation::LoadFromXML(xmlNode* node)
{
FUStatus status = FCDEntity::LoadFromXML(node);
if (!status) return status;
if (!IsEquivalent(node->name, DAE_ANIMATION_ELEMENT))
{
return status.Warning(FS("Animation library contains unknown element."), node->line);
}
// Optimization: Grab all the IDs of the child nodes, in CRC format.
ReadChildrenIds(node, childNodes);
// Parse all the inner <channel> elements
xmlNodeList channelNodes;
FindChildrenByType(node, DAE_CHANNEL_ELEMENT, channelNodes);
channels.reserve(channelNodes.size());
for (xmlNodeList::iterator itC = channelNodes.begin(); itC != channelNodes.end(); ++itC)
{
// Parse each <channel> element individually
// They each handle reading the <sampler> and <source> elements
FCDAnimationChannel* channel = AddChannel();
status.AppendStatus(channel->LoadFromXML(*itC));
if (!status)
{
ReleaseChannel(channel);
}
}
// Parse all the hierarchical <animation> elements
xmlNodeList animationNodes;
FindChildrenByType(node, DAE_ANIMATION_ELEMENT, animationNodes);
for (xmlNodeList::iterator itA = animationNodes.begin(); itA != animationNodes.end(); ++itA)
{
FCDAnimation* animation = AddChild();
animation->LoadFromXML(*itA);
}
return status;
}
// Search for an animation channel for the given XML pointer in this animation node
void FCDAnimation::FindAnimationChannels(const string& pointer, vector<FCDAnimationChannel*>& targetChannels)
{
// Look for channels locally
for (FCDAnimationChannelList::iterator itChannel = channels.begin(); itChannel != channels.end(); ++itChannel)
{
if ((*itChannel)->GetTargetPointer() == pointer)
{
targetChannels.push_back(*itChannel);
}
}
// Look for channel(s) within the child animations
for (FCDAnimationList::iterator it = children.begin(); it != children.end(); ++it)
{
(*it)->FindAnimationChannels(pointer, targetChannels);
}
}
// Write out the COLLADA animations to the document
xmlNode* FCDAnimation::WriteToXML(xmlNode* parentNode) const
{
xmlNode* animationNode = WriteToEntityXML(parentNode, DAE_ANIMATION_ELEMENT);
// Write out the local channels
for (FCDAnimationChannelList::const_iterator itChannel = channels.begin(); itChannel != channels.end(); ++itChannel)
{
(*itChannel)->WriteToXML(animationNode);
}
// Write out the child animations
for (FCDAnimationList::const_iterator it = children.begin(); it != children.end(); ++it)
{
(*it)->WriteToXML(animationNode);
}
FCDEntity::WriteToExtraXML(animationNode);
return animationNode;
}

View File

@@ -0,0 +1,163 @@
/*
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
*/
/**
@file FCDAnimation.h
This file contains the FCDAnimation class.
*/
#ifndef _FCD_ANIMATION_H_
#define _FCD_ANIMATION_H_
#include "FUtils/FUXmlNodeIdPair.h"
#include "FCDocument/FCDEntity.h"
class FCDocument;
class FCDAnimated;
class FCDAnimation;
class FCDAnimationChannel;
class FCDAnimationCurve;
typedef vector<FCDAnimation*> FCDAnimationList; /**< A dynamically-sized array of animation entities. */
typedef vector<FCDAnimationChannel*> FCDAnimationChannelList; /**< A dynamically-sized array of animation channels. */
typedef vector<FCDAnimationCurve*> FCDAnimationCurveList; /**< A dynamically-sized array of animation curves. */
/**
A COLLADA animation entity.
An animation entity contains a list of child animation entities,
in order to form a tree of animation entities.
It also hold a list of animation channels, which hold the information
to generate animation curves.
In other words, the animation entity is a structural class
used to group animation channels hierarchically.
@ingroup FCDocument
*/
class FCOLLADA_EXPORT FCDAnimation : public FCDEntity
{
private:
FCDAnimationChannelList channels;
FUXmlNodeIdPairList childNodes;
FCDAnimationList children;
public:
/** Constructor: do not use directly.
Instead, use the FCDLibrary::AddEntity function
or the AddChild function, depending on the
hierarchical level of the animation entity.
@param document The COLLADA document that owns the animation entity. */
FCDAnimation(FCDocument* document);
/** Destructor: do not use directly.
Instead, use the FCDLibrary::ReleaseEntity function
or the ReleaseChild function, depending on the
hierarchical level of the animation entity.*/
virtual ~FCDAnimation();
/** Retrieves the entity class type.
This function is a part of the FCDEntity interface.
@return The entity class type: ANIMATION. */
virtual Type GetType() const { return ANIMATION; }
/** Retrieves the entity with the given COLLADA id.
This function will look through the local sub-tree of animations
for the given COLLADA id.
@param daeId A COLLADA id.
@return The animation entity that matches the COLLADA id. This pointer
will be NULL if there are no animation entities that matches the COLLADA id. */
virtual FCDEntity* FindDaeId(const string& daeId);
/** Retrieves the number of animation entity sub-trees contained
by this animation entity tree.
@return The number of animation entity sub-trees. */
inline size_t GetChildCount() const { return children.size(); }
/** Retrieves an animation entity sub-tree contained by this
animation entity tree.
@param index The index of the sub-tree.
@return The animation entity sub-tree at the given index. This pointer will
be NULL if the index is out-of-bounds. */
inline FCDAnimation* GetChild(size_t index) { FUAssert(index < GetChildCount(), return NULL); return children.at(index); }
inline const FCDAnimation* GetChild(size_t index) const { FUAssert(index < GetChildCount(), return NULL); return children.at(index); } /**< See above. */
/** Creates a new animation entity sub-tree contained within this animation entity tree.
@return The new animation sub-tree. */
inline FCDAnimation* AddChild();
/** Releases an animation entity sub-tree contained by this animation entity tree.
@param animation The animation entity the release. */
inline void ReleaseChild(FCDAnimation* animation);
/** Retrieves the animation channels that target the given COLLADA target pointer.
@param pointer A COLLADA target pointer.
@param targetChannels A list of animation channels to fill in.
This list is not cleared. */
void FindAnimationChannels(const string& pointer, FCDAnimationChannelList& targetChannels);
/** Retrieves the number of animation channels at this level within the animation tree.
@return The number of animation channels. */
size_t GetChannelCount() const { return channels.size(); }
/** Retrieves an animation channel contained by this animation entity.
@param index The index of the channel.
@return The channel at the given index. This pointer will be NULL
if the index is out-of-bounds. */
FCDAnimationChannel* GetChannel(size_t index) { FUAssert(index < GetChannelCount(), return NULL); return channels.at(index); }
const FCDAnimationChannel* GetChannel(size_t index) const { FUAssert(index < GetChannelCount(), return NULL); return channels.at(index); } /**< See above. */
/** Adds a new animation channel to this animation entity.
@return The new animation channel. */
FCDAnimationChannel* AddChannel();
/** Releases an animation channel contained within this animation entity.
@param channel The animation channel to release. */
void ReleaseChannel(FCDAnimationChannel* channel);
/** Retrieves all the curves created in the subtree of this animation element.
@param curves A list of animation curves to fill in.
This list is not cleared. */
void GetCurves(FCDAnimationCurveList& curves);
/** [INTERNAL] Links the animation sub-tree with the other entities within the document.
This function is used at the end of the import of a document to verify that all the
necessary drivers were found.
@return The status of the linkage. */
FUStatus Link();
/** [INTERNAL] Reads in the animation entity from a given COLLADA XML tree node.
@param animationNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the animation. */
virtual FUStatus LoadFromXML(xmlNode* animationNode);
/** [INTERNAL] Writes out the \<animation\> element to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the animation tree.
@return The created element XML tree node. */
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
/** [INTERNAL] Retrieves the child source or sampler.
This function should only be used by the FCDAnimationChannel class
during the import of a COLLADA document.
@param id The COLLADA id of a sampler or a source.
@return The XML node tree for the sampler or the source. This pointer
will be NULL if there are no child nodes for the given id. */
xmlNode* FindChildById(const string& id);
/** [INTERNAL] Links a possible driver with the animation curves contained
within the subtree of this animation element.
This function is used during the import of a COLLADA document.
@param animated The driver animated value.
@return Whether any linkage was done. */
bool LinkDriver(FCDAnimated* animated);
};
#endif // _FCD_ANIMATION_H_

View File

@@ -0,0 +1,292 @@
/*
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/FCDAnimation.h"
#include "FCDocument/FCDAnimationChannel.h"
#include "FCDocument/FCDAnimationCurve.h"
#include "FCDocument/FCDAnimationMultiCurve.h"
#include "FUtils/FUDaeEnum.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
#include "FUtils/FUStringConversion.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDAnimationChannel::FCDAnimationChannel(FCDocument* document, FCDAnimation* _parent) : FCDObject(document, "FCDAnimationChannel")
{
parent = _parent;
}
FCDAnimationChannel::~FCDAnimationChannel()
{
CLEAR_POINTER_VECTOR(curves);
parent = NULL;
}
FCDAnimationCurve* FCDAnimationChannel::AddCurve()
{
FCDAnimationCurve* curve = new FCDAnimationCurve(GetDocument(), this);
curves.push_back(curve);
return curve;
}
void FCDAnimationChannel::ReleaseCurve(FCDAnimationCurve* curve)
{
FCDAnimationCurveList::iterator itC = std::find(curves.begin(), curves.end(), curve);
if (itC != curves.end())
{
// TODO: IMPLEMENT THIS. NEED RTTI and memory management. In other words, I need time!!! :(.
// delete *itC;
curves.erase(itC);
}
}
// Consider this animated as the curve's driver
bool FCDAnimationChannel::LinkDriver(FCDAnimated* animated)
{
bool driver = !driverPointer.empty();
driver = driver && animated->GetTargetPointer() == driverPointer;
if (driver && driverQualifier >= 0 && (uint32) driverQualifier < animated->GetValueCount())
{
// Retrieve the value pointer for the driver
for (FCDAnimationCurveList::iterator itC = curves.begin(); itC != curves.end(); ++itC)
{
(*itC)->SetDriver(animated->GetValue((uint32) driverQualifier));
}
}
return driver;
}
FUStatus FCDAnimationChannel::CheckDriver()
{
FUStatus status;
if (!driverPointer.empty() && !curves.empty() && curves.front()->GetDriver() == NULL)
{
status.Fail(FS("Unable to find animation curve driver: ") + TO_FSTRING(driverPointer) + FS(" for animation: ") + TO_FSTRING(parent->GetDaeId()));
}
return status;
}
// Load a Collada animation channel from the XML document
FUStatus FCDAnimationChannel::LoadFromXML(xmlNode* channelNode)
{
FUStatus status;
// Read the channel-specific ID
string daeId = ReadNodeId(channelNode);
string samplerId = ReadNodeSource(channelNode);
ReadNodeTargetProperty(channelNode, targetPointer, targetQualifier);
xmlNode* samplerNode = parent->FindChildById(samplerId);
if (samplerNode == NULL || !IsEquivalent(samplerNode->name, DAE_SAMPLER_ELEMENT))
{
return status.Fail(FS("Unable to find sampler node for channel node: ") + TO_FSTRING(daeId), channelNode->line);
}
// Find and process the sources
xmlNode* inputSource = NULL,* outputSource = NULL,* inTangentSource = NULL,* outTangentSource = NULL;
xmlNode* outTangentWeightSource = NULL,* inTangentWeightSource = NULL,* interpolationSource = NULL;
xmlNodeList samplerInputNodes;
FindChildrenByType(samplerNode, DAE_INPUT_ELEMENT, samplerInputNodes);
for (size_t i = 0; i < samplerInputNodes.size(); ++i) // Don't use iterator here because we are possibly appending source nodes in the loop
{
xmlNode* inputNode = samplerInputNodes[i];
string sourceId = ReadNodeSource(inputNode);
xmlNode* sourceNode = parent->FindChildById(sourceId);
string sourceSemantic = ReadNodeSemantic(inputNode);
if (sourceSemantic == DAE_INPUT_ANIMATION_INPUT) inputSource = sourceNode;
else if (sourceSemantic == DAE_OUTPUT_ANIMATION_INPUT) outputSource = sourceNode;
else if (sourceSemantic == DAE_INTANGENT_ANIMATION_INPUT) inTangentSource = sourceNode;
else if (sourceSemantic == DAE_OUTTANGENT_ANIMATION_INPUT) outTangentSource = sourceNode;
else if (sourceSemantic == DAEMAYA_INTANGENTWEIGHT_ANIMATION_INPUT) inTangentWeightSource = sourceNode;
else if (sourceSemantic == DAEMAYA_OUTTANGENTWEIGHT_ANIMATION_INPUT) outTangentWeightSource = sourceNode;
else if (sourceSemantic == DAE_INTERPOLATION_ANIMATION_INPUT) interpolationSource = sourceNode;
}
if (inputSource == NULL || outputSource == NULL)
{
return status.Fail(FS("Missing INPUT or OUTPUT sources in animation channel: ") + TO_FSTRING(parent->GetDaeId()), samplerNode->line);
}
// Calculate the number of curves that in contained by this channel
xmlNode* outputAccessor = FindTechniqueAccessor(outputSource);
string accessorStrideString = ReadNodeProperty(outputAccessor, DAE_STRIDE_ATTRIBUTE);
uint32 curveCount = FUStringConversion::ToUInt32(accessorStrideString);
if (curveCount == 0) curveCount = 1;
// Create the animation curves
curves.reserve(curveCount);
for (uint32 i = 0; i < curveCount; ++i) AddCurve();
// Read in the animation curves
// The input keys are shared by all the curves
ReadSource(inputSource, curves.front()->GetKeys());
for (uint32 i = 1; i < curveCount; ++i) curves[i]->GetKeys() = curves.front()->GetKeys();
// Read in the interleaved outputs and tangents as floats
#define READ_SOURCE_INTERLEAVED(sourceNode, curveArrayPtr) \
if (sourceNode != NULL) { \
vector<FloatList*> arrays(curveCount); \
for (uint32 i = 0; i < curveCount; ++i) { \
arrays[i] = &(curves[i]->curveArrayPtr()); } \
ReadSourceInterleaved(sourceNode, arrays); \
}
READ_SOURCE_INTERLEAVED(outputSource, GetKeyValues)
READ_SOURCE_INTERLEAVED(inTangentSource, GetInTangents)
READ_SOURCE_INTERLEAVED(outTangentSource, GetOutTangents)
READ_SOURCE_INTERLEAVED(inTangentWeightSource, GetInTangentWeights)
READ_SOURCE_INTERLEAVED(outTangentWeightSource, GetOutTangentWeights)
#undef READ_SOURCE_INTERLEAVED
// Read in the interleaved interpolation values, parsing the tokens directly
if (interpolationSource != NULL)
{
vector<UInt32List*> arrays(curveCount);
for (uint32 i = 0; i < curveCount; ++i) arrays[i] = &(curves[i]->GetInterpolations());
ReadSourceInterpolationInterleaved(interpolationSource, arrays);
}
// Read in the pre/post-infinity type
xmlNodeList mayaParameterNodes; StringList mayaParameterNames;
xmlNode* mayaTechnique = FindTechnique(inputSource, DAEMAYA_MAYA_PROFILE);
FindParameters(mayaTechnique, mayaParameterNames, mayaParameterNodes);
size_t parameterCount = mayaParameterNodes.size();
for (size_t i = 0; i < parameterCount; ++i)
{
xmlNode* parameterNode = mayaParameterNodes[i];
const string& paramName = mayaParameterNames[i];
const char* content = ReadNodeContentDirect(parameterNode);
if (paramName == DAEMAYA_PREINFINITY_PARAMETER || paramName == DAEMAYA_PREINFINITY_PARAMETER1_3)
{
for (FCDAnimationCurveList::iterator itC = curves.begin(); itC != curves.end(); ++itC)
{
(*itC)->SetPreInfinity(FUDaeInfinity::FromString(content));
}
}
else if (paramName == DAEMAYA_POSTINFINITY_PARAMETER || paramName == DAEMAYA_POSTINFINITY_PARAMETER1_3)
{
for (FCDAnimationCurveList::iterator itC = curves.begin(); itC != curves.end(); ++itC)
{
(*itC)->SetPostInfinity(FUDaeInfinity::FromString(content));
}
}
else
{
// Look for driven-key input target
if (paramName == DAE_INPUT_ELEMENT)
{
string semantic = ReadNodeSemantic(parameterNode);
if (semantic == DAEMAYA_DRIVER_INPUT)
{
string fullDriverTarget = ReadNodeSource(parameterNode);
const char* driverTarget = FUDaeParser::SkipPound(fullDriverTarget);
if (driverTarget != NULL)
{
string driverQualifierValue;
FUDaeParser::SplitTarget(driverTarget, driverPointer, driverQualifierValue);
driverQualifier = FUDaeParser::ReadTargetMatrixElement(driverQualifierValue);
}
}
}
}
}
// Ready the curves for usage/evaluation.
for (uint32 i = 0; i < curveCount; ++i) curves[i]->Ready();
return status;
}
// Write out the animation curves for an animation channel to a COLLADA document
void FCDAnimationChannel::WriteToXML(xmlNode* parentNode) const
{
string baseId = CleanId(targetPointer);
// Check for curve merging
uint32 realCurveCount = 0;
FCDAnimationCurve* masterCurve = NULL;
bool mergeCurves = true;
for (FCDAnimationCurveList::const_iterator itC = curves.begin(); itC != curves.end(); ++itC)
{
FCDAnimationCurve* curve = (*itC);
if ((*itC) != NULL)
{
++realCurveCount;
if (masterCurve == NULL)
{
masterCurve = curve;
if (masterCurve->GetDriver() != NULL) break;
}
else
{
// Check preliminary information, before verifying the individual keys: key count, infinity types and such..
const FloatList& masterKeys = masterCurve->GetKeys();
const FloatList& curveKeys = curve->GetKeys();
size_t keyCount = masterKeys.size();
mergeCurves &= curveKeys.size() == keyCount && curve->GetPostInfinity() == masterCurve->GetPostInfinity() && curve->GetPreInfinity() == masterCurve->GetPreInfinity();
for (size_t k = 0; k < keyCount && mergeCurves; ++k)
{
mergeCurves = curveKeys[k] == masterKeys[k];
}
}
}
}
if (mergeCurves && realCurveCount > 1)
{
// HACK: Will need to merge the channel and animated classes.
FloatList defaultValues(curves.size(), 0.0f);
// Merge and export the curves
FCDAnimationMultiCurve* multiCurve = FCDAnimationMultiCurve::MergeCurves(curves, defaultValues);
multiCurve->WriteSourceToXML(parentNode, baseId);
multiCurve->WriteSamplerToXML(parentNode, baseId);
multiCurve->WriteChannelToXML(parentNode, baseId, targetPointer);
SAFE_DELETE(multiCurve);
}
else
{
// Interlace the curve's sources, samplers and channels
// Generate new ids for each of the curve's data sources, to avoid collision in special cases
size_t curveCount = curves.size();
StringList ids; ids.resize(curves.size());
FUSStringBuilder curveId;
for (size_t c = 0; c < curveCount; ++c)
{
if (curves[c] != NULL)
{
// Generate a valid id for this curve
curveId.set(baseId);
if (curves[c]->GetTargetElement() >= 0)
{
curveId.append('_'); curveId.append(curves[c]->GetTargetElement()); curveId.append('_');
}
curveId.append(curves[c]->GetTargetQualifier());
ids[c] = CleanId(curveId.ToCharPtr());
// Write out the curve's sources
curves[c]->WriteSourceToXML(parentNode, ids[c]);
}
}
for (size_t c = 0; c < curveCount; ++c)
{
if (curves[c] != NULL) curves[c]->WriteSamplerToXML(parentNode, ids[c]);
}
for (size_t c = 0; c < curveCount; ++c)
{
if (curves[c] != NULL) curves[c]->WriteChannelToXML(parentNode, ids[c], targetPointer.c_str());
}
}
}

View File

@@ -0,0 +1,134 @@
/*
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
*/
/**
@file FCDAnimationChannel.h
This file contains the FCDAnimationChannel class.
*/
#ifndef _FCD_ANIMATION_CHANNEL_H_
#define _FCD_ANIMATION_CHANNEL_H_
#include "FCDocument/FCDObject.h"
class FCDocument;
class FCDAnimated;
class FCDAnimation;
class FCDAnimationCurve;
/** A dynamically-sized array of animation curves. */
typedef vector<FCDAnimationCurve*> FCDAnimationCurveList;
/**
A COLLADA animation channel.
Each animation channel holds the animation curves for one animatable element,
such as a single floating-point value, a 3D vector or a matrix.
@see FCDAnimated
@ingroup FCDocument
*/
class FCOLLADA_EXPORT FCDAnimationChannel : public FCDObject
{
private:
FCDAnimation* parent;
// Channel target
string targetPointer;
string targetQualifier;
// Maya-specific: the driver for this/these curves
string driverPointer;
int32 driverQualifier;
FCDAnimationCurveList curves;
public:
/** Constructor: do not use directly.
Instead, call the FCDAnimation::AddChannel function.
@param document The COLLADA document that owns the animation channel.
@param parent The animation sub-tree that contains the animation channel. */
FCDAnimationChannel(FCDocument* document, FCDAnimation* parent);
/** Destructor: do not use directly.
Instead, call the FCDAnimation::ReleaseChannel function. */
virtual ~FCDAnimationChannel();
/** Retrieves the animation sub-tree that contains the animation channel.
@return The parent animation sub-tree. */
FCDAnimation* GetParent() { return parent; }
const FCDAnimation* GetParent() const { return parent; } /**< See above. */
/** Retrieves the list of animation curves contained within the channel.
@return The list of animation curves. */
const FCDAnimationCurveList& GetCurves() const { return curves; }
/** Retrieves the number of animation curves contained within the channel.
@return The number of animation curves. */
size_t GetCurveCount() const { return curves.size(); }
/** Retrieves an animation curve contained within the channel.
@param index The index of the animation curve.
@return The animation curve at the given index. This pointer will be NULL
if the index is out-of-bounds. */
FCDAnimationCurve* GetCurve(size_t index) { FUAssert(index < GetCurveCount(), return NULL); return curves.at(index); }
const FCDAnimationCurve* GetCurve(size_t index) const { FUAssert(index < GetCurveCount(), return NULL); return curves.at(index); } /**< See above. */
/** Adds a new animation curve to this animation channel.
@return The new animation curve. */
FCDAnimationCurve* AddCurve();
/** Releases an animation curve contained within this channel.
@todo This function is not yet implemented, as it requires
a lot more memory management than FCollada currently does.
@param curve The animation curve to release. */
void ReleaseCurve(FCDAnimationCurve* curve);
/** [INTERNAL] Retrieves the target pointer prefix for this animation channel.
This function is used during the import of a COLLADA document to match the
target pointer prefixes with the animated elements.
@return The target pointer prefix. */
const string& GetTargetPointer() const { return targetPointer; }
/** [INTERNAL] Retrieves the target qualifier for this animation channel.
This function is used during the import of a COLLADA document.
Where there is a target qualifier, there should be only one curve contained by the channel.
@return The target qualifier. This value may be the empty string if the channel
targets all the values targeted by the target pointer prefix. */
const string& GetTargetQualifier() const { return targetQualifier; }
/** [INTERNAL] Enforces the tarrget pointer prefix for the animation channel.
This function is used during the export of a COLLADA document.
@param p The new target pointer prefix. */
void SetTargetPointer(const string& p) { targetPointer = p; }
/** [INTERNAL] Considers the given animated element as the driver for this animation channel.
@param animated An animated element.
@return Whether the animated element is in fact the driver for the animation channel. */
bool LinkDriver(FCDAnimated* animated);
/** [INTERNAL] Verifies that if a driver is used by this channel, then it was found during
the import of the animated elements.
@return The status of the verification. */
FUStatus CheckDriver();
/** [INTERNAL] Reads in the animation channel from a given COLLADA XML tree node.
@param channelNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the animation channel. */
FUStatus LoadFromXML(xmlNode* channelNode);
/** [INTERNAL] Writes out the animation channel to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the animation channel.
@return The created element XML tree node. */
void WriteToXML(xmlNode* parentNode) const;
};
#endif // _FCD_ANIMATION_CHANNEL_H_

View File

@@ -0,0 +1,139 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDocument.h"
#include "FCDocument/FCDAnimation.h"
#include "FCDocument/FCDAnimationChannel.h"
#include "FCDocument/FCDAnimationClip.h"
#include "FCDocument/FCDAnimationCurve.h"
#include "FCDocument/FCDAnimated.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDAnimationClip::FCDAnimationClip(FCDocument* document) : FCDEntity(document, "AnimationClip")
{
start = end = 0.0f;
}
FCDAnimationClip::~FCDAnimationClip()
{
curves.clear();
}
FCDAnimationClip* FCDAnimationClip::Clone()
{
FCDAnimationClip* clone = new FCDAnimationClip(GetDocument());
FCDEntity::Clone(clone);
for(FCDAnimationCurveList::iterator it = curves.begin(); it != curves.end(); ++it)
{
curves.push_back((*it)->Clone());
}
clone->start = start;
clone->end = end;
return clone;
}
FUStatus FCDAnimationClip::LoadFromXML(xmlNode* clipNode)
{
FUStatus status = FCDEntity::LoadFromXML(clipNode);
if (!status) return status;
if (!IsEquivalent(clipNode->name, DAE_ANIMCLIP_ELEMENT))
{
return status.Warning(FS("Unknown element in animation clip library."), clipNode->line);
}
// Read in and verify the clip's time/input bounds
start = FUStringConversion::ToFloat(ReadNodeProperty(clipNode, DAE_START_ATTRIBUTE));
end = FUStringConversion::ToFloat(ReadNodeProperty(clipNode, DAE_END_ATTRIBUTE));
if (end - start < FLT_TOLERANCE)
{
status.Warning(FS("Invalid start/end pair for animation clip: ") + TO_FSTRING(GetDaeId()), clipNode->line);
}
// Read in the <input> elements and segment the corresponding animation curves
xmlNodeList inputNodes;
FindChildrenByType(clipNode, DAE_INSTANCE_ANIMATION_ELEMENT, inputNodes);
for (xmlNodeList::iterator itI = inputNodes.begin(); itI != inputNodes.end(); ++itI)
{
xmlNode* inputNode = (*itI);
// Retrieve the animation for this input
FUUri animationId = ReadNodeUrl(inputNode);
if (animationId.suffix.empty() || !animationId.prefix.empty())
{
return status.Fail(FS("Invalid animation instantiation for animation clip: ") + TO_FSTRING(GetDaeId()), inputNode->line);
}
FCDAnimation* animation = GetDocument()->FindAnimation(animationId.suffix);
if (animation == NULL) continue;
// Retrieve all the curves created under this animation node
FCDAnimationCurveList animationCurves;
animation->GetCurves(animationCurves);
if (animationCurves.empty())
{
status.Warning(FS("No curves instantiated by animation '") + TO_FSTRING(animationId.suffix) + FS("' for animation clip: ") + TO_FSTRING(GetDaeId()), inputNode->line);
}
for (FCDAnimationCurveList::iterator itC = animationCurves.begin(); itC != animationCurves.end(); ++itC)
{
// Keep only newly listed curves
FCDAnimationCurve* curve = *itC;
FCDAnimationCurveList::iterator itF = std::find(curves.begin(), curves.end(), curve);
if (itF == curves.end()) continue;
curve->RegisterAnimationClip(this);
curves.push_back(curve);
}
}
// Check for an empty clip
if (curves.empty())
{
status.Warning(FS("Empty animation clip :") + TO_FSTRING(GetDaeId()), clipNode->line);
}
return status;
}
// Write out the COLLADA animations to the document
xmlNode* FCDAnimationClip::WriteToXML(xmlNode* parentNode) const
{
// Create the <clip> element and write out its start/end information.
xmlNode* clipNode = FCDEntity::WriteToEntityXML(parentNode, DAE_ANIMCLIP_ELEMENT);
AddAttribute(clipNode, DAE_START_ATTRIBUTE, start);
AddAttribute(clipNode, DAE_END_ATTRIBUTE, end);
// Build a list of the animations to instantiate
// from the list of curves for this clip
typedef vector<const FCDAnimation*> FCDAnimationConstList;
FCDAnimationConstList animations;
for (FCDAnimationCurveList::const_iterator itC = curves.begin(); itC != curves.end(); ++itC)
{
const FCDAnimationChannel* channel = (*itC)->GetParent();
if (channel == NULL) continue;
const FCDAnimation* animation = channel->GetParent();
if (std::find(animations.begin(), animations.end(), animation) == animations.end())
{
animations.push_back(animation);
}
}
// Instantiate all the animations
for (FCDAnimationConstList::iterator itA = animations.begin(); itA != animations.end(); ++itA)
{
xmlNode* instanceNode = AddChild(clipNode, DAE_INSTANCE_ANIMATION_ELEMENT);
AddAttribute(instanceNode, DAE_URL_ATTRIBUTE, string("#") + (*itA)->GetDaeId());
}
FCDEntity::WriteToExtraXML(clipNode);
return clipNode;
}

View File

@@ -0,0 +1,46 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#ifndef _FCD_ANIMATION_CLIP_H_
#define _FCD_ANIMATION_CLIP_H_
class FCDocument;
class FCDAnimationCurve;
typedef vector<FCDAnimationCurve*> FCDAnimationCurveList;
#include "FCDocument/FCDEntity.h"
#include "FCDocument/FCDObject.h"
class FCOLLADA_EXPORT FCDAnimationClip : public FCDEntity
{
private:
FCDAnimationCurveList curves;
float start, end;
public:
FCDAnimationClip(FCDocument* document);
virtual ~FCDAnimationClip();
FCDAnimationClip* Clone();
// FCDEntity overrides
virtual Type GetType() const { return ANIMATION_CLIP; }
// Accessors
FCDAnimationCurveList& GetClipCurves() { return curves; }
const FCDAnimationCurveList& GetClipCurves() const { return curves; }
float GetStart() const { return start; }
float GetEnd() const { return end; }
// Load a Collada animation node from the XML document
virtual FUStatus LoadFromXML(xmlNode* clipNode);
// Write out the COLLADA animations to the document
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif // _FCD_ANIMATION_CLIP_H_

View File

@@ -0,0 +1,295 @@
/*
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/FCDAnimationCurve.h"
#include "FCDocument/FCDAnimationClip.h"
#include "FUtils/FUDaeEnum.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeWriter;
FCDAnimationCurve::FCDAnimationCurve(FCDocument* document, FCDAnimationChannel* _parent)
: FCDObject(document, "FCDAnimationCurve"),
parent(_parent),
targetElement(-1),
preInfinity(FUDaeInfinity::CONSTANT),
postInfinity(FUDaeInfinity::CONSTANT),
inputDriver(NULL)
{
}
FCDAnimationCurve::~FCDAnimationCurve()
{
inputDriver = NULL;
parent = NULL;
clips.clear();
}
FCDAnimationCurve* FCDAnimationCurve::Clone()
{
FCDAnimationCurve* clone = new FCDAnimationCurve(GetDocument(), parent);
clone->SetTargetElement(targetElement);
string q;
q.assign(targetQualifier);
clone->SetTargetQualifier(q);
clone->keys = keys;
clone->keyValues = keyValues;
clone->inTangents = inTangents;
clone->outTangents = outTangents;
clone->inTangentWeights = inTangentWeights;
clone->outTangentWeights = outTangentWeights;
clone->isWeightedCurve = isWeightedCurve;
clone->preInfinity = preInfinity;
clone->postInfinity = postInfinity;
clone->inputDriver = inputDriver;
clone->SetDriverPointer(driverPointer);
clone->interpolations = interpolations;
// Animation clips that depend on this curve
for(FCDAnimationClipList::iterator it = clips.begin(); it != clips.end(); ++it)
{
clone->clips.push_back((*it)->Clone());
}
return clone;
}
// Prepare a curve for evaluation
void FCDAnimationCurve::Ready()
{
if (keys.empty()) return;
if (inTangents.empty() || outTangents.empty())
{
// Calculate the bezier tangents
inTangents.resize(keys.size(), 0.0f);
outTangents.resize(keys.size(), 0.0f);
if (keys.size() > 1)
{
for (size_t i = 0; i < keys.size(); ++i)
{
float previousKeySpan = (i > 0) ? keys[i] - keys[i - 1] : keys[i + 1] - keys[i];
float nextKeySpan = (i < keys.size() - 1) ? keys[i + 1] - keys[i] : previousKeySpan;
float currentKeyValue = keyValues[i];
float previousKeyValue = (i > 0) ? keyValues[i - 1] : currentKeyValue;
float nextKeyValue = (i < keys.size() - 1) ? keyValues[i + 1] : currentKeyValue;
float slope = (nextKeyValue - previousKeyValue) / (nextKeySpan + previousKeySpan);
inTangents[i] = previousKeySpan / 3.0f * slope;
outTangents[i] = nextKeySpan / 3.0f * slope;
}
}
}
if (interpolations.empty())
{
// Fill in the array with the default interpolation type
interpolations.resize(keys.size(), FUDaeInterpolation::DEFAULT);
}
isWeightedCurve = !inTangentWeights.empty() && !outTangentWeights.empty();
}
// Main workhorse for the animation system:
// Evaluates the curve for a given input
float FCDAnimationCurve::Evaluate(float input) const
{
if (keys.size() == 1) return keyValues.front();
float outputStart = keyValues.front();
float outputEnd = keyValues.back();
float inputStart = keys.front();
float inputEnd = keys.back();
float inputSpan = inputEnd - inputStart;
// Account for pre-infinity mode
float outputOffset = 0.0f;
if (input <= inputStart)
{
switch (preInfinity)
{
case FUDaeInfinity::CONSTANT: return outputStart;
case FUDaeInfinity::LINEAR: return outputStart + (input - inputStart) * (keyValues[1] - outputStart) / (keys[1] - inputStart);
case FUDaeInfinity::CYCLE: { float cycleCount = ceilf((inputStart - input) / inputSpan); input += cycleCount * inputSpan; break; }
case FUDaeInfinity::CYCLE_RELATIVE: { float cycleCount = ceilf((inputStart - input) / inputSpan); input += cycleCount * inputSpan; outputOffset -= cycleCount * (outputEnd - outputStart); break; }
case FUDaeInfinity::OSCILLATE: { float cycleCount = ceilf((inputStart - input) / (2.0f * inputSpan)); input += cycleCount * 2.0f * inputSpan; input = inputEnd - fabsf(input - inputEnd); break; }
case FUDaeInfinity::UNKNOWN: default: return outputStart;
}
}
// Account for post-infinity mode
else if (input >= inputEnd)
{
switch (postInfinity)
{
case FUDaeInfinity::CONSTANT: return outputEnd;
case FUDaeInfinity::LINEAR: return outputEnd + (input - inputEnd) * (keyValues[keys.size() - 2] - outputEnd) / (keys[keys.size() - 2] - inputEnd);
case FUDaeInfinity::CYCLE: { float cycleCount = ceilf((input - inputEnd) / inputSpan); input -= cycleCount * inputSpan; break; }
case FUDaeInfinity::CYCLE_RELATIVE: { float cycleCount = ceilf((input - inputEnd) / inputSpan); input -= cycleCount * inputSpan; outputOffset += cycleCount * (outputEnd - outputStart); break; }
case FUDaeInfinity::OSCILLATE: { float cycleCount = ceilf((input - inputEnd) / (2.0f * inputSpan)); input -= cycleCount * 2.0f * inputSpan; input = inputStart + fabsf(input - inputStart); break; }
case FUDaeInfinity::UNKNOWN: default: return outputEnd;
}
}
// Find the current interval
uint32 index = 0;
FloatList::const_iterator it;
for (it = keys.begin(); it != keys.end(); ++it, ++index)
{
if ((*it) > input) break;
}
// Get the keys and values for this interval
float endKey = *it;
float startKey = *(it - 1);
float endValue = keyValues[index];
float startValue = keyValues[index - 1];
float output;
// Interpolate the output.
// Similar code is found in FCDAnimationMultiCurve.cpp. If you update this, update the other one too.
uint32 interpolation = interpolations.empty() ? ((uint32) FUDaeInterpolation::DEFAULT) : interpolations[index];
switch (FUDaeInterpolation::Interpolation(interpolation))
{
case FUDaeInterpolation::LINEAR:
output = (input - startKey) / (endKey - startKey) * (endValue - startValue) + startValue;
break;
case FUDaeInterpolation::BEZIER: {
float t = (input - startKey) / (endKey - startKey);
float bValue = startValue + outTangents[index - 1];
float cValue = endValue - inTangents[index];
float ti = 1.0f - t;
output = startValue * ti * ti * ti + 3.0f * bValue * ti * ti * t + 3.0f * cValue * ti * t * t + endValue * t * t * t;
break; }
case FUDaeInterpolation::STEP:
case FUDaeInterpolation::UNKNOWN:
default:
output = startValue;
break;
}
return outputOffset + output;
}
// Apply a conversion function on the key values and tangents
void FCDAnimationCurve::ConvertValues(FCDConversionFunction valueConversion, FCDConversionFunction tangentConversion)
{
size_t keyCount = keys.size();
if (valueConversion != NULL)
{
for (size_t k = 0; k < keyCount; k++)
{
keyValues[k] = (*valueConversion)(keyValues[k]);
}
}
if (tangentConversion != NULL)
{
for (size_t k = 0; k < keyCount; k++)
{
inTangents[k] = (*tangentConversion)(inTangents[k]);
outTangents[k] = (*tangentConversion)(outTangents[k]);
}
}
}
// Apply a conversion function on the key times and tangent weights
void FCDAnimationCurve::ConvertInputs(FCDConversionFunction timeConversion, FCDConversionFunction tangentWeightConversion)
{
size_t keyCount = keys.size();
if (timeConversion != NULL)
{
for (size_t k = 0; k < keyCount; k++)
{
keys[k] = (*timeConversion)(keys[k]);
}
}
if (tangentWeightConversion != NULL)
{
for (size_t k = 0; k < keyCount; k++)
{
inTangentWeights[k] = (*tangentWeightConversion)(inTangentWeights[k]);
outTangentWeights[k] = (*tangentWeightConversion)(outTangentWeights[k]);
}
}
}
// Write out the specific animation elements to the COLLADA xml tree node
void FCDAnimationCurve::WriteSourceToXML(xmlNode* parentNode, const string& baseId) const
{
const char* parameter = targetQualifier.c_str();
if (*parameter == '.') ++parameter;
xmlNode* sourceNode = AddSourceFloat(parentNode, baseId + "-input", keys, "TIME");
AddSourceFloat(parentNode, baseId + "-output", keyValues, parameter);
AddSourceFloat(parentNode, baseId + "-intangents", inTangents, parameter);
AddSourceFloat(parentNode, baseId + "-outtangents", outTangents, parameter);
if (isWeightedCurve && !inTangentWeights.empty())
{
AddSourceFloat(parentNode, baseId + "-intangents_weights", inTangents, parameter);
AddSourceFloat(parentNode, baseId + "-outtangents_weights", outTangents, parameter);
}
AddSourceInterpolation(parentNode, baseId + "-interpolations", *(FUDaeInterpolationList*)&interpolations);
// Export the infinity parameters
xmlNode* mayaTechnique = AddTechniqueChild(sourceNode, DAEMAYA_MAYA_PROFILE);
string infinityType = FUDaeInfinity::ToString(preInfinity);
AddChild(mayaTechnique, DAEMAYA_PREINFINITY_PARAMETER, infinityType);
infinityType = FUDaeInfinity::ToString(postInfinity);
AddChild(mayaTechnique, DAEMAYA_POSTINFINITY_PARAMETER, infinityType);
}
xmlNode* FCDAnimationCurve::WriteSamplerToXML(xmlNode* parentNode, const string& baseId) const
{
xmlNode* samplerNode = AddChild(parentNode, DAE_SAMPLER_ELEMENT);
AddAttribute(samplerNode, DAE_ID_ATTRIBUTE, baseId + "-sampler");
// Add the sampler inputs
AddInput(samplerNode, baseId + "-input", DAE_INPUT_ANIMATION_INPUT);
AddInput(samplerNode, baseId + "-output", DAE_OUTPUT_ANIMATION_INPUT);
AddInput(samplerNode, baseId + "-intangents", DAE_INTANGENT_ANIMATION_INPUT);
AddInput(samplerNode, baseId + "-outtangents", DAE_OUTTANGENT_ANIMATION_INPUT);
if (isWeightedCurve && !inTangentWeights.empty())
{
AddInput(samplerNode, baseId + "-intangents_weights", DAEMAYA_INTANGENTWEIGHT_ANIMATION_INPUT);
AddInput(samplerNode, baseId + "-outtangents_weights", DAEMAYA_OUTTANGENTWEIGHT_ANIMATION_INPUT);
}
AddInput(samplerNode, baseId + "-interpolations", DAE_INTERPOLATION_ANIMATION_INPUT);
// Add the driver input
if (inputDriver != NULL)
{
AddInput(samplerNode, driverPointer, DAEMAYA_DRIVER_INPUT);
}
return samplerNode;
}
xmlNode* FCDAnimationCurve::WriteChannelToXML(xmlNode* parentNode, const string& baseId, const char* targetPointer) const
{
xmlNode* channelNode = AddChild(parentNode, DAE_CHANNEL_ELEMENT);
AddAttribute(channelNode, DAE_SOURCE_ATTRIBUTE, baseId + "-sampler");
// Generate and export the channel target
globalSBuilder.set(targetPointer);
if (targetElement >= 0)
{
globalSBuilder.append('('); globalSBuilder.append(targetElement); globalSBuilder.append(')');
}
globalSBuilder.append(targetQualifier);
AddAttribute(channelNode, DAE_TARGET_ATTRIBUTE, globalSBuilder);
return channelNode;
}

View File

@@ -0,0 +1,262 @@
/*
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
*/
/**
@file FCDAnimationCurve.h
This file contains the FCDAnimationCurve class.
*/
#ifndef _FCD_ANIMATION_CURVE_H_
#define _FCD_ANIMATION_CURVE_H_
#include "FUtils/FUDaeEnum.h"
#include "FCDocument/FCDObject.h"
class FCDAnimationClip;
class FCDAnimationChannel;
typedef vector<FCDAnimationClip*> FCDAnimationClipList; /**< A dynamically-sized array of animation clips. */
typedef float (*FCDConversionFunction)(float v); /**< A simple conversion function. */
/**
A COLLADA single-dimensional animation curve.
An animation curve holds the keyframes necessary
to animate an animatable floating-point value.
There are multiple interpolation mechanisms supported by COLLADA.
FCollada supports the CONSTANT, LINEAR and BEZIER interpolations.
@see FUDaeInterpolation FUDaeInfinity
@ingroup FCDocument
*/
class FCOLLADA_EXPORT FCDAnimationCurve : public FCDObject
{
private:
FCDAnimationChannel* parent;
// Targeting information
int32 targetElement;
string targetQualifier;
// Input information
FloatList keys, keyValues;
FloatList inTangents, outTangents;
FloatList inTangentWeights, outTangentWeights;
bool isWeightedCurve;
FUDaeInfinity::Infinity preInfinity;
FUDaeInfinity::Infinity postInfinity;
// Driver information
const float* inputDriver;
string driverPointer;
// The interpolation values follow the FUDaeInterpolation enum (FUDaeEnum.h)
UInt32List interpolations;
// Animation clips that depend on this curve
FCDAnimationClipList clips;
public:
/** Constructor: do not use directly.
Instead, use the FCDAnimationChannel::AddCurve function.
You should also attach the new curve to an animated
element using the FCDAnimated::SetCurve function.
@param document The COLLADA document that owns the animation curve.
@param parent The animation channel that contains the curve. */
FCDAnimationCurve(FCDocument* document, FCDAnimationChannel* parent);
/** Destructor: do not release directly.
Instead, use the FCDAnimationChannel::ReleaseCurve function. */
virtual ~FCDAnimationCurve();
/** Retrieves the animation channel that contains this animation curve.
@return The parent animation channel. */
inline FCDAnimationChannel* GetParent() { return parent; }
inline const FCDAnimationChannel* GetParent() const { return parent; } /**< See above. */
/** Retrieves the list of key inputs for the animation curve.
@return The list of key inputs. */
inline FloatList& GetKeys() { return keys; }
inline const FloatList& GetKeys() const { return keys; } /**< See above. */
/** Retrieves the list of key outputs for the animation curve.
@return The list of key outputs. */
inline FloatList& GetKeyValues() { return keyValues; }
inline const FloatList& GetKeyValues() const { return keyValues; } /**< See above. */
/** Retrieves the list of interpolation type for the segments of the animation curve.
There is always one interpolation type for each key in the curve. The interpolation type
of a segment of the curve is set at the key at which begins the segment.
@see FUDaeInterpolation
@return The list of interpolation types. */
inline UInt32List& GetInterpolations() { return interpolations; }
inline const UInt32List& GetInterpolations() const { return interpolations; } /**< See above. */
/** Retrieves the list of key in-tangent values for the animation curve.
This list has data only for curves that include segments with the bezier interpolation.
@return The list of in-tangent values. */
inline FloatList& GetInTangents() { return inTangents; }
inline const FloatList& GetInTangents() const { return inTangents; } /**< See above. */
/** Retrieves the list of key out-tangent values for the animation curve.
This list has data only for curves that include segments with the bezier interpolation.
@return The list of out-tangent values. */
inline FloatList& GetOutTangents() { return outTangents; }
inline const FloatList& GetOutTangents() const { return outTangents; } /**< See above. */
/** Retrieves the list of key in-tangent weights for the animation curve.
This list has data only for curves that are weighted
and include segments with the bezier interpolation.
@see IsWeightedCurve
@return The list of in-tangent weights. */
inline FloatList& GetInTangentWeights() { return inTangentWeights; }
inline const FloatList& GetInTangentWeights() const { return inTangentWeights; } /**< See above. */
/** Retrieves the list of key out-tangent weights for the animation curve.
This list has data only for curves that are weighted
and include segments with the bezier interpolation.
@see IsWeightedCurve
@return The list of out-tangent weights. */
inline FloatList& GetOutTangentWeights() { return outTangentWeights; }
inline const FloatList& GetOutTangentWeights() const { return outTangentWeights; } /**< See above. */
/** Retrieves whether this curve has weighted tangents. Tangent weights
give you access to 2D tangents by providing the length of the tangent.
@return Whether this curve has weighted tangents. */
inline bool IsWeightedCurve() const { return isWeightedCurve; }
/** Sets whether this curve has weighted tangents. Tangent weights
give you access to 2D tangents by providing the length of the tangent.
@param _isWeightedCurve Whether this curve has weighted tangents. */
inline void SetWeightedCurveFlag(bool _isWeightedCurve) { isWeightedCurve = _isWeightedCurve; }
/** Retrieves the type of behavior for the curve if the input value is
outside the input interval defined by the curve keys and less than any key input value.
@see FUDaeInfinity
@return The pre-infinity behavior of the curve. */
inline FUDaeInfinity::Infinity GetPreInfinity() const { return preInfinity; }
/** Sets the behavior of the curve if the input value is
outside the input interval defined by the curve keys and less than any key input value.
@see FUDaeInfinity
@param infinity The pre-infinity behavior of the curve. */
inline void SetPreInfinity(FUDaeInfinity::Infinity infinity) { preInfinity = infinity; }
/** Retrieves the type of behavior for the curve if the input value is
outside the input interval defined by the curve keys and greater than any key input value.
@see FUDaeInfinity
@return The post-infinity behavior of the curve. */
inline FUDaeInfinity::Infinity GetPostInfinity() const { return postInfinity; }
/** Sets the behavior of the curve if the input value is
outside the input interval defined by the curve keys and greater than any key input value.
@see FUDaeInfinity
@param infinity The post-infinity behavior of the curve. */
inline void SetPostInfinity(FUDaeInfinity::Infinity infinity) { postInfinity = infinity; }
/** Retrieves the value pointer that drives this animation curve.
@return The driver value pointer. This pointer will be NULL to indicate
that time drives the animation curve. */
inline const float* GetDriver() const { return inputDriver; }
/** Sets the value pointer that drives the animation curve.
@param driver The driver value pointer. Set this pointer to NULL
to indicate that time drives the animation curve. */
inline void SetDriver(const float* driver) { inputDriver = driver; }
/** Retrieves the list of animation clips that use this animation curve.
@return The list of animation clips. */
inline FCDAnimationClipList& GetClips() { return clips; }
inline const FCDAnimationClipList& GetClips() const { return clips; } /**< See above. */
/** Readies this curve for evaluation.
This will create the tangents and the tangent weights, if necessary. */
void Ready();
/** Clones the animation curve.
@return The cloned animation curve. */
FCDAnimationCurve* Clone();
/** Applies a conversion function to the keys output values of the animation curve.
@param valueConversion The conversion function to use on the key outputs.
@param tangentConversion The conversion function to use on the key tangents. */
void ConvertValues(FCDConversionFunction valueConversion, FCDConversionFunction tangentConversion);
/** Applies a conversion function to the keys input values of the animation curve.
@param timeConversion The conversion function to use on the key inputs.
@param tangentWeightConversion The conversion function to use on the key tangent weights. */
void ConvertInputs(FCDConversionFunction timeConversion, FCDConversionFunction tangentWeightConversion);
/** Evaluates the animation curve.
@param input An input value.
@return The sampled value of the curve at the given input value. */
float Evaluate(float input) const;
/** [INTERNAL] Adds an animation clip to the list of animation clips that use this curve.
@param clip An animation clip. */
inline void RegisterAnimationClip(FCDAnimationClip* clip) { clips.push_back(clip); }
/** [INTERNAL] Writes out the data sources necessary to import the animation curve
to a given XML tree node.
@param parentNode The XML tree node in which to create the data sources.
@param baseId A COLLADA Id prefix to use when generating the source ids. */
void WriteSourceToXML(xmlNode* parentNode, const string& baseId) const;
/** [INTERNAL] Writes out the sampler that puts together the data sources
and generates a sampling function.
@param parentNode The XML tree node in which to create the sampler.
@param baseId The COLLADA id prefix used when generating the source ids.
This prefix is also used to generate the sampler COLLADA id.
@return The created XML tree node. */
xmlNode* WriteSamplerToXML(xmlNode* parentNode, const string& baseId) const;
/** [INTERNAL] Writes out the animation channel that attaches the sampling function
to the animatable value.
@param parentNode The XML tree node in which to create the sampler.
@param baseId The COLLADA Id prefix used when generating the source ids
and the sampler id.
@param targetPointer The target pointer prefix for the targeted animated element.
@return The created XML tree node. */
xmlNode* WriteChannelToXML(xmlNode* parentNode, const string& baseId, const char* targetPointer) const;
/** [INTERNAL] Retrieves the target element suffix for the curve.
This will be -1 if the animated element does not belong to an
animated element list.
@return The target element suffix. */
inline int32 GetTargetElement() const { return targetElement; }
/** [INTERNAL] Retrieves the target qualifier for the curve.
This will be the empty string if that the curve affects
a one-dimensional animated element.
@return The target qualifier. */
inline const string& GetTargetQualifier() const { return targetQualifier; }
/** [INTERNAL] Sets the target element suffix for the curve.
@param e The target element suffix. Set to value to -1
if the animated element does not belong to an animated element list. */
inline void SetTargetElement(int32 e) { targetElement = e; }
/** [INTERNAL] Sets the target qualifier for the curve.
@param q The target qualifier. You may sets this string to the empty string
only if that the curve affects a one-dimensional animated element. */
inline void SetTargetQualifier(const string& q) { targetQualifier = q; }
/** [INTERNAL] Retrieves the target pointer prefix of the driver.
@return The driver's target pointer prefix. */
inline const string& GetDriverPointer() const { return driverPointer; }
/** [INTERNAL] Sets the target pointer prefix of the driver.
@param p The driver's target pointer prefix. Set this string to the
empty string if the input of the animation curve is the time. */
inline void SetDriverPointer(const string& p) { driverPointer = p; }
};
#endif // _FCD_ANIMATION_CURVE_H_

View File

@@ -0,0 +1,378 @@
/*
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/FCDAnimationCurve.h"
#include "FCDocument/FCDAnimationMultiCurve.h"
#include "FUtils/FUDaeEnum.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeWriter;
#define SMALL_DELTA 0.001f
FCDAnimationMultiCurve::FCDAnimationMultiCurve(FCDocument* document, uint32 _dimension) : FCDObject(document, "FCDAnimationMultiCurve")
{
dimension = _dimension;
if (dimension == 0) dimension = 1;
// Prepare the target information
targetElement = -1;
targetQualifiers = new string[dimension];
// Allocate the key values and tangents to the wanted dimension
keyValues = new FloatList[dimension];
inTangents = new FloatList[dimension];
outTangents = new FloatList[dimension];
}
FCDAnimationMultiCurve::~FCDAnimationMultiCurve()
{
SAFE_DELETE_ARRAY(targetQualifiers);
SAFE_DELETE_ARRAY(keyValues);
SAFE_DELETE_ARRAY(inTangents);
SAFE_DELETE_ARRAY(outTangents);
}
// Samples all the curves for a given input
void FCDAnimationMultiCurve::Evaluate(float input, float* output) const
{
// Single key curves imply a constant value
if (keys.size() == 1)
{
for (uint32 i = 0; i < dimension; ++i) output[i] = keyValues[i].front();
return;
}
// Find the current interval
uint32 index = 0;
FloatList::const_iterator it;
for (it = keys.begin(); it != keys.end(); ++it, ++index)
{
if ((*it) > input) break;
}
if (it == keys.end())
{
// We're sampling after the curve, return the last values
for (uint32 i = 0; i < dimension; ++i) output[i] = keyValues[i].back();
return;
}
else if (it == keys.begin())
{
// We're sampling before the curve, return the first values
for (uint32 i = 0; i < dimension; ++i) output[i] = keyValues[i].front();
return;
}
// Get the keys and values for this interval
float endKey = *it;
float startKey = *(it - 1);
// Interpolate the outputs.
// Similar code is found in FCDAnimationCurve.cpp. If you update this, update the other one too.
uint32 interpolation = interpolations.empty() ? ((uint32) FUDaeInterpolation::DEFAULT) : interpolations[index];
switch (FUDaeInterpolation::Interpolation(interpolation))
{
case FUDaeInterpolation::LINEAR: {
for (uint32 i = 0; i < dimension; ++i)
{
float startValue = keyValues[i][index - 1];
float endValue = keyValues[i][index];
output[i] = (input - startKey) / (endKey - startKey) * (endValue - startValue) + startValue;
}
break; }
case FUDaeInterpolation::BEZIER: {
for (uint32 i = 0; i < dimension; ++i)
{
float startValue = keyValues[i][index - 1];
float endValue = keyValues[i][index];
float t = (input - startKey) / (endKey - startKey);
float bValue = startValue + outTangents[i][index - 1];
float cValue = endValue - inTangents[i][index];
float ti = 1.0f - t;
output[i] = startValue * ti * ti * ti + 3.0f * bValue * ti * ti * t + 3.0f * cValue * ti * t * t + endValue * t * t * t;
}
break; }
case FUDaeInterpolation::UNKNOWN:
case FUDaeInterpolation::STEP:
default: {
for (uint32 i = 0; i < dimension; ++i)
{
output[i] = keyValues[i][index - 1];
}
break; }
}
}
FCDAnimationMultiCurve* FCDAnimationMultiCurve::MergeCurves(const vector<FCDAnimationCurve*>& _toMerge, const FloatList& defaultValues)
{
vector<const FCDAnimationCurve*> toMerge(_toMerge.size());
for (vector<FCDAnimationCurve*>::const_iterator itC = _toMerge.begin(); itC != _toMerge.end(); ++itC)
{
toMerge.push_back(*itC);
}
return MergeCurves(toMerge, defaultValues);
}
// Non-standard constructor used to merge together animation curves
FCDAnimationMultiCurve* FCDAnimationMultiCurve::MergeCurves(const vector<const FCDAnimationCurve*>& toMerge, const FloatList& defaultValues)
{
size_t dimension = toMerge.size();
if (dimension == 0) return NULL;
// Look for the document pointer
FCDocument* document = NULL;
int32 targetElement = -1;
for (size_t i = 0; i < dimension; ++i)
{
if (toMerge[i] != NULL)
{
document = toMerge[i]->GetDocument();
targetElement = toMerge[i]->GetTargetElement();
}
}
if (document == NULL) return NULL;
// Allocate the output multiCurve.
FCDAnimationMultiCurve* multiCurve = new FCDAnimationMultiCurve(document, (uint32) dimension);
multiCurve->targetElement = targetElement;
// Grab all the animation curve data element right away, to spare me some typing.
FloatList& keys = multiCurve->GetKeys();
FloatList* values = multiCurve->GetKeyValues();
FloatList* inTangents = multiCurve->GetInTangents();
FloatList* outTangents = multiCurve->GetOutTangents();
UInt32List& interpolations = multiCurve->GetInterpolations();
// Calculate the merged input keys
for (size_t i = 0; i < dimension; ++i)
{
const FCDAnimationCurve* curve = toMerge[i];
if (curve == NULL) continue;
const FloatList& curveKeys = curve->GetKeys();
// Merge each curve's keys, which should already be sorted, into the multi-curve's
size_t multiCurveKeyCount = keys.size(), m = 0;
size_t curveKeyCount = curveKeys.size(), c = 0;
while (m < multiCurveKeyCount && c < curveKeyCount)
{
if (IsEquivalent(keys[m], curveKeys[c])) { ++c; ++m; }
else if (keys[m] < curveKeys[c]) { ++m; }
else { keys.insert(keys.begin() + m, curveKeys[c++]); }
}
if (c < curveKeyCount) keys.insert(keys.end(), curveKeys.begin() + c, curveKeys.end());
}
size_t keyCount = keys.size();
// Start with the unknown interpolation everywhere
interpolations.resize(keyCount);
for (UInt32List::iterator it = interpolations.begin(); it != interpolations.end(); ++it)
{
(*it) = (uint32) FUDaeInterpolation::UNKNOWN;
}
// Merge the curves one by one into the multi-curve
for (size_t i = 0; i < dimension; ++i)
{
// Pre-allocate the value and tangent data arrays
values[i].resize(keyCount);
inTangents[i].resize(keyCount);
outTangents[i].resize(keyCount);
const FCDAnimationCurve* curve = toMerge[i];
if (curve == NULL)
{
// No curve, set the default value on all the keys
float defaultValue = (i < defaultValues.size()) ? defaultValues[i] : 0.0f;
for (size_t k = 0; k < keyCount; ++k)
{
values[i][k] = defaultValue;
inTangents[i][k] = 0.0f;
outTangents[i][k] = 0.0f;
}
continue;
}
multiCurve->targetQualifiers[i] = curve->GetTargetQualifier();
// Does the curve have per-key interpolations?
bool hasDefaultInterpolation = curve->GetInterpolations().empty();
// Merge in this curve's values, sampling when the multi-curve's key is not present in the curve.
const FloatList& curveKeys = curve->GetKeys();
size_t curveKeyCount = curveKeys.size();
bool sampleNextInTangent = false;
for (size_t k = 0, c = 0; k < keyCount; ++k)
{
uint32 interpolation;
if (c >= curveKeyCount || !IsEquivalent(keys[k], curveKeys[c]))
{
// Sample the curve
float value = values[i][k] = curve->Evaluate(keys[k]);
// Calculate the in-tangent and the previous key's out-tangent
float span = ((k > 0) ? (keys[k] - keys[k - 1]) : (keys[k + 1] - keys[k])) / 3.0f;
inTangents[i][k] = value - curve->Evaluate(keys[k] - SMALL_DELTA) / SMALL_DELTA * span;
if (k > 0) outTangents[i][k-1] = curve->Evaluate(keys[k - 1] + SMALL_DELTA) / SMALL_DELTA * span - values[i][k-1];
// Calculate the out-tangent and force the sampling of the next key's in-tangent
span = (c < curveKeyCount - 1) ? (keys[k + 1] - keys[k]) / 3.0f : span;
outTangents[i][k] = curve->Evaluate(keys[k] + SMALL_DELTA) / SMALL_DELTA * span - value;
interpolation = FUDaeInterpolation::BEZIER;
sampleNextInTangent = true;
}
else
{
// Keys match, grab the values directly
values[i][k] = curve->GetKeyValues()[c];
outTangents[i][k] = curve->GetOutTangents()[c];
interpolation = hasDefaultInterpolation ? ((uint32) FUDaeInterpolation::DEFAULT) : curve->GetInterpolations()[c];
// Sampling the previous key would require that we sample the inTangent
if (!sampleNextInTangent) inTangents[i][k] = curve->GetInTangents()[c];
else
{
float span = (keys[k] - keys[k - 1]) / 3.0f;
inTangents[i][k] = values[i][k] - curve->Evaluate(keys[k] - SMALL_DELTA) / SMALL_DELTA * span;
}
++c;
}
// Merge the interpolation values, where bezier wins whenever interpolation values differ
uint32& oldInterpolation = interpolations[k];
if (oldInterpolation == FUDaeInterpolation::UNKNOWN) oldInterpolation = interpolation;
else if (oldInterpolation != interpolation) oldInterpolation = FUDaeInterpolation::BEZIER;
}
}
// Reset any unknown interpolation left
for (UInt32List::iterator it = interpolations.begin(); it != interpolations.end(); ++it)
{
if ((*it) == (uint32) FUDaeInterpolation::UNKNOWN) (*it) = FUDaeInterpolation::DEFAULT;
}
return multiCurve;
}
// Collapse this multi-dimensional curve into a one-dimensional curve, given a collapsing function
FCDAnimationCurve* FCDAnimationMultiCurve::Collapse(FCDCollapsingFunction collapse) const
{
size_t keyCount = keys.size();
if (keyCount == 0 || dimension == 0) return NULL;
if (collapse == NULL) collapse = Average;
// Create the output one-dimensional curve and retrieve its data list
FCDAnimationCurve* out = new FCDAnimationCurve(GetDocument(), NULL);
out->SetTargetElement(targetElement);
FloatList& outKeys = out->GetKeys();
FloatList& outKeyValues = out->GetKeyValues();
FloatList& outInTangents = out->GetInTangents();
FloatList& outOutTangents = out->GetOutTangents();
UInt32List& outInterpolations = out->GetInterpolations();
// Pre-allocate the output arrays
outKeys.resize(keyCount);
outKeyValues.resize(keyCount);
outInTangents.resize(keyCount);
outOutTangents.resize(keyCount);
outInterpolations.resize(keyCount);
// Copy the key data over, collapsing the values
float* buffer = new float[dimension];
for (size_t i = 0; i < keyCount; ++i)
{
outKeys[i] = keys[i];
outInterpolations[i] = interpolations[i];
// Collapse the values and the tangents
# define COLLAPSE(outArray, inArray) \
for (uint32 j = 0; j < dimension; ++j) buffer[j] = inArray[j][i]; \
outArray[i] = (*collapse)(buffer, dimension)
COLLAPSE(outKeyValues, keyValues);
COLLAPSE(outInTangents, inTangents);
COLLAPSE(outOutTangents, outTangents);
# undef COLLAPSE
}
SAFE_DELETE_ARRAY(buffer);
return out;
}
// Write out the specific animation elements to the COLLADA xml tree node
void FCDAnimationMultiCurve::WriteSourceToXML(xmlNode* parentNode, const string& baseId)
{
if (keys.empty() || dimension == 0 || keyValues[0].empty()) return;
// Generate the list of the parameters
typedef const char* pchar;
pchar* parameters = new pchar[dimension];
for (size_t i = 0; i < dimension; ++i)
{
parameters[i] = targetQualifiers[i].c_str();
if (*(parameters[i]) == '.') ++(parameters[i]);
}
// Export the key times
AddSourceFloat(parentNode, baseId + "-input", keys, "TIME");
// Interlace the key values and tangents for the export
size_t valueCount = keyValues[0].size();
FloatList sourceData; sourceData.reserve(dimension * valueCount);
for (size_t v = 0; v < valueCount; ++v) for (uint32 n = 0; n < dimension; ++n) sourceData.push_back(keyValues[n].at(v));
AddSourceFloat(parentNode, baseId + "-output", sourceData, dimension, parameters);
sourceData.clear();
for (size_t v = 0; v < valueCount; ++v) for (uint32 n = 0; n < dimension; ++n) sourceData.push_back(inTangents[n].at(v));
AddSourceFloat(parentNode, baseId + "-intangents", sourceData, dimension, parameters);
sourceData.clear();
for (size_t v = 0; v < valueCount; ++v) for (uint32 n = 0; n < dimension; ++n) sourceData.push_back(outTangents[n].at(v));
AddSourceFloat(parentNode, baseId + "-outtangents", sourceData, dimension, parameters);
// Weights not yet supported on multi-curve
AddSourceInterpolation(parentNode, baseId + "-interpolations", *(FUDaeInterpolationList*)&interpolations);
}
xmlNode* FCDAnimationMultiCurve::WriteSamplerToXML(xmlNode* parentNode, const string& baseId)
{
xmlNode* samplerNode = AddChild(parentNode, DAE_SAMPLER_ELEMENT);
AddAttribute(samplerNode, DAE_ID_ATTRIBUTE, baseId + "-sampler");
// Add the sampler inputs
AddInput(samplerNode, baseId + "-input", DAE_INPUT_ANIMATION_INPUT);
AddInput(samplerNode, baseId + "-output", DAE_OUTPUT_ANIMATION_INPUT);
AddInput(samplerNode, baseId + "-intangents", DAE_INTANGENT_ANIMATION_INPUT);
AddInput(samplerNode, baseId + "-outtangents", DAE_OUTTANGENT_ANIMATION_INPUT);
AddInput(samplerNode, baseId + "-interpolations", DAE_INTERPOLATION_ANIMATION_INPUT);
return samplerNode;
}
xmlNode* FCDAnimationMultiCurve::WriteChannelToXML(xmlNode* parentNode, const string& baseId, const string& pointer)
{
xmlNode* channelNode = AddChild(parentNode, DAE_CHANNEL_ELEMENT);
AddAttribute(channelNode, DAE_SOURCE_ATTRIBUTE, baseId + "-sampler");
// Generate and export the full target [no qualifiers]
globalSBuilder.set(pointer);
if (targetElement >= 0)
{
globalSBuilder.append('('); globalSBuilder.append(targetElement); globalSBuilder.append(')');
}
AddAttribute(channelNode, DAE_TARGET_ATTRIBUTE, globalSBuilder);
return channelNode;
}

View File

@@ -0,0 +1,179 @@
/*
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
*/
/**
@file FCDAnimationMultiCurve.h
This file contains the FCDAnimationMultiCurve class.
*/
#ifndef _FCD_ANIMATION_MULTI_CURVE_H_
#define _FCD_ANIMATION_MULTI_CURVE_H_
class FCDocument;
#include "FCDocument/FCDObject.h"
typedef float (*FCDConversionFunction)(float v); /**< A simple conversion function. */
typedef float (*FCDCollapsingFunction)(float* values, uint32 count); /**< A collapsing function. It converts multiple floating-point values into one floating-point value. */
/**
A COLLADA multi-dimensional animation curve.
This is a utility class that is used to convert multiple
animation curves into one animation curve that has multiple
dimensions, but only one list of key inputs.
FCollada will never create a multi-dimensional animation curve
during the import of a COLLADA document.
@ingroup FCDocument
*/
class FCOLLADA_EXPORT FCDAnimationMultiCurve : public FCDObject
{
private:
// The number of merged curves
uint32 dimension;
// Target information
int32 targetElement;
string* targetQualifiers;
// Input information
FloatList keys,* keyValues;
FloatList* inTangents,* outTangents;
// The interpolation values follow the FUDaeInterpolation enum (FUDaeEnum.h)
UInt32List interpolations;
public:
/** Constructor.
The number of dimensions will not change in the lifetime of a
multi-dimensional curve.
@param document The COLLADA document that owns the animation curve.
@param dimension The number of dimensions for the animation curve. */
FCDAnimationMultiCurve(FCDocument* document, uint32 dimension);
/** Destructor. */
virtual ~FCDAnimationMultiCurve();
/** Merges multiple single-dimensional animation curves into one
multi-dimensional animation curve.
For each NULL element found within the 'toMerge' list, the corresponding
default value is used. If there are not enough default values provided, zero is assumed.
The number of dimensions for the output animation curve is taken as the size of the 'toMerge' list.
@param toMerge The list of single-dimensional animation curves to merge. This list may
contain NULL elements, as explained above.
@param defaultValues The list of default values to use when a NULL element is encountered.
Default values should be provided even for the elements that are not NULL. */
static FCDAnimationMultiCurve* MergeCurves(const vector<FCDAnimationCurve*>& toMerge, const FloatList& defaultValues);
static FCDAnimationMultiCurve* MergeCurves(const vector<const FCDAnimationCurve*>& toMerge, const FloatList& defaultValues); /**< See above. */
/** Retrieves the number of dimensions for the curve.
@return The number of dimensions for the curve. */
inline uint32 GetDimension() const { return dimension; }
/** Retrieves the list of key inputs for the animation curve.
@return The list of key inputs. */
inline FloatList& GetKeys() { return keys; }
inline const FloatList& GetKeys() const { return keys; } /**< See above. */
/** Retrieves the lists of key outputs for the animation curve.
There is one separate list of key outputs for each dimension of the curve.
@return The lists of key outputs. */
inline FloatList* GetKeyValues() { return keyValues; }
inline const FloatList* GetKeyValues() const { return keyValues; } /**< See above. */
/** Retrieves the lists of key in-tangent values for the animation curve.
These lists have data only if the curve includes segments with the bezier interpolation.
There is one separate list of key in-tangent values for each dimension of the curve.
@return The lists of in-tangent values. */
inline FloatList* GetInTangents() { return inTangents; }
inline const FloatList* GetInTangents() const { return inTangents; } /**< See above. */
/** Retrieves the lists of key out-tangent values for the animation curve.
These lists have data only if the curve includes segments with the bezier interpolation.
There is one separate list of key out-tangent values for each dimension of the curve.
@return The lists of out-tangent values. */
inline FloatList* GetOutTangents() { return outTangents; }
inline const FloatList* GetOutTangents() const { return outTangents; } /**< See above. */
/** Retrieves the list of interpolation type for the segments of the animation curve.
There is always one interpolation type for each key in the curve. The interpolation type
of a segment of the curve is set at the key at which begins the segment.
@see FUDaeInterpolation
@return The list of interpolation types. */
inline UInt32List& GetInterpolations() { return interpolations; }
inline const UInt32List& GetInterpolations() const { return interpolations; } /**< See above. */
/** Evaluates the animation curve.
@param input An input value.
@param output An array of floating-point values to fill in with the sampled values. */
void Evaluate(float input, float* output) const;
/** Collapses this multi-dimensional curve into a one-dimensional curve.
@param collapse The function to use to collapse multiple floating-point
values into one. Set this to NULL to use the default collapsing
function, which averages all the values.
@see Average TakeFirst */
FCDAnimationCurve* Collapse(FCDCollapsingFunction collapse=NULL) const;
/** [INTERNAL] Writes out the data sources necessary to import the animation curve
to a given XML tree node.
@param parentNode The XML tree node in which to create the data sources.
@param baseId A COLLADA Id prefix to use when generating the source ids. */
void WriteSourceToXML(xmlNode* parentNode, const string& baseId);
/** [INTERNAL] Writes out the sampler that puts together the data sources
and generates a sampling function.
@param parentNode The XML tree node in which to create the sampler.
@param baseId The COLLADA id prefix used when generating the source ids.
This prefix is also used to generate the sampler COLLADA id.
@return The created XML tree node. */
xmlNode* WriteSamplerToXML(xmlNode* parentNode, const string& baseId);
/** [INTERNAL] Writes out the animation channel that attaches the sampling function
to the animatable value.
@param parentNode The XML tree node in which to create the sampler.
@param baseId The COLLADA Id prefix used when generating the source ids
and the sampler id.
@param pointer The target pointer prefix for the targeted animated element.
@return The created XML tree node. */
xmlNode* WriteChannelToXML(xmlNode* parentNode, const string& baseId, const string& pointer);
/** [INTERNAL] Retrieves the target element suffix for the curve.
This will be -1 if the animated element does not belong to an
animated element list.
@return The target element suffix. */
inline int32 GetTargetElement() const { return targetElement; }
/** [INTERNAL] Sets the target element suffix for the curve.
@param e The target element suffix. Set to value to -1
if the animated element does not belong to an animated element list. */
inline void SetTargetElement(int32 e) { targetElement = e; }
};
/**
Retrieves the first floating-point value of a list of floating-point values.
This is a typical conversion function.
@param values The list of floating-point values.
@param count The number of values within the given list.
*/
inline float TakeFirst(float* values, uint32 count) { return (count > 0) ? *values : 0.0f; }
/**
Retrieves the average value of a list of floating-point values.
This is a typical conversion function.
@param values The list of floating-point values.
@param count The number of values within the given list.
*/
inline float Average(float* values, uint32 count) { float v = 0.0f; for (uint32 i = 0; i < count; ++i) v += values[i]; v /= float(count); return v; }
#endif // _FCD_ANIMATION_MULTI_CURVE_H_

View File

@@ -0,0 +1,207 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FUtils/FUDateTime.h"
#include "FCDocument/FCDAsset.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDAsset::FCDAsset(FCDocument* document) : FCDObject(document, "FCDAsset")
{
unitConversionFactor = 1.0f;
unitName = FC("meter");
upAxis = FMVector3::YAxis;
creationDateTime = modifiedDateTime = FUDateTime::GetNow();
}
FCDAsset::~FCDAsset()
{
while(!contributors.empty())
{
SAFE_DELETE(contributors.back());
contributors.pop_back();
}
}
// Insert a new contributor within the list
FCDAssetContributor* FCDAsset::AddContributor()
{
FCDAssetContributor* contributor = new FCDAssetContributor(GetDocument());
contributors.push_back(contributor);
return contributor;
}
// Read in the <asset> element from a COLLADA xml document
FUStatus FCDAsset::LoadFromXML(xmlNode* assetNode)
{
FUStatus status;
bool isPreCollada1_4 = false;
for (xmlNode* child = assetNode->children; child != NULL; child = child->next)
{
if (child->type != XML_ELEMENT_NODE) continue;
const char* content = ReadNodeContentDirect(child);
if (IsEquivalent(child->name, DAE_CONTRIBUTOR_ASSET_ELEMENT))
{
FCDAssetContributor* contributor = new FCDAssetContributor(GetDocument());
contributors.push_back(contributor);
status.AppendStatus(contributor->LoadFromXML(child, false));
}
else if (IsEquivalent(child->name, DAE_CREATED_ASSET_PARAMETER))
{
FUStringConversion::ToDateTime(content, creationDateTime);
}
else if (IsEquivalent(child->name, DAE_KEYWORDS_ASSET_PARAMETER))
{
keywords = TO_FSTRING(content);
}
else if (IsEquivalent(child->name, DAE_MODIFIED_ASSET_PARAMETER))
{
FUStringConversion::ToDateTime(content, modifiedDateTime );
}
else if (IsEquivalent(child->name, DAE_REVISION_ASSET_PARAMETER))
{
revision = TO_FSTRING(content);
}
else if (IsEquivalent(child->name, DAE_SUBJECT_ASSET_PARAMETER))
{
subject = TO_FSTRING(content);
}
else if (IsEquivalent(child->name, DAE_TITLE_ASSET_PARAMETER))
{
title = TO_FSTRING(content);
}
else if (IsEquivalent(child->name, DAE_UNITS_ASSET_PARAMETER))
{
unitName = TO_FSTRING(ReadNodeName(child));
unitConversionFactor = FUStringConversion::ToFloat(ReadNodeProperty(child, DAE_METERS_ATTRIBUTE));
if (unitName.empty()) unitName = FC("UNKNOWN");
if (IsEquivalent(unitConversionFactor, 0.0f) || unitConversionFactor < 0.0f) unitConversionFactor = 1.0f;
}
else if (IsEquivalent(child->name, DAE_UPAXIS_ASSET_PARAMETER))
{
if (IsEquivalent(content, DAE_X_UP)) upAxis = FMVector3::XAxis;
else if (IsEquivalent(content, DAE_Y_UP)) upAxis = FMVector3::YAxis;
else if (IsEquivalent(content, DAE_Z_UP)) upAxis = FMVector3::ZAxis;
}
else if (IsEquivalent(child->name, DAE_AUTHOR_ASSET_PARAMETER) || IsEquivalent(child->name, DAE_AUTHORINGTOOL_ASSET_PARAMETER)
|| IsEquivalent(child->name, DAE_COMMENTS_ASSET_PARAMETER) || IsEquivalent(child->name, DAE_SOURCEDATA_ASSET_PARAMETER)
|| IsEquivalent(child->name, DAE_COPYRIGHT_ASSET_PARAMETER))
{
isPreCollada1_4 = true;
}
else
{
status.Warning(FS("Unknown <asset> child element: ") + TO_FSTRING((const char*) child->name), child->line);
}
}
// COLLADA 1.3 Backward Compatibility: Look for the contributor information within the <asset> element
if (isPreCollada1_4)
{
FCDAssetContributor* contributor = new FCDAssetContributor(GetDocument());
contributor->LoadFromXML(assetNode, true);
if (!contributor->IsEmpty()) contributors.push_back(contributor);
else SAFE_DELETE(contributor);
}
return status;
}
// Write out the <asset> element to a COLLADA xml node tree
xmlNode* FCDAsset::WriteToXML(xmlNode* parentNode) const
{
xmlNode* assetNode = AddChild(parentNode, DAE_ASSET_ELEMENT);
// Update the 'last modified time'
FCDAsset* hackedAsset = const_cast<FCDAsset*>(this);
hackedAsset->modifiedDateTime = FUDateTime::GetNow();
// Write out the contributors first.
for (FCDAssetContributorList::const_iterator itC = contributors.begin(); itC != contributors.end(); ++itC)
{
(*itC)->WriteToXML(assetNode);
}
// Write out the parameters, one by one and in the correct order.
AddChild(assetNode, DAE_CREATED_ASSET_PARAMETER, FUStringConversion::ToString(creationDateTime));
if (!keywords.empty()) AddChild(assetNode, DAE_KEYWORDS_ASSET_PARAMETER, keywords);
AddChild(assetNode, DAE_MODIFIED_ASSET_PARAMETER, FUStringConversion::ToString(modifiedDateTime));
if (!revision.empty()) AddChild(assetNode, DAE_REVISION_ASSET_PARAMETER, revision);
if (!subject.empty()) AddChild(assetNode, DAE_SUBJECT_ASSET_PARAMETER, subject);
if (!title.empty()) AddChild(assetNode, DAE_TITLE_ASSET_PARAMETER, title);
// Finally: <unit> and <up_axis>
xmlNode* unitNode = AddChild(assetNode, DAE_UNITS_ASSET_PARAMETER);
AddAttribute(unitNode, DAE_METERS_ATTRIBUTE, unitConversionFactor);
AddAttribute(unitNode, DAE_NAME_ATTRIBUTE, unitName);
AddChild(assetNode, DAE_UPAXIS_ASSET_PARAMETER, FUStringConversion::ToString(subject));
return assetNode;
}
FCDAssetContributor::FCDAssetContributor(FCDocument* document) : FCDObject(document, "FCDAssetContributor") {}
FCDAssetContributor::~FCDAssetContributor() {}
// Returns whether this contributor element contain any valid data
bool FCDAssetContributor::IsEmpty() const
{
return author.empty() && authoringTool.empty() && comments.empty() && copyright.empty() && sourceData.empty();
}
// Read in the <asset><contributor> element from a COLLADA xml document
FUStatus FCDAssetContributor::LoadFromXML(xmlNode* contributorNode, bool isPreCollada1_4)
{
FUStatus status;
for (xmlNode* child = contributorNode->children; child != NULL; child = child->next)
{
if (child->type != XML_ELEMENT_NODE) continue;
const char* content = ReadNodeContentDirect(child);
if (IsEquivalent(child->name, DAE_AUTHOR_ASSET_PARAMETER))
{
author = TO_FSTRING(content);
}
else if (IsEquivalent(child->name, DAE_AUTHORINGTOOL_ASSET_PARAMETER))
{
authoringTool = TO_FSTRING(content);
}
else if (IsEquivalent(child->name, DAE_COMMENTS_ASSET_PARAMETER))
{
comments = TO_FSTRING(content);
}
else if (IsEquivalent(child->name, DAE_COPYRIGHT_ASSET_PARAMETER))
{
copyright = TO_FSTRING(content);
}
else if (IsEquivalent(child->name, DAE_SOURCEDATA_ASSET_PARAMETER))
{
sourceData = TO_FSTRING(content);
}
else if (!isPreCollada1_4)
{
status.Warning(FS("Unknown <asset><contributor> child element: ") + TO_FSTRING((const char*) child->name), child->line);
}
}
return status;
}
// Write out the <asset><contributor> element to a COLLADA xml node tree
xmlNode* FCDAssetContributor::WriteToXML(xmlNode* parentNode) const
{
xmlNode* contributorNode = NULL;
if (!IsEmpty())
{
contributorNode = AddChild(parentNode, DAE_CONTRIBUTOR_ASSET_ELEMENT);
if (!author.empty()) AddChild(contributorNode, DAE_AUTHOR_ASSET_PARAMETER, author);
if (!authoringTool.empty()) AddChild(contributorNode, DAE_AUTHORINGTOOL_ASSET_PARAMETER, authoringTool);
if (!comments.empty()) AddChild(contributorNode, DAE_COMMENTS_ASSET_PARAMETER, comments);
if (!copyright.empty()) AddChild(contributorNode, DAE_COPYRIGHT_ASSET_PARAMETER, copyright);
if (!sourceData.empty()) AddChild(contributorNode, DAE_SOURCEDATA_ASSET_PARAMETER, sourceData);
}
return contributorNode;
}

View File

@@ -0,0 +1,109 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#ifndef _FCD_ASSET_H_
#define _FCD_ASSET_H_
#include "FCDocument/FCDObject.h"
#include "FUtils/FUDateTime.h"
class FCDAssetContributor;
typedef vector<FCDAssetContributor*> FCDAssetContributorList;
class FCOLLADA_EXPORT FCDAsset : public FCDObject
{
FCDAssetContributorList contributors;
FUDateTime creationDateTime;
FUDateTime modifiedDateTime;
fstring keywords;
fstring revision;
fstring subject;
fstring title;
FMVector3 upAxis;
// <unit>
fstring unitName;
float unitConversionFactor;
public:
FCDAsset(FCDocument* document);
virtual ~FCDAsset();
// Direct contributor list access
inline FCDAssetContributorList& GetContributors() { return contributors; }
inline const FCDAssetContributorList& GetContributors() const { return contributors; }
inline size_t GetContributorCount() const { return contributors.size(); }
inline FCDAssetContributor* GetContributor(size_t index) { return index < contributors.size() ? contributors[index] : NULL; }
inline const FCDAssetContributor* GetContributor(size_t index) const { return index < contributors.size() ? contributors[index] : NULL; }
FCDAssetContributor* AddContributor();
// Direct accessors
inline const FUDateTime& GetCreationDateTime() const { return creationDateTime; }
inline const FUDateTime& GetModifiedDateTime() const { return modifiedDateTime; }
inline const fstring& GetKeywords() const { return keywords; }
inline const fstring& GetRevision() const { return revision; }
inline const fstring& GetSubject() const { return subject; }
inline const fstring& GetTitle() const { return title; }
inline const FMVector3& GetUpAxis() const { return upAxis; }
inline const fstring& GetUnitName() const { return unitName; }
inline float GetUnitConversionFactor() const { return unitConversionFactor; }
// Direct mutators
inline void SetKeywords(const fstring& _keywords) { keywords = _keywords; }
inline void SetRevision(const fstring& _revision) { revision = _revision; }
inline void SetSubject(const fstring& _subject) { subject = _subject; }
inline void SetTitle(const fstring& _title) { title = _title; }
inline void SetUpAxis(const FMVector3& _upAxis) { upAxis = _upAxis; }
inline void SetUnitName(const fstring& _unitName) { unitName = _unitName; }
inline void SetUnitConversionFactor(float factor) { unitConversionFactor = factor; }
// Read in the <asset> element from a COLLADA xml document
FUStatus LoadFromXML(xmlNode* assetNode);
// Write out the <asset> element to a COLLADA xml node tree
// Calling this function will update the 'last modified' timestamp.
xmlNode* WriteToXML(xmlNode* parentNode) const;
};
// Encapsulates the <asset><contributor> element
class FCOLLADA_EXPORT FCDAssetContributor : public FCDObject
{
private:
fstring author;
fstring authoringTool;
fstring comments;
fstring copyright;
fstring sourceData;
public:
FCDAssetContributor(FCDocument* document);
virtual ~FCDAssetContributor();
// Direct accessors
inline const fstring& GetAuthor() const { return author; }
inline const fstring& GetAuthoringTool() const { return authoringTool; }
inline const fstring& GetComments() const { return comments; }
inline const fstring& GetCopyright() const { return copyright; }
inline const fstring& GetSourceData() const { return sourceData; }
// Direct mutators
inline void SetAuthor(const fstring& _author) { author = _author; }
inline void SetAuthoringTool(const fstring& _authoringTool) { authoringTool = _authoringTool; }
inline void SetComments(const fstring& _comments) { comments = _comments; }
inline void SetCopyright(const fstring& _copyright) { copyright = _copyright; }
inline void SetSourceData(const fstring& _sourceData) { sourceData = _sourceData; }
// Returns whether this contributor element contain any valid data
bool IsEmpty() const;
// Read in the <asset><contributor> element from a COLLADA xml document
FUStatus LoadFromXML(xmlNode* contributorNode, bool isPreCollada1_4=false);
// Write out the <asset><contributor> element to a COLLADA xml node tree
xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif // _FCD_ASSET_H_

View File

@@ -0,0 +1,268 @@
/*
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/FCDCamera.h"
#include "FCDocument/FCDocument.h"
#include "FCDocument/FCDAnimated.h"
#include "FCDocument/FCDSceneNode.h"
#include "FUtils/FUStringConversion.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDCamera::FCDCamera(FCDocument* document) : FCDTargetedEntity(document, "Camera")
{
isPerspective = true;
isOrthographic = false;
viewY = viewX = 60.0f;
hasAperture = hasHorizontalView = hasVerticalView = false;
nearZ = 1.0f;
farZ = 1000.0f;
aspectRatio = 1.0f;
horizontalAperture = verticalAperture = lensSqueeze = 1.0f;
}
FCDCamera::~FCDCamera()
{
}
void FCDCamera::SetFovX(float _viewX)
{
viewX = _viewX;
if (hasVerticalView && !IsEquivalent(viewX, 0.0f)) aspectRatio = viewY / viewX;
hasHorizontalView = true;
}
void FCDCamera::SetFovY(float _viewY)
{
viewY = _viewY;
if (hasHorizontalView && !IsEquivalent(viewX, 0.0f)) aspectRatio = viewY / viewX;
hasVerticalView = true;
}
void FCDCamera::SetAspectRatio(float _aspectRatio)
{
aspectRatio = _aspectRatio;
}
// Load this camera from the given COLLADA document's node
FUStatus FCDCamera::LoadFromXML(xmlNode* cameraNode)
{
FUStatus status = FCDEntity::LoadFromXML(cameraNode);
if (!status) return status;
if (!IsEquivalent(cameraNode->name, DAE_CAMERA_ELEMENT))
{
return status.Warning(FS("Camera library contains unknown element."), cameraNode->line);
}
// COLLADA 1.3: Grab the techniques and their <optics><program> children
xmlNode* commonTechniqueNode1_3 = FindTechnique(cameraNode, DAE_COMMON_PROFILE);
xmlNode* commonOpticsNode1_3 = FindChildByType(commonTechniqueNode1_3, DAE_OPTICS_ELEMENT);
xmlNode* commonProgramNode1_3 = FindChildByType(commonOpticsNode1_3, DAE_PROGRAM_ELEMENT);
xmlNode* maxTechniqueNode1_3 = FindTechnique(cameraNode, DAEMAX_MAX_PROFILE);
xmlNode* maxOpticsNode1_3 = FindChildByType(maxTechniqueNode1_3, DAE_OPTICS_ELEMENT);
xmlNode* maxProgramNode1_3 = FindChildByType(maxOpticsNode1_3, DAE_PROGRAM_ELEMENT);
xmlNode* mayaTechniqueNode = FindTechnique(cameraNode, DAEMAYA_MAYA_PROFILE);
xmlNode* mayaOpticsNode = FindChildByType(mayaTechniqueNode, DAE_OPTICS_ELEMENT);
xmlNode* mayaProgramNode = FindChildByType(mayaOpticsNode, DAE_PROGRAM_ELEMENT);
bool isCollada1_3 = commonTechniqueNode1_3 != NULL;
// COLLADA 1.4: Grab the <optics> element's techniques
xmlNode* opticsNode = FindChildByType(cameraNode, DAE_OPTICS_ELEMENT);
xmlNode* commonTechniqueNode = FindChildByType(opticsNode, DAE_TECHNIQUE_COMMON_ELEMENT);
xmlNode* maxTechniqueNode = FindTechnique(opticsNode, DAEMAX_MAX_PROFILE);
xmlNode* cameraContainerNode = (isCollada1_3) ? ((maxProgramNode1_3 != NULL) ? maxProgramNode1_3 : commonProgramNode1_3) : NULL;
if (mayaProgramNode == NULL) mayaProgramNode = FindTechnique(opticsNode, DAEMAYA_MAYA_PROFILE);
// Figure out the camera type
if (isCollada1_3)
{
FUUri programType = ReadNodeUrl(maxProgramNode1_3);
if (programType.prefix.empty()) programType = ReadNodeUrl(commonProgramNode1_3);
if (programType.prefix.empty())
{
return status.Fail(FS("No standard program type for camera: ") + TO_FSTRING(GetDaeId()), cameraNode->line);
}
string cameraType = TO_STRING(programType.prefix);
isOrthographic = cameraType == DAE_ORTHOGRAPHIC_CAMERA_TYPE;
isPerspective = cameraType == DAE_PERSPECTIVE_CAMERA_TYPE;
}
else
{
// Retrieve the <perspective> or <orthographic> element
cameraContainerNode = FindChildByType(commonTechniqueNode, DAE_CAMERA_ORTHO_ELEMENT);
isOrthographic = cameraContainerNode != NULL;
if (!isOrthographic)
{
cameraContainerNode = FindChildByType(commonTechniqueNode, DAE_CAMERA_PERSP_ELEMENT);
isPerspective = cameraContainerNode != NULL;
}
else
{
isPerspective = false;
}
}
// Check the necessary camera structures
if (cameraContainerNode == NULL)
{
return status.Fail(FS("Cannot find parameter root node for camera: ") + TO_FSTRING(GetDaeId()), cameraNode->line);
}
if (!(isPerspective ^ isOrthographic))
{
return status.Fail(FS("Unknown program type for camera: ") + TO_FSTRING(GetDaeId()), cameraContainerNode->line);
}
// Setup the camera according to the type and its parameters
// Retrieve all the camera parameters
StringList parameterNames;
xmlNodeList parameterNodes;
FindParameters(cameraContainerNode, parameterNames, parameterNodes);
FindParameters(maxTechniqueNode, parameterNames, parameterNodes);
FindParameters(mayaProgramNode, parameterNames, parameterNodes);
#define CAM_PARAMETER(colladaParam, memberFunction, animatedMember) \
if (parameterName == colladaParam) { \
memberFunction(FUStringConversion::ToFloat(parameterValue)); \
FCDAnimatedFloat::Create(GetDocument(), parameterNode, &animatedMember); } else
size_t parameterCount = parameterNodes.size();
for (size_t i = 0; i < parameterCount; ++i)
{
xmlNode* parameterNode = parameterNodes[i];
const string& parameterName = parameterNames[i];
const char* parameterValue = ReadNodeContentDirect(parameterNode);
// Process the camera parameters
CAM_PARAMETER(DAE_ZNEAR_CAMERA_PARAMETER, SetNearZ, nearZ)
CAM_PARAMETER(DAE_ZFAR_CAMERA_PARAMETER, SetFarZ, farZ)
CAM_PARAMETER(DAE_XFOV_CAMERA_PARAMETER, SetFovX, viewX)
CAM_PARAMETER(DAE_YFOV_CAMERA_PARAMETER, SetFovY, viewY)
CAM_PARAMETER(DAE_XMAG_CAMERA_PARAMETER, SetMagX, viewX)
CAM_PARAMETER(DAE_YMAG_CAMERA_PARAMETER, SetMagY, viewY)
CAM_PARAMETER(DAE_ASPECT_CAMERA_PARAMETER, SetAspectRatio, aspectRatio)
CAM_PARAMETER(DAEMAYA_VAPERTURE_PARAMETER, SetVerticalAperture, verticalAperture)
CAM_PARAMETER(DAEMAYA_HAPERTURE_PARAMETER, SetHorizontalAperture, horizontalAperture)
CAM_PARAMETER(DAEMAYA_LENSSQUEEZE_PARAMETER, SetLensSqueeze, lensSqueeze)
if (parameterName == DAEMAX_TARGET_CAMERA_PARAMETER)
SetTargetId(parameterValue);
else
// COLLADA 1.3 backward compatibility
CAM_PARAMETER(DAE_ZNEAR_CAMERA_PARAMETER1_3, SetNearZ, nearZ)
CAM_PARAMETER(DAE_ZFAR_CAMERA_PARAMETER1_3, SetFarZ, farZ)
CAM_PARAMETER(DAE_XFOV_CAMERA_PARAMETER1_3, SetFovX, viewX)
CAM_PARAMETER(DAE_YFOV_CAMERA_PARAMETER1_3, SetFovY, viewY)
CAM_PARAMETER(DAE_RIGHT_CAMERA_PARAMETER1_3, SetMagX, viewX)
CAM_PARAMETER(DAE_TOP_CAMERA_PARAMETER1_3, SetMagY, viewY)
CAM_PARAMETER(DAEMAYA_VAPERTURE_PARAMETER1_3, SetVerticalAperture, verticalAperture)
CAM_PARAMETER(DAEMAYA_HAPERTURE_PARAMETER1_3, SetHorizontalAperture, horizontalAperture)
CAM_PARAMETER(DAEMAYA_LENSSQUEEZE_PARAMETER1_3, SetLensSqueeze, lensSqueeze)
if (parameterName == DAE_LEFT_CAMERA_PARAMETER1_3) {} // Don't process
else if (parameterName == DAE_BOTTOM_CAMERA_PARAMETER1_3) {} // Don't process
// Max-specific parameter: target
else if (parameterName == DAEMAX_TARGET_CAMERA_PARAMETER
|| parameterName == DAEMAX_TARGET_CAMERA_PARAMETER1_3)
{
SetTargetId(parameterValue);
}
else
{
status.Warning(FS("Unknown parameter for camera: ") + TO_FSTRING(GetDaeId()), parameterNode->line);
}
}
return status;
}
// Write out this camera to the COLLADA XML document
xmlNode* FCDCamera::WriteToXML(xmlNode* parentNode) const
{
// Create the base camera node
xmlNode* cameraNode = WriteToEntityXML(parentNode, DAE_CAMERA_ELEMENT);
xmlNode* opticsNode = AddChild(cameraNode, DAE_OPTICS_ELEMENT);
xmlNode* baseNode = AddChild(opticsNode, DAE_TECHNIQUE_COMMON_ELEMENT);
const char* baseNodeName;
if (isPerspective) baseNodeName = DAE_CAMERA_PERSP_ELEMENT;
else if (isOrthographic) baseNodeName = DAE_CAMERA_ORTHO_ELEMENT;
else baseNodeName = DAEERR_UNKNOWN_ELEMENT;
baseNode = AddChild(baseNode, baseNodeName);
// Write out the basic camera parameters
if (isPerspective)
{
if (hasHorizontalView)
{
xmlNode* viewNode = AddChild(baseNode, DAE_XFOV_CAMERA_PARAMETER, viewX);
GetDocument()->WriteAnimatedValueToXML(&viewX, viewNode, "horizontal_fov");
}
if (!hasHorizontalView || hasVerticalView)
{
xmlNode* viewNode = AddChild(baseNode, DAE_YFOV_CAMERA_PARAMETER, viewY);
GetDocument()->WriteAnimatedValueToXML(&viewY, viewNode, "vertical_fov");
}
if (!hasHorizontalView || !hasVerticalView)
{
xmlNode* aspectNode = AddChild(baseNode, DAE_ASPECT_CAMERA_PARAMETER, aspectRatio);
GetDocument()->WriteAnimatedValueToXML(&aspectRatio, aspectNode, "aspect_ratio");
}
}
if (isOrthographic)
{
if (hasHorizontalView)
{
xmlNode* viewNode = AddChild(baseNode, DAE_XMAG_CAMERA_PARAMETER, viewX);
GetDocument()->WriteAnimatedValueToXML(&viewX, viewNode, "horizontal_zoom");
}
if (!hasHorizontalView || hasVerticalView)
{
xmlNode* viewNode = AddChild(baseNode, DAE_YMAG_CAMERA_PARAMETER, viewY);
GetDocument()->WriteAnimatedValueToXML(&viewY, viewNode, "vertical_zoom");
}
if (!hasHorizontalView || !hasVerticalView)
{
xmlNode* aspectNode = AddChild(baseNode, DAE_ASPECT_CAMERA_PARAMETER, aspectRatio);
GetDocument()->WriteAnimatedValueToXML(&aspectRatio, aspectNode, "aspect_ratio");
}
}
// Near/Far clip plane distance
xmlNode* clipNode = AddChild(baseNode, DAE_ZNEAR_CAMERA_PARAMETER, nearZ);
GetDocument()->WriteAnimatedValueToXML(&nearZ, clipNode, "near_clip");
clipNode = AddChild(baseNode, DAE_ZFAR_CAMERA_PARAMETER, farZ);
GetDocument()->WriteAnimatedValueToXML(&farZ, clipNode, "near_clip");
// Add the application-specific technique/parameters
// Maya has extra aperture information
if (hasAperture)
{
xmlNode* techniqueMayaNode = AddTechniqueChild(opticsNode, DAEMAYA_MAYA_PROFILE);
xmlNode* apertureNode = AddChild(techniqueMayaNode, DAEMAYA_VAPERTURE_PARAMETER, verticalAperture);
GetDocument()->WriteAnimatedValueToXML(&verticalAperture, apertureNode, "vertical_aperture");
apertureNode = AddChild(techniqueMayaNode, DAEMAYA_HAPERTURE_PARAMETER, horizontalAperture);
GetDocument()->WriteAnimatedValueToXML(&horizontalAperture, apertureNode, "horizontal_aperture");
apertureNode = AddChild(techniqueMayaNode, DAEMAYA_LENSSQUEEZE_PARAMETER, lensSqueeze);
GetDocument()->WriteAnimatedValueToXML(&lensSqueeze, apertureNode, "lens_squeeze");
}
// Max has target information
if (GetTargetNode() != NULL)
{
xmlNode* techniqueMaxNode = AddTechniqueChild(opticsNode, DAEMAX_MAX_PROFILE);
AddChild(techniqueMaxNode, DAEMAX_TARGET_CAMERA_PARAMETER, GetTargetNode()->GetDaeId());
}
FCDEntity::WriteToExtraXML(cameraNode);
return cameraNode;
}

View File

@@ -0,0 +1,255 @@
/*
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
*/
/**
@file FCDCamera.h
This file contains the FCDCamera class.
*/
#ifndef _FCD_CAMERA_H_
#define _FCD_CAMERA_H_
#include "FCDocument/FCDTargetedEntity.h"
class FCDocument;
class FCDSceneNode;
/**
A COLLADA camera.
Based on the FCDTargetedEntity class to support aimed cameras.
COLLADA defines two types of cameras: perspective and orthographic.
Both types are fully handled by this class.
A COLLADA perspective camera defines two of the three following parameters: horizontal field of view,
vertical field of view and aspect ratio. The missing parameter can be calculated using the following formulae:
aspect ratio = vertical field of view / horizontal field of view. The vertical and horizontal field
of view are in degrees.
A COLLADA orthographic camera defines two of the three following parameters: horizontal magnification,
vertical magnification and aspect ratio. The missing parameter can be calculated using the following formulae:
aspect ratio = vertical magnification / horizontal magnification. You can calculate the viewport width
and height using the following formulas: viewport width = horizontal magnification * 2, viewport height
= vertical magnification * 2.
@ingroup FCDocument
*/
class FCOLLADA_EXPORT FCDCamera : public FCDTargetedEntity
{
private:
// Camera flags
bool isPerspective;
bool isOrthographic;
bool hasHorizontalView;
bool hasVerticalView;
// Camera parameters
float viewY;
float viewX;
float nearZ;
float farZ;
float aspectRatio;
// Maya parameters
bool hasAperture;
float verticalAperture;
float horizontalAperture;
float lensSqueeze;
public:
/** Constructor: do not use directly. Create new cameras using the FCDLibrary::AddEntity function.
@param document The COLLADA document that contains this camera entity.*/
FCDCamera(FCDocument* document);
/** Destructor: do not release directly. Release cameras using the FCDLibrary::ReleaseEntity function.
All cameras are released with the document that they belong to. */
virtual ~FCDCamera();
/** Retrieves the entity type for this class. This function is part of the FCDEntity interface.
@return The entity type: CAMERA. */
virtual Type GetType() const { return CAMERA; }
/** Retrieves whether this camera is a perspective camera.
This is the default type of camera.
@return Whether this camera is a perspective camera.*/
inline bool IsPerspective() const { return isPerspective; }
/** Sets the type of this camera to perspective. */
inline void SetPerspective() { isPerspective = true; isOrthographic = false; }
/** Retrieves whether the perspective camera defines an horizontal field of view.
If the camera does not define the horizontal field of view, you can calculate
it using the following formula: horizontal field of view = vertical field of view / aspect ratio.
@return Whether the perspective camera defines an horizontal field of view. */
inline bool HasHorizontalFov() const { return hasHorizontalView; }
/** Retrieves whether the perspective camera defines a vertical field of view.
If the camera does not define the vertical field of view, you can calculate
it using the following formula: vertical field of view = aspect ratio * horizontal field of view.
@return Whether the perspective camera defines a vertical field of view. */
inline bool HasVerticalFov() const { return hasVerticalView; }
/** Retrieves the horizontal field of view. Before retrieving this value,
check whether the camera defines the horizontal field of view using the
HasHorizontalFov function.
@return The horizontal field of view, in degrees. */
inline float& GetFovX() { return viewX; }
inline const float& GetFovX() const { return viewX; } /**< See above. */
/** Retrieves the vertical field of view. Before retrieving this value,
check whether the camera defines the vertical field of view using the
HasVerticalFov function.
@return The horizontal field of view, in degrees. */
inline float& GetFovY() { return viewY; }
inline const float& GetFovY() const { return viewY; } /**< See above. */
/** Sets the horizontal field of view value for this camera.
@param fovX The new horizontal field of view, in degrees. */
void SetFovX(float fovX);
/** Sets the vertical field of view value for this camera.
@param fovY The new vertical field of view, in degrees. */
void SetFovY(float fovY);
/** Retrieves whether this camera is an orthographic camera.
@return Whether this camera is an orthographic camera. */
inline bool IsOrthographic() const { return isOrthographic; }
/** Sets the type of this camera to orthographic. */
inline void SetOrthographic() { isPerspective = false; isOrthographic = true; }
/** Retrieves whether the orthographic camera defines an horizontal magnification.
If the camera does not define the horizontal magnification, you can calculate
it using the following formula: horizontal magnification = vertical magnification / aspect ratio.
@return Whether the orthographic camera defines an horizontal magnification. */
inline bool HasHorizontalMag() const { return hasHorizontalView; }
/** Retrieves whether the perspective camera defines a vertical magnification.
If the camera does not define the vertical magnification, you can calculate
it using the following formula: vertical magnification = aspect ratio * horizontal magnification.
@return Whether the perspective camera defines a vertical magnification. */
inline bool HasVerticalMag() const { return hasVerticalView; }
/** Retrieves the horizontal magnification. Before retrieving this value,
check whether the camera defines the horizontal magnification using the
HasHorizontalMag function.
@return The horizontal magnification. */
inline float& GetMagX() { return viewX; }
inline const float& GetMagX() const { return viewX; } /**< See above. */
/** Retrieves the vertical magnification. Before retrieving this value,
check whether the camera defines the vertical magnification using the
HasVerticalMag function.
@return The vertical magnification. */
inline float& GetMagY() { return viewY; }
inline const float& GetMagY() const { return viewY; } /**< See above. */
/** Sets the horizontal magnification for this camera.
@param magX The new horizontal magnification, in degrees. */
inline void SetMagX(float magX) { return SetFovX(magX); }
/** Sets the vertical magnification value for this camera.
@param magY The new vertical magnification, in degrees. */
inline void SetMagY(float magY) { return SetFovY(magY); }
/** Retrieves the near-z value for this camera.
The near-z value represent how close the near-clip
plane of the view frustrum is. For orthographic cameras,
this value is solely used for depth-buffering.
@return The near-z value for this camera. */
inline float& GetNearZ() { return nearZ; }
inline const float& GetNearZ() const { return nearZ; } /**< See above. */
/** Retrieves the far-z value for this camera. The far-z value represent
how close the far-clip plane of the view frustrum is.
For orthographic cameras, this value is solely used for depth-buffering.
@return The far-z value for this camera. */
inline float& GetFarZ() { return farZ; }
inline const float& GetFarZ() const { return farZ; } /**< See above. */
/** Retrieves the aspect ratio for the view of this camera. Before using this value,
check if there are only one of the horizontal and vertical view ratios.
If there are both of the view ratios provided for the camera, you will
need to calculate the aspect ratio using the following formula:
aspect ratio = vertical field of view / horizontal field of view.
@return The view aspect ratio. */
inline float& GetAspectRatio() { return aspectRatio; }
inline const float& GetAspectRatio() const { return aspectRatio; } /**< See above. */
/** Sets the near-z value for this camera.
The near-z value represent how close the near-clip
plane of the view frustrum is. For orthographic cameras,
this value is solely used for depth-buffering.
@param _nearZ A valid near-z value. No check is made to verify that the
near-z value is greather than the far-z value.*/
inline void SetNearZ(float _nearZ) { nearZ = _nearZ; }
/** Sets the far-z value for this camera. The far-z value represent
how close the far-clip plane of the view frustrum is.
For orthographic cameras, this value is solely used for depth-buffering.
@param _farZ A valid far-z value. No check is made to verify that the
far-z value is greather than the near-z value.*/
inline void SetFarZ(float _farZ) { farZ = _farZ; }
/** Sets the aspect ratio for the view of this camera.
@param aspectRatio The new view aspect ratio. */
void SetAspectRatio(float aspectRatio);
/** Retrieves whether the camera provides aperture information. This information is specific
to COLLADA documents exported from ColladaMaya.
@return Whether the camera provides aperture information. */
inline bool HasAperture() const { return hasAperture; }
/** Retrieves the vertical aperture of the camera. This information is specific to
COLLADA documents exported from ColladaMaya.
@return The vertical aperture of the camera. */
inline float& GetVerticalAperture() { return verticalAperture; }
inline const float& GetVerticalAperture() const { return verticalAperture; } /**< See above. */
/** Retrieves the horizontal aperture of the camera. This information is specific to
COLLADA documents exported from ColladaMaya.
@return The horizontal aperture of the camera. */
inline float& GetHorizontalAperture() { return horizontalAperture; }
inline const float& GetHorizontalAperture() const { return horizontalAperture; } /**< See above. */
/** Retrieves the lens squeeze of the camera. This information is specific to
COLLADA documents exported from ColladaMaya. The lens squeeze of the camera
is a multiplier that acts directly on the horizontal aperture, following this
formula: real horizontal aperture = given horizontal aperture * lens squeeze.
@return The lens squeeze of the camera. */
inline float& GetLensSqueeze() { return lensSqueeze; }
inline const float& GetLensSqueeze() const { return lensSqueeze; } /**< See above. */
/** Sets the vertical aperture of the camera.
@param aperture The vertical aperture of the camera. */
inline void SetVerticalAperture(float aperture) { verticalAperture = aperture; hasAperture = true; }
/** Sets the horizontal aperture of the camera.
@param aperture The horizontal aperture of the camera. */
inline void SetHorizontalAperture(float aperture) { horizontalAperture = aperture; hasAperture = true; }
/** Sets the lens squeeze of the camera.
@param factor The lense squeeze of the camera. */
inline void SetLensSqueeze(float factor) { lensSqueeze = factor; }
/** [INTERNAL] Reads in the \<camera\> element from a given COLLADA XML tree node.
@param cameraNode A COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the camera.*/
FUStatus LoadFromXML(xmlNode* cameraNode);
/** [INTERNAL] Writes out the \<camera\> element to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the geometry information.
@return The created XML tree node. */
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif // _FCD_CAMERA_H_

View File

@@ -0,0 +1,123 @@
/*
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/FCDController.h"
#include "FCDocument/FCDSkinController.h"
#include "FCDocument/FCDMorphController.h"
#include "FUtils/FUDaeParser.h"
using namespace FUDaeParser;
FCDController::FCDController(FCDocument* document) : FCDEntity(document, "Controller")
{
skinController = NULL;
morphController = NULL;
}
FCDController::~FCDController()
{
SAFE_DELETE(skinController);
SAFE_DELETE(morphController);
}
// Sets the type of this controller to a skin controller.
FCDSkinController* FCDController::CreateSkinController()
{
SAFE_DELETE(skinController);
SAFE_DELETE(morphController);
skinController = new FCDSkinController(GetDocument(), this);
return skinController;
}
// Sets the type of this controller to a morph controller.
FCDMorphController* FCDController::CreateMorphController()
{
SAFE_DELETE(skinController);
SAFE_DELETE(morphController);
morphController = new FCDMorphController(GetDocument(), this);
return morphController;
}
FCDEntity* FCDController::GetBaseTarget()
{
if (skinController != NULL) return skinController->GetTarget();
else if (morphController != NULL) return morphController->GetBaseTarget();
else return NULL;
}
const FCDEntity* FCDController::GetBaseTarget() const
{
if (skinController != NULL) return skinController->GetTarget();
else if (morphController != NULL) return morphController->GetBaseTarget();
else return NULL;
}
// Load this controller from a Collada <controller> node
FUStatus FCDController::LoadFromXML(xmlNode* controllerNode)
{
FUStatus status = FCDEntity::LoadFromXML(controllerNode);
if (!status) return status;
if (!IsEquivalent(controllerNode->name, DAE_CONTROLLER_ELEMENT))
{
return status.Warning(FS("Unexpected node in controller library: <") + TO_FSTRING((const char*) controllerNode->name) + FC(">."), controllerNode->line);
}
// COLLADA 1.3 backward compatiblity: read in the 'target' attribute
targetId = ReadNodeProperty(controllerNode, DAE_TARGET_ATTRIBUTE);
// Find the <skin> or <morph> element and process it
xmlNode* skinNode = FindChildByType(controllerNode, DAE_CONTROLLER_SKIN_ELEMENT);
xmlNode* morphNode = FindChildByType(controllerNode, DAE_CONTROLLER_MORPH_ELEMENT);
if (skinNode != NULL && morphNode != NULL)
{
status.Warning(FS("A controller cannot be both a skin and a morpher: ") + TO_FSTRING(GetDaeId()), controllerNode->line);
}
if (skinNode != NULL)
{
// Create and parse in the skin controller
FCDSkinController* controller = CreateSkinController();
status.AppendStatus(controller->LoadFromXML(skinNode));
}
else if (morphNode != NULL)
{
// Create and parse in the morph controller
FCDMorphController* controller = CreateMorphController();
status.AppendStatus(controller->LoadFromXML(morphNode));
}
else
{
status.Warning(FS("No base type element, <skin> or <morph>, found for controller: ") + TO_FSTRING(GetDaeId()), controllerNode->line);
}
return status;
}
// Write out this controller to a COLLADA xml node tree
xmlNode* FCDController::WriteToXML(xmlNode* parentNode) const
{
xmlNode* controllerNode = FCDEntity::WriteToEntityXML(parentNode, DAE_CONTROLLER_ELEMENT);
if (skinController != NULL) skinController->WriteToXML(controllerNode);
if (morphController != NULL) morphController->WriteToXML(controllerNode);
FCDEntity::WriteToExtraXML(controllerNode);
return controllerNode;
}
// Link this controller to the rest of the document: joints/base geometry...
FUStatus FCDController::Link()
{
FUStatus status;
// Link the controller
if (skinController != NULL) status.AppendStatus(skinController->Link());
if (morphController != NULL) status.AppendStatus(morphController->Link());
return status;
}

View File

@@ -0,0 +1,124 @@
/*
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
*/
/**
@file FCDController.h
This file contains the FCDController class.
*/
#ifndef _FCD_CONTROLLER_H_
#define _FCD_CONTROLLER_H_
#include "FCDocument/FCDEntity.h"
class FCDocument;
class FCDSkinController;
class FCDMorphController;
/**
A generic COLLADA controller.
A COLLADA controller is used to influence a mesh.
COLLADA defines two types of controller:
skins (FCDSkinController) and morphers (FCDMorphController).
@ingroup FCDGeometry
*/
class FCOLLADA_EXPORT FCDController : public FCDEntity
{
private:
string targetId; // COLLADA 1.3 backward compatibility
FCDSkinController* skinController;
FCDMorphController* morphController;
public:
/** Constructor: do not use directly.
Instead, use the FCDLibrary::AddEntity function.
@param document The COLLADA document that owns the controller. */
FCDController(FCDocument* document);
/** Destructor: do not use directly.
Instead, use the FCDLibrary::ReleaseEntity function. */
virtual ~FCDController();
/** Retrieves the entity class type.
This function is a part of the FCDEntity interface.
@return The entity class type: CONTROLLER. */
virtual Type GetType() const { return CONTROLLER; };
/** Retrieves whether this controller is a skin controller.
@return Whether this controller is a skin controller. */
bool HasSkinController() const { return skinController != NULL; }
/** Retrieves whether this controller is a morph controller.
@return Whether this controller is a morph controller. */
bool HasMorphController() const { return morphController != NULL; }
/** Sets the type of this controller to a skin controller.
This function will release any previously created morpher or skin.
@return The new skin controller. */
FCDSkinController* CreateSkinController();
/** Sets the type of this controller to a morph controller.
This function will release any previously created morpher or skin.
@return The new morph controller. */
FCDMorphController* CreateMorphController();
/** Retrieves the skin controller.
This pointer is only valid for skins. To verify that this is a skin,
check the HasSkinController function.
@return The skin controller. This pointer will be NULL, if the controller
is not a skin. */
FCDSkinController* GetSkinController() { return skinController; }
const FCDSkinController* GetSkinController() const { return skinController; } /**< See above. */
/** Retrieves the morph controller.
This pointer is only valid for skins. To verify that this is a morpher,
check the HasMorphController function.
@return The morph controller. This pointer will be NULL, if the controller
is not a morpher. */
FCDMorphController* GetMorphController() { return morphController; }
const FCDMorphController* GetMorphController() const { return morphController; } /**< See above. */
/** Retrieves the base target entity for this controller.
The base target entity may be another controller or a geometry entity.
To change the base target, use the FCDMorphController::SetBaseTarget
or the FCDSkinController::SetTarget functions.
@return The base target entity. This pointer will be NULL, if no base target is defined. */
FCDEntity* GetBaseTarget();
const FCDEntity* GetBaseTarget() const; /**< See above. */
/** [INTERNAL] Retrieves the COLLADA id of the target entity.
This value is only useful for COLLADA 1.3 backward compatibility.
For more recent COLLADA documents, this value is unused.
@return The COLLADA id of the target entity. */
const string& GetTargetId() const { return targetId; }
/** [INTERNAL] Reads in the \<controller\> element from a given COLLADA XML tree node.
@param controllerNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the controller.*/
virtual FUStatus LoadFromXML(xmlNode* controllerNode);
/** [INTERNAL] Writes out the \<controller\> element to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the controller information.
@return The created element XML tree node. */
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
/** [INTERNAL] Links the controller entities with their many targets/influences.
This function is executed for all the controllers, after the scene graph has been imported.
It is mainly used to link the skin and its bones.
@return The status of the linkage.*/
FUStatus Link();
};
#endif // _FCD_CONTROLLER_H_

View File

@@ -0,0 +1,268 @@
/*
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/FCDEffect.h"
#include "FCDocument/FCDEffectStandard.h"
#include "FCDocument/FCDEffectProfileFX.h"
#include "FCDocument/FCDEffectParameter.h"
#include "FCDocument/FCDEffectParameterFactory.h"
#include "FCDocument/FCDEffectParameterList.h"
#include "FCDocument/FCDLibrary.h"
#include "FCDocument/FCDImage.h"
#include "FUtils/FUStringConversion.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDEffect::FCDEffect(FCDocument* document) : FCDEntity(document, "Effect")
{
parameters = new FCDEffectParameterList(GetDocument(), true);
}
FCDEffect::~FCDEffect()
{
SAFE_DELETE(parameters);
CLEAR_POINTER_VECTOR(profiles);
}
void FCDEffect::AddParameter(FCDEffectParameter* parameter)
{
parameters->push_back(parameter);
}
// Flatten this effect: trickling down all the parameters to the technique level
void FCDEffect::Flatten()
{
for (FCDEffectParameterList::iterator itP = parameters->begin(); itP != parameters->end(); ++itP)
{
FCDEffectParameterList generators;
if ((*itP)->IsModifier())
{
// Overwrite the generators
FindParametersByReference((*itP)->GetReference(), generators);
for (FCDEffectParameterList::iterator itQ = generators.begin(); itQ != generators.end(); ++itQ)
{
if ((*itP) != (*itQ))
{
(*itP)->Overwrite(*itQ);
}
}
}
else
{
// Add this parameter to hierarchies below
for (FCDEffectProfileList::iterator itR = profiles.begin(); itR != profiles.end(); ++itR)
{
if ((*itR)->GetType() != FUDaeProfileType::COMMON)
{
((FCDEffectProfileFX*) (*itR))->AddParameter((*itP)->Clone());
}
}
}
}
CLEAR_POINTER_VECTOR(*parameters);
for (FCDEffectProfileList::iterator itR = profiles.begin(); itR != profiles.end(); ++itR)
{
(*itR)->Flatten();
}
}
// Search for a profile of the given type
FCDEffectProfile* FCDEffect::FindProfile(FUDaeProfileType::Type type)
{
for (FCDEffectProfileList::iterator itR = profiles.begin(); itR != profiles.end(); ++itR)
{
if ((*itR)->GetType() == type) return (*itR);
}
return NULL;
}
const FCDEffectProfile* FCDEffect::FindProfile(FUDaeProfileType::Type type) const
{
for (FCDEffectProfileList::const_iterator itR = profiles.begin(); itR != profiles.end(); ++itR)
{
if ((*itR)->GetType() == type) return (*itR);
}
return NULL;
}
// Create a new effect profile.
FCDEffectProfile* FCDEffect::AddProfile(FUDaeProfileType::Type type)
{
// Delete any old profile of the same type
FCDEffectProfile* profile = FindProfile(type);
if (profile != NULL)
{
ReleaseProfile(profile);
profile = NULL;
}
// Create the correct profile for this type.
if (type == FUDaeProfileType::COMMON) profile = new FCDEffectStandard(GetDocument(), this);
else profile = new FCDEffectProfileFX(GetDocument(), this, type);
profiles.push_back(profile);
return profile;
}
// Releases the effect profile.
void FCDEffect::ReleaseProfile(FCDEffectProfile* profile)
{
FCDEffectProfileList::iterator itR = std::find(profiles.begin(), profiles.end(), profile);
if (itR != profiles.end())
{
delete *itR;
profiles.erase(itR);
}
}
// Look for the effect parameter with the correct semantic, in order to bind/set its value
FCDEffectParameter* FCDEffect::FindParameterBySemantic(const string& semantic)
{
FCDEffectParameter* p = parameters->FindSemantic(semantic);
for (FCDEffectProfileList::iterator itR = profiles.begin(); itR != profiles.end() && p == NULL; ++itR)
{
p = (*itR)->FindParameterBySemantic(semantic);
}
return p;
}
void FCDEffect::FindParametersBySemantic(const string& semantic, FCDEffectParameterList& _parameters)
{
parameters->FindSemantic(semantic, _parameters);
for (FCDEffectProfileList::iterator itR = profiles.begin(); itR != profiles.end(); ++itR)
{
(*itR)->FindParametersBySemantic(semantic, _parameters);
}
}
void FCDEffect::FindParametersByReference(const string& reference, FCDEffectParameterList& _parameters)
{
parameters->FindReference(reference, _parameters);
for (FCDEffectProfileList::iterator itR = profiles.begin(); itR != profiles.end(); ++itR)
{
(*itR)->FindParametersBySemantic(reference, _parameters);
}
}
// Parse COLLADA document's <effect> element
// Also parses the <material> element for COLLADA 1.3 backward compatibility
FUStatus FCDEffect::LoadFromXML(xmlNode* effectNode)
{
FUStatus status = FCDEntity::LoadFromXML(effectNode);
if (!status) return status;
CLEAR_POINTER_VECTOR(*parameters);
// COLLADA 1.3 backward compatibility: look for a <material><shader> node and parse this into a standard effect.
if (IsEquivalent(effectNode->name, DAE_MATERIAL_ELEMENT))
{
xmlNode* shaderNode = FindChildByType(effectNode, DAE_SHADER_ELEMENT);
if (shaderNode != NULL)
{
FCDEffectProfile* profile = AddProfile(FUDaeProfileType::COMMON);
status.AppendStatus(profile->LoadFromXML(shaderNode));
}
}
else
{
// Accept solely <effect> elements at this point.
if (!IsEquivalent(effectNode->name, DAE_EFFECT_ELEMENT))
{
return status.Warning(FS("Unknown element in effect library."), effectNode->line);
}
for (xmlNode* child = effectNode->children; child != NULL; child = child->next)
{
if (child->type != XML_ELEMENT_NODE) continue;
if (IsEquivalent(child->name, DAE_IMAGE_ELEMENT))
{
FCDImage* image = GetDocument()->GetImageLibrary()->AddEntity();
status.AppendStatus(image->LoadFromXML(child));
images.push_back(image);
}
else if (IsEquivalent(child->name, DAE_FXCMN_SETPARAM_ELEMENT) || IsEquivalent(child->name, DAE_FXCMN_NEWPARAM_ELEMENT))
{
AddParameter(FCDEffectParameterFactory::LoadFromXML(GetDocument(), child, &status));
}
else if (IsEquivalent(child->name, DAE_EXTRA_ELEMENT))
{
// Valid element.. but not processed.
}
else
{
// Check for a valid profile element.
FUDaeProfileType::Type type = FUDaeProfileType::FromString((const char*) child->name);
if (type != FUDaeProfileType::UNKNOWN)
{
FCDEffectProfile* profile = AddProfile(type);
status.AppendStatus(profile->LoadFromXML(child));
}
else
{
status.Warning(FS("Unsupported profile or unknown element in effect: ") + TO_FSTRING(GetDaeId()), child->line);
}
}
}
}
return status;
}
// Returns a copy of the effect, with all the animations/textures attached
FCDEffect* FCDEffect::Clone()
{
FCDEffect* clone = new FCDEffect(GetDocument());
FCDEntity::Clone(clone);
for (FCDEffectProfileList::iterator itR = profiles.begin(); itR != profiles.end(); ++itR)
{
FCDEffectProfile* p = (*itR)->Clone(clone);
clone->profiles.push_back(p);
}
for (FCDEffectImageList::iterator itI = images.begin(); itI != images.end(); ++itI)
{
FCDImage* p = *itI;
clone->images.push_back(p);
}
SAFE_DELETE(clone->parameters);
clone->parameters = parameters->Clone();
return clone;
}
// Write out the <material> element to the COLLADA xml tree
xmlNode* FCDEffect::WriteToXML(xmlNode* parentNode) const
{
xmlNode* effectNode = WriteToEntityXML(parentNode, DAE_EFFECT_ELEMENT);
// Write out the parameters
for (FCDEffectParameterList::iterator itP = parameters->begin(); itP != parameters->end(); ++itP)
{
(*itP)->WriteToXML(effectNode);
}
// Write out the profiles
for (FCDEffectProfileList::const_iterator itR = profiles.begin(); itR != profiles.end(); ++itR)
{
(*itR)->WriteToXML(effectNode);
}
FCDEffect::WriteToExtraXML(effectNode);
return effectNode;
}

View File

@@ -0,0 +1,179 @@
/*
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
*/
/**
@file FCDEffect.h
This file contains the FCDEffect class.
*/
#ifndef _FCD_EFFECT_H_
#define _FCD_EFFECT_H_
#include "FUtils/FUDaeEnum.h"
#include "FCDocument/FCDEntity.h"
class FCDocument;
class FCDEffectStandard;
class FCDEffectParameter;
class FCDEffectProfile;
class FCDEffectParameterList;
/**
@defgroup FCDEffect COLLADA Effect Classes [ColladaFX]
*/
class FCDEffectProfile;
class FCDEffectParameterList;
class FCDImage;
/** A dynamically-sized array of effect profiles. */
typedef vector<FCDEffectProfile*> FCDEffectProfileList;
typedef vector<FCDImage*> FCDEffectImageList;
/**
A COLLADA effect.
A COLLADA effect is one of many abstraction level that defines how
to render mesh polygon sets. It contains one or more rendering profile
that the application can choose to support. In theory, all the rendering
profiles should reach the same render output, using different
rendering technologies.
An effect may also declare new general purpose parameters that are common
to all the profiles.
@ingroup FCDEffect
*/
class FCOLLADA_EXPORT FCDEffect : public FCDEntity
{
private:
FCDEffectProfileList profiles;
FCDEffectParameterList* parameters;
FCDEffectImageList images;
public:
/** Constructor: do not use directly.
Instead use the FCDMaterialLibrary::AddEffect function.
@param document The COLLADA document that owns this effect. */
FCDEffect(FCDocument* document);
/** Destructor: do not use directly.
Instead use the FCDMaterialLibrary::ReleaseEffect function. */
virtual ~FCDEffect();
/** Retrieves the type for this entity class.
This function is a part of the FCDEntity interface.
@return The entity type: EFFECT. */
virtual Type GetType() const { return FCDEntity::EFFECT; }
/** Retrieves the number of profiles contained within the effect.
@return The number of profiles within the effect. */
size_t GetProfileCount() const { return profiles.size(); }
/** Retrieves a profile contained within the effect.
@param index The index of the profile.
@return The profile. This pointer will be NULL, if the given index is out-of-bounds. */
FCDEffectProfile* GetProfile(size_t index) { FUAssert(index < GetProfileCount(), return NULL); return profiles.at(index); }
const FCDEffectProfile* GetProfile(size_t index) const { FUAssert(index < GetProfileCount(), return NULL); return profiles.at(index); } /**< See above. */
/** Retrieves the list of the profiles contained within the effect.
@return The list of effect profiles. */
FCDEffectProfileList& GetProfiles() { return profiles; }
const FCDEffectProfileList& GetProfiles() const { return profiles; } /**< See above. */
/** Retrieves the profile for a specific profile type.
There should only be one profile of each type within an effect. This
function allows you to retrieve the profile for a given type.
@param type The profile type.
@return The profile of this type. This pointer will be NULL if the effect
does not have any profile of this type. */
FCDEffectProfile* FindProfile(FUDaeProfileType::Type type);
const FCDEffectProfile* FindProfile(FUDaeProfileType::Type type) const; /**< See above. */
/** Retrieves whether the effect contains a profile of the given type.
@param type The profile type.
@return Whether the effect has a profile of this type. */
inline bool HasProfile(FUDaeProfileType::Type type) const { return FindProfile(type) != NULL; }
/** Creates a profile of the given type.
If a profile of this type already exists, it will be released, as
a COLLADA effect should only contain one profile of each type.
@param type The profile type.
@return The new effect profile. */
FCDEffectProfile* AddProfile(FUDaeProfileType::Type type);
/** Releases the given effect profile.
@param profile The effect profile. */
void ReleaseProfile(FCDEffectProfile* profile);
/** Retrieves the list of common effect parameters declared at the effect level.
According to the COLLADA 1.4 schema, you should expect only parameter generators
at this abstraction level.
@return The list of effect parameters. */
FCDEffectParameterList* GetParameters() { return parameters; }
const FCDEffectParameterList* GetParameters() const { return parameters; } /**< See above. */
/** [INTERNAL] Inserts an existing parameter into the list of common effect parameters
at this abstraction level. This function is used during the flattening of a material.
@param parameter The effect parameter to insert. */
void AddParameter(FCDEffectParameter* parameter);
/** Retrieves a common effect parameter. Looks for the common effect parameter with the correct
semantic, in order to bind or override its value.
This function searches through the effect and the level of abstractions below.
@param semantic The effect parameter semantic to match.
@return The first effect parameter that matches the semantic.
This pointer will be NULL if no effect parameter matches the given semantic. */
FCDEffectParameter* FindParameterBySemantic(const string& semantic);
/** Retrieves a subset of the common effect parameter list.
Look for the effect parameter generators with the correct semantic.
This function searches through the effect and the level of abstractions below.
@param semantic The effect parameter semantic to match.
@param parameters The list of parameters to fill in. This list is not cleared. */
void FindParametersBySemantic(const string& semantic, FCDEffectParameterList& parameters);
/** Retrieves a subset of the common effect parameter list.
Look for the effect parameter generators with the correct reference.
This function searches through the effect and the level of abstractions below.
@param reference The effect parameter reference to match. In the case of effect
parameter generators, the reference is replaced by the sub-id.
@param parameters The list of parameters to fill in. This list is not cleared. */
void FindParametersByReference(const string& reference, FCDEffectParameterList& parameters);
/** Clones the effect object. Everything is cloned, including the effect parameter
and their animations. You will need release the cloned effect directly, by deleting the pointer.
@return The cloned effect object. You will must delete this pointer. */
FCDEffect* Clone();
/** [INTERNAL] Flattens the effect, pushing all the common effect parameters
into to the effect technique level of abstraction. To correctly flatten a
material, use the FCDMaterialInstance::FlattenMaterial function. */
void Flatten();
/** [INTERNAL] Reads in the \<effect\> element from a given COLLADA XML tree node.
@param effectNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the effect.*/
virtual FUStatus LoadFromXML(xmlNode* effectNode);
/** [INTERNAL] Writes out the \<effect\> element to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the effect.
@return The created element XML tree node. */
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
/** Retrieves the list of the images contained within the effect.
@return The list of effect images. */
FCDEffectImageList& GetImages() { return images; }
const FCDEffectImageList& GetImages() const { return images; } /**< See above. */
};
#endif // _FCD_MATERIAL_H_

View File

@@ -0,0 +1,88 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDocument.h"
#include "FCDocument/FCDEffectCode.h"
#include "FUtils/FUFileManager.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDEffectCode::FCDEffectCode(FCDocument* document) : FCDObject(document, "FCDEffectCode")
{
type = INCLUDE;
}
FCDEffectCode::~FCDEffectCode()
{
}
// Clone
FCDEffectCode* FCDEffectCode::Clone() const
{
FCDEffectCode* clone = new FCDEffectCode(GetDocument());
clone->type = type;
clone->sid = sid;
clone->filename = filename;
clone->code = code;
return clone;
}
// Read in the code/include from the xml node tree
FUStatus FCDEffectCode::LoadFromXML(xmlNode* codeNode)
{
FUStatus status;
if (IsEquivalent(codeNode->name, DAE_FXCMN_INCLUDE_ELEMENT)) type = INCLUDE;
else if (IsEquivalent(codeNode->name, DAE_FXCMN_CODE_ELEMENT)) type = CODE;
else
{
return status.Fail(FS("Unknown effect code type."), codeNode->line);
}
// Read in the code identifier and the actual code or filename
sid = ReadNodeProperty(codeNode, DAE_SID_ATTRIBUTE);
if (type == INCLUDE && sid.empty())
{
status.Warning(FS("<code>/<include> nodes must have an 'sid' attribute to identify them."), codeNode->line);
}
if (type == INCLUDE)
{
filename = ReadNodeUrl(codeNode).prefix;
filename = GetDocument()->GetFileManager()->GetFilePath(filename);
}
else
{
code = TO_FSTRING(ReadNodeContentDirect(codeNode));
}
return status;
}
// Write out the code/include to the COLLADA xml node tree
xmlNode* FCDEffectCode::WriteToXML(xmlNode* parentNode) const
{
// In COLLADA 1.4, the 'sid' and 'url' attributes are required.
// In the case of the sub-id, save it for later use.
xmlNode* codeNode;
switch (type)
{
case CODE:
codeNode = AddChild(parentNode, DAE_FXCMN_CODE_ELEMENT, code);
const_cast<FCDEffectCode*>(this)->sid = AddNodeSid(codeNode, !sid.empty() ? sid.c_str() : "code");
break;
case INCLUDE:
codeNode = AddChild(parentNode, DAE_FXCMN_INCLUDE_ELEMENT);
const_cast<FCDEffectCode*>(this)->sid = AddNodeSid(codeNode, !sid.empty() ? sid.c_str() : "include");
AddAttribute(codeNode, DAE_URL_ATTRIBUTE, filename);
break;
default:
codeNode = NULL;
}
return codeNode;
}

View File

@@ -0,0 +1,118 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
/**
@file FCDEffectCode.h
This file contains the FCDEffectCode class.
*/
#ifndef _FCD_EFFECT_CODE_H_
#define _FCD_EFFECT_CODE_H_
#include "FCDocument/FCDObject.h"
class FCDocument;
/**
A COLLADA code inclusion.
Code inclusions come in two forms: file includes and inline code.
For file includes, you will want to grab the filename of the file
using the GetFilename function and for inline code, you can get
the code directly through the GetCode function.
Code inclusions are referenced through sub-ids by the effect pass
shaders. Regardless of the extension of the filename of file
includes, the code inclusions' language is solely determined by
the effect profile they belong to.
*/
class FCDEffectCode : public FCDObject
{
public:
/** The list of support code inclusion types. */
enum Type
{
INCLUDE, /** A file include. @see GetFilename */
CODE /** Inlined code. @see GetCode */
};
private:
Type type;
string sid;
fstring code;
fstring filename;
public:
/** Constructor: do not use directly.
Instead, use the FCDEffectProfile::AddCode
or the FCDEffectTechnique::AddCode functions.
@param document The COLLADA document that owns this code inclusion. */
FCDEffectCode(FCDocument* document);
/** Destructor: do not use directly.
Instead, use the FCDEffectProfile::ReleaseCode
or the FCDEffectTechnique::ReleaseCode functions. */
~FCDEffectCode();
/** Retrieves the form of the code inclusion.
@return The form. */
inline Type GetType() const { return type; }
/** Sets the form of the code inclusion.
Changing the form of the code inclusion will not
remove the inline code or the filename.
@param _type The form. */
inline void SetType(Type _type) { type = _type; }
/** Retrieves the sub-id of the code inclusion.
Used to match the code inclusion within the effect pass shaders.
@return The sub-id. */
const string& GetSid() const { return sid; }
/** Sets the sub-id of the code inclusion.
This value may change on export, as the sub-id must be unique within its scope.
@param _sid The sub-id. */
void SetSid(const string& _sid) { sid = _sid; }
/** Retrieves the inlined code.
First verify that this code inclusion contains inlined code
using the GetType function.
@return The inlined code. */
const fstring& GetCode() const { return code; }
/** Sets the inlined code.
As a side-effect, calling this function forces the type of the code inclusion.
@param _code The inlined code. */
void SetCode(const fstring& _code) { code = _code; type = CODE; }
/** Retrieves the filename of the code file to open.
First verify that this code inclusion contains a filename
using the GetType function.
@return The code filename. */
const fstring& GetFilename() const { return filename; }
/** Sets the filename of the code file.
As a side-effect, calling this function forces the type of the code inclusion.
@param _filename The code filename. */
void SetFilename(const fstring& _filename) { filename = _filename; type = INCLUDE; }
/** [INTERNAL] Clones the code inclusion.
@return The cloned effect object. You will must delete this pointer. */
FCDEffectCode* Clone() const;
/** [INTERNAL] Reads in the code inclusion from a given COLLADA XML tree node.
Code inclusions cover the \<code\> element and the \<include\> element.
@param codeNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the code inclusion.*/
FUStatus LoadFromXML(xmlNode* codeNode);
/** [INTERNAL] Writes out the code inclusion to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the code inclusion.
@return The created element XML tree node. */
xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif // _FCD_EFFECT_CODE_H_

View File

@@ -0,0 +1,646 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDocument.h"
#include "FCDocument/FCDAnimated.h"
#include "FCDocument/FCDEffectPass.h"
#include "FCDocument/FCDEffectProfile.h"
#include "FCDocument/FCDEffectTechnique.h"
#include "FCDocument/FCDEffectParameter.h"
#include "FCDocument/FCDImage.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDEffectParameter::FCDEffectParameter(FCDocument* document) : FCDObject(document, "FCDEffectParameter")
{
isGenerator = true;
isFragment = false;
reference = "";
semantic = "";
bindSymbol = "";
}
FCDEffectParameter::~FCDEffectParameter()
{
}
FUStatus FCDEffectParameter::LoadFromXML(xmlNode* parameterNode)
{
FUStatus status;
// This parameter is a generator if this is a <newparam> element. Otherwise, it modifies
// an existing parameter (<bind>, <bind_semantic> or <setparam>.
isGenerator = IsEquivalent(parameterNode->name, DAE_FXCMN_NEWPARAM_ELEMENT);
if (isGenerator)
{
reference = ReadNodeProperty(parameterNode, DAE_SID_ATTRIBUTE);
if (reference.empty())
{
return status.Warning(FS("No reference attribute on generator parameter."), parameterNode->line);
}
}
else
{
reference = ReadNodeProperty(parameterNode, DAE_REF_ATTRIBUTE);
if (reference.empty())
{
return status.Warning(FS("No reference attribute on modifier parameter."), parameterNode->line);
}
}
xmlNode* valueNode = FindChildByType(parameterNode, DAE_FXCMN_SEMANTIC_ELEMENT);
if (valueNode != NULL)
{
semantic = ReadNodeContentDirect(valueNode);
}
return status;
}
// Write out this ColladaFX parameter to the xml node tree
xmlNode* FCDEffectParameter::WriteToXML(xmlNode* parentNode) const
{
xmlNode* parameterNode;
if (isGenerator)
{
parameterNode = AddChild(parentNode, DAE_FXCMN_NEWPARAM_ELEMENT);
if (!reference.empty()) AddAttribute(parameterNode, DAE_SID_ATTRIBUTE, reference);
if (!semantic.empty()) AddChild(parameterNode, DAE_FXCMN_SEMANTIC_ELEMENT, semantic);
}
else
{
parameterNode = AddChild(parentNode, DAE_FXCMN_SETPARAM_ELEMENT);
if (!reference.empty()) AddAttribute(parameterNode, DAE_REF_ATTRIBUTE, reference);
}
return parameterNode;
}
void FCDEffectParameter::Clone(FCDEffectParameter* clone)
{
clone->bindSymbol = bindSymbol;
clone->reference = reference;
clone->semantic = semantic;
clone->isFragment = isFragment;
clone->isGenerator = isGenerator;
}
// Flattening: overwrite the target parameter with this parameter
void FCDEffectParameter::Overwrite(FCDEffectParameter* UNUSED(target))
{
// Do nothing on the base class, only values and animations should be overwritten
}
FCDEffectParameterSampler::FCDEffectParameterSampler(FCDocument* document) : FCDEffectParameter(document)
{
samplerType = SAMPLER2D;
}
FCDEffectParameterSampler::~FCDEffectParameterSampler()
{
}
// Clone
FCDEffectParameter* FCDEffectParameterSampler::Clone()
{
FCDEffectParameterSampler* clone = new FCDEffectParameterSampler(GetDocument());
FCDEffectParameter::Clone(clone);
clone->surfaceSid = surfaceSid;
clone->samplerType = samplerType;
return clone;
}
// Flattening: overwrite the target parameter with this parameter
void FCDEffectParameterSampler::Overwrite(FCDEffectParameter* target)
{
if (target->GetType() == SAMPLER)
{
FCDEffectParameterSampler* s = (FCDEffectParameterSampler*) target;
if (samplerType == s->samplerType)
{
s->surfaceSid = surfaceSid;
}
}
}
FUStatus FCDEffectParameterSampler::LoadFromXML(xmlNode* parameterNode)
{
FUStatus status = FCDEffectParameter::LoadFromXML(parameterNode);
// Find the sampler node
xmlNode* samplerNode = NULL;
for (xmlNode* child = parameterNode->children; child != NULL; child = child->next)
{
if (child->type != XML_ELEMENT_NODE) continue;
if (IsEquivalent(child->name, DAE_FXCMN_SAMPLER1D_ELEMENT)) { samplerType = SAMPLER1D; samplerNode = child; break; }
else if (IsEquivalent(child->name, DAE_FXCMN_SAMPLER2D_ELEMENT)) { samplerType = SAMPLER2D; samplerNode = child; break; }
else if (IsEquivalent(child->name, DAE_FXCMN_SAMPLER3D_ELEMENT)) { samplerType = SAMPLER3D; samplerNode = child; break; }
else if (IsEquivalent(child->name, DAE_FXCMN_SAMPLERCUBE_ELEMENT)) { samplerType = SAMPLERCUBE; samplerNode = child; break; }
}
if (samplerNode == NULL)
{
return status.Warning(FS("Unable to find sampler node for sampler parameter: ") + TO_FSTRING(GetReference()), parameterNode->line);
}
// Parse the source node
xmlNode* sourceNode = FindChildByType(samplerNode, DAE_SOURCE_ELEMENT);
surfaceSid = ReadNodeContentDirect(sourceNode);
if (surfaceSid.empty())
{
return status.Fail(FS("Empty surface source value for sampler parameter: ") + TO_FSTRING(GetReference()), parameterNode->line);
}
return status;
}
xmlNode* FCDEffectParameterSampler::WriteToXML(xmlNode* parentNode) const
{
xmlNode* parameterNode = FCDEffectParameter::WriteToXML(parentNode);
const char* samplerName;
switch(samplerType)
{
case SAMPLER1D: samplerName = DAE_FXCMN_SAMPLER1D_ELEMENT; break;
case SAMPLER2D: samplerName = DAE_FXCMN_SAMPLER2D_ELEMENT; break;
case SAMPLER3D: samplerName = DAE_FXCMN_SAMPLER3D_ELEMENT; break;
case SAMPLERCUBE: samplerName = DAE_FXCMN_SAMPLERCUBE_ELEMENT; break;
default: samplerName = DAEERR_UNKNOWN_ELEMENT; break;
}
xmlNode* samplerNode = AddChild(parameterNode, samplerName);
if (!surfaceSid.empty()) AddChild(samplerNode, DAE_SOURCE_ELEMENT, surfaceSid);
return parameterNode;
}
FCDEffectParameterInt::FCDEffectParameterInt(FCDocument* document) : FCDEffectParameter(document) { value = 0; }
FCDEffectParameterInt::~FCDEffectParameterInt()
{
value = 0;
}
// Clone
FCDEffectParameter* FCDEffectParameterInt::Clone()
{
FCDEffectParameterInt* clone = new FCDEffectParameterInt(GetDocument());
FCDEffectParameter::Clone(clone);
clone->value = value;
return clone;
}
// Flattening: overwrite the target parameter with this parameter
void FCDEffectParameterInt::Overwrite(FCDEffectParameter* target)
{
if (target->GetType() == INTEGER)
{
FCDEffectParameterInt* s = (FCDEffectParameterInt*) target;
s->value = value;
}
}
// Parse in this ColladaFX integer from the document's XML node
FUStatus FCDEffectParameterInt::LoadFromXML(xmlNode* parameterNode)
{
FUStatus status = FCDEffectParameter::LoadFromXML(parameterNode);
xmlNode* valueNode = FindChildByType(parameterNode, DAE_FXCMN_INT_ELEMENT);
const char* valueString = ReadNodeContentDirect(valueNode);
if (valueString == NULL || *valueString == 0)
{
return status.Fail(FS("Bad value for float parameter in integer parameter: ") + TO_FSTRING(GetReference()), parameterNode->line);
}
value = FUStringConversion::ToInt32(valueString);
return status;
}
xmlNode* FCDEffectParameterInt::WriteToXML(xmlNode* parentNode) const
{
xmlNode* parameterNode = FCDEffectParameter::WriteToXML(parentNode);
AddChild(parameterNode, DAE_FXCMN_INT_ELEMENT, value);
return parameterNode;
}
// boolean type parameter
FCDEffectParameterBool::FCDEffectParameterBool(FCDocument* document) : FCDEffectParameter(document)
{
value = 0;
}
FCDEffectParameterBool::~FCDEffectParameterBool() {}
// Clone
FCDEffectParameter* FCDEffectParameterBool::Clone()
{
FCDEffectParameterBool* clone = new FCDEffectParameterBool(GetDocument());
FCDEffectParameter::Clone(clone);
clone->value = value;
return clone;
}
// Flattening: overwrite the target parameter with this parameter
void FCDEffectParameterBool::Overwrite(FCDEffectParameter* target)
{
if (target->GetType() == BOOLEAN)
{
FCDEffectParameterBool* s = (FCDEffectParameterBool*) target;
s->value = value;
}
}
FUStatus FCDEffectParameterBool::LoadFromXML(xmlNode* parameterNode)
{
FUStatus status = FCDEffectParameter::LoadFromXML(parameterNode);
xmlNode* valueNode = FindChildByType(parameterNode, DAE_FXCMN_BOOL_ELEMENT);
const char* valueString = ReadNodeContentDirect(valueNode);
if (valueString == NULL || *valueString == 0)
{
return status.Fail(FS("Bad value for boolean parameter in effect: ") + TO_FSTRING(GetReference()), parameterNode->line);
}
value = FUStringConversion::ToBoolean(valueString);
return status;
}
xmlNode* FCDEffectParameterBool::WriteToXML(xmlNode* parentNode) const
{
xmlNode* parameterNode = FCDEffectParameter::WriteToXML(parentNode);
AddChild(parameterNode, DAE_FXCMN_BOOL_ELEMENT, value);
return parameterNode;
}
// string type parameter
FCDEffectParameterString::FCDEffectParameterString(FCDocument* document) : FCDEffectParameter(document)
{
value = "";
}
FCDEffectParameterString::~FCDEffectParameterString()
{
}
// Clone
FCDEffectParameter* FCDEffectParameterString::Clone()
{
FCDEffectParameterString* clone = new FCDEffectParameterString(GetDocument());
FCDEffectParameter::Clone(clone);
clone->value = value;
return clone;
}
// Flattening: overwrite the target parameter with this parameter
void FCDEffectParameterString::Overwrite(FCDEffectParameter* target)
{
if (target->GetType() == STRING)
{
FCDEffectParameterString* s = (FCDEffectParameterString*) target;
s->value = value;
}
}
FUStatus FCDEffectParameterString::LoadFromXML(xmlNode* parameterNode)
{
FUStatus status = FCDEffectParameter::LoadFromXML(parameterNode);
xmlNode* valueNode = FindChildByType(parameterNode, DAE_FXCMN_STRING_ELEMENT);
const char* valueString = ReadNodeContentDirect(valueNode);
value = valueString;
return status;
}
xmlNode* FCDEffectParameterString::WriteToXML(xmlNode* parentNode) const
{
xmlNode* parameterNode = FCDEffectParameter::WriteToXML(parentNode);
AddChild(parameterNode, DAE_FXCMN_STRING_ELEMENT, value);
return parameterNode;
}
// float type parameter
FCDEffectParameterFloat::FCDEffectParameterFloat(FCDocument* document) : FCDEffectParameter(document)
{
floatType = FLOAT;
value = 0.0f;
min = 0.0f;
max = 1.0f;
}
FCDEffectParameterFloat::~FCDEffectParameterFloat()
{
}
// Clone
FCDEffectParameter* FCDEffectParameterFloat::Clone()
{
FCDEffectParameterFloat* clone = new FCDEffectParameterFloat(GetDocument());
FCDEffectParameter::Clone(clone);
clone->floatType = floatType;
clone->value = value;
clone->min = min;
clone->max = max;
return clone;
}
// Flattening: overwrite the target parameter with this parameter
void FCDEffectParameterFloat::Overwrite(FCDEffectParameter* target)
{
if (target->GetType() == FCDEffectParameter::FLOAT)
{
FCDEffectParameterFloat* s = (FCDEffectParameterFloat*) target;
if (s->floatType == floatType) s->value = value;
}
}
FUStatus FCDEffectParameterFloat::LoadFromXML(xmlNode* parameterNode)
{
FUStatus status = FCDEffectParameter::LoadFromXML(parameterNode);
xmlNode* valueNode = FindChildByType(parameterNode, DAE_FXCMN_FLOAT_ELEMENT);
if (valueNode == NULL)
{
valueNode = FindChildByType(parameterNode, DAE_FXCMN_HALF_ELEMENT);
floatType = HALF;
}
else floatType = FLOAT;
const char* valueString = ReadNodeContentDirect(valueNode);
if (valueString == NULL || *valueString == 0)
{
return status.Fail(FS("Bad float value for float parameter: ") + TO_FSTRING(GetReference()), parameterNode->line);
}
value = FUStringConversion::ToFloat(valueString);
FCDAnimatedFloat::Create(GetDocument(), parameterNode, &value);
xmlNode* minannNode = FindChildByName(parameterNode, "UIMin");
if(minannNode) {
xmlNode* minNode = FindChildByType(minannNode, DAE_FXCMN_FLOAT_ELEMENT);
valueString = ReadNodeContentDirect(minNode);
if (valueString != NULL) min = FUStringConversion::ToFloat(valueString);
}
xmlNode* maxannNode = FindChildByName(parameterNode, "UIMax");
if(maxannNode) {
xmlNode* maxNode = FindChildByType(maxannNode, DAE_FXCMN_FLOAT_ELEMENT);
valueString = ReadNodeContentDirect(maxNode);
if (valueString != NULL) max = FUStringConversion::ToFloat(valueString);
}
return status;
}
xmlNode* FCDEffectParameterFloat::WriteToXML(xmlNode* parentNode) const
{
xmlNode* parameterNode = FCDEffectParameter::WriteToXML(parentNode);
AddChild(parameterNode, (floatType == FLOAT) ? DAE_FXCMN_FLOAT_ELEMENT : DAE_FXCMN_HALF_ELEMENT, value);
return parameterNode;
}
// float2 type parameter
FCDEffectParameterFloat2::FCDEffectParameterFloat2(FCDocument* document) : FCDEffectParameter(document)
{
floatType = FLOAT;
value_x = 0.0f;
value_y = 0.0f;
}
FCDEffectParameterFloat2::~FCDEffectParameterFloat2()
{
}
// Clone
FCDEffectParameter* FCDEffectParameterFloat2::Clone()
{
FCDEffectParameterFloat2* clone = new FCDEffectParameterFloat2(GetDocument());
FCDEffectParameter::Clone(clone);
clone->floatType = floatType;
clone->value_x = value_x;
clone->value_y = value_y;
return clone;
}
// Flattening: overwrite the target parameter with this parameter
void FCDEffectParameterFloat2::Overwrite(FCDEffectParameter* target)
{
if (target->GetType() == FLOAT2)
{
FCDEffectParameterFloat2* s = (FCDEffectParameterFloat2*) target;
if (s->floatType == floatType)
{
s->value_x = value_x;
s->value_y = value_y;
}
}
}
FUStatus FCDEffectParameterFloat2::LoadFromXML(xmlNode* parameterNode)
{
FUStatus status = FCDEffectParameter::LoadFromXML(parameterNode);
xmlNode* valueNode = FindChildByType(parameterNode, DAE_FXCMN_FLOAT2_ELEMENT);
if (valueNode == NULL)
{
valueNode = FindChildByType(parameterNode, DAE_FXCMN_HALF2_ELEMENT);
floatType = HALF;
}
else floatType = FLOAT;
const char* valueString = ReadNodeContentDirect(valueNode);
if (valueString == NULL || *valueString == 0)
{
return status.Fail(FS("Bad value for float2 parameter: ") + TO_FSTRING(GetReference()), parameterNode->line);
}
value_x = FUStringConversion::ToFloat(&valueString);
value_y = FUStringConversion::ToFloat(&valueString);
return status;
}
xmlNode* FCDEffectParameterFloat2::WriteToXML(xmlNode* parentNode) const
{
xmlNode* parameterNode = FCDEffectParameter::WriteToXML(parentNode);
globalSBuilder.set(value_x); globalSBuilder.append(' '); globalSBuilder.append(value_y);
AddChild(parameterNode, (floatType == FLOAT) ? DAE_FXCMN_FLOAT2_ELEMENT : DAE_FXCMN_HALF2_ELEMENT, globalSBuilder);
return parameterNode;
}
// float3 type parameter
FCDEffectParameterFloat3::FCDEffectParameterFloat3(FCDocument* document) : FCDEffectParameter(document)
{
floatType = FLOAT;
value = FMVector3(0.0f, 0.0f, 0.0f);
}
FCDEffectParameterFloat3::~FCDEffectParameterFloat3()
{
}
// Clone
FCDEffectParameter* FCDEffectParameterFloat3::Clone()
{
FCDEffectParameterFloat3* clone = new FCDEffectParameterFloat3(GetDocument());
FCDEffectParameter::Clone(clone);
clone->floatType = floatType;
clone->value = value;
return clone;
}
// Flattening: overwrite the target parameter with this parameter
void FCDEffectParameterFloat3::Overwrite(FCDEffectParameter* target)
{
if (target->GetType() == FLOAT3)
{
FCDEffectParameterFloat3* s = (FCDEffectParameterFloat3*) target;
if (s->floatType == floatType)
{
s->value = value;
}
}
}
FUStatus FCDEffectParameterFloat3::LoadFromXML(xmlNode* parameterNode)
{
FUStatus status = FCDEffectParameter::LoadFromXML(parameterNode);
xmlNode* valueNode = FindChildByType(parameterNode, DAE_FXCMN_FLOAT3_ELEMENT);
if (valueNode == NULL)
{
valueNode = FindChildByType(parameterNode, DAE_FXCMN_HALF3_ELEMENT);
floatType = HALF;
}
else floatType = FLOAT;
const char* valueString = ReadNodeContentDirect(valueNode);
if (valueString == NULL || *valueString == 0)
{
return status.Fail(FS("Bad value for float3 parameter: ") + TO_FSTRING(GetReference()), parameterNode->line);
}
value = FUStringConversion::ToPoint(valueString);
FCDAnimatedColor::Create(GetDocument(), parameterNode, &value);
return status;
}
xmlNode* FCDEffectParameterFloat3::WriteToXML(xmlNode* parentNode) const
{
xmlNode* parameterNode = FCDEffectParameter::WriteToXML(parentNode);
string s = FUStringConversion::ToString(value);
AddChild(parameterNode, (floatType == FLOAT) ? DAE_FXCMN_FLOAT3_ELEMENT : DAE_FXCMN_HALF3_ELEMENT, s);
return parameterNode;
}
FCDEffectParameterVector::FCDEffectParameterVector(FCDocument* document) : FCDEffectParameter(document)
{
floatType = FLOAT;
vector[0] = vector[1] = vector[2] = vector[3] = 0.0f;
}
FCDEffectParameterVector::~FCDEffectParameterVector() {}
// Clone
FCDEffectParameter* FCDEffectParameterVector::Clone()
{
FCDEffectParameterVector* clone = new FCDEffectParameterVector(GetDocument());
FCDEffectParameter::Clone(clone);
clone->floatType = floatType;
memcpy(clone->vector, vector, sizeof(float) * 4);
return clone;
}
// Flattening: overwrite the target parameter with this parameter
void FCDEffectParameterVector::Overwrite(FCDEffectParameter* target)
{
if (target->GetType() == VECTOR)
{
FCDEffectParameterVector* s = (FCDEffectParameterVector*) target;
if (s->floatType == floatType)
{
memcpy(s->vector, vector, sizeof(float) * 4);
}
}
}
FUStatus FCDEffectParameterVector::LoadFromXML(xmlNode* parameterNode)
{
FUStatus status = FCDEffectParameter::LoadFromXML(parameterNode);
xmlNode* valueNode = FindChildByType(parameterNode, DAE_FXCMN_FLOAT4_ELEMENT);
if (valueNode == NULL)
{
valueNode = FindChildByType(parameterNode, DAE_FXCMN_HALF4_ELEMENT);
floatType = HALF;
}
else floatType = FLOAT;
const char* valueString = ReadNodeContentDirect(valueNode);
if (valueString == NULL || *valueString == 0)
{
return status.Fail(FS("Bad value for float4 parameter: ") + TO_FSTRING(GetReference()), parameterNode->line);
}
vector[0] = FUStringConversion::ToFloat(&valueString);
vector[1] = FUStringConversion::ToFloat(&valueString);
vector[2] = FUStringConversion::ToFloat(&valueString);
vector[3] = FUStringConversion::ToFloat(&valueString);
return status;
}
xmlNode* FCDEffectParameterVector::WriteToXML(xmlNode* parentNode) const
{
xmlNode* parameterNode = FCDEffectParameter::WriteToXML(parentNode);
globalSBuilder.set(vector[0]); globalSBuilder.append(' '); globalSBuilder.append(vector[1]); globalSBuilder.append(' ');
globalSBuilder.append(vector[2]); globalSBuilder.append(' '); globalSBuilder.append(vector[3]);
AddChild(parameterNode, (floatType == FLOAT) ? DAE_FXCMN_FLOAT4_ELEMENT : DAE_FXCMN_HALF4_ELEMENT, globalSBuilder);
return parameterNode;
}
FCDEffectParameterMatrix::FCDEffectParameterMatrix(FCDocument* document) : FCDEffectParameter(document)
{
floatType = FLOAT;
matrix = FMMatrix44::Identity;
}
FCDEffectParameterMatrix::~FCDEffectParameterMatrix()
{
}
// Clone
FCDEffectParameter* FCDEffectParameterMatrix::Clone()
{
FCDEffectParameterMatrix* clone = new FCDEffectParameterMatrix(GetDocument());
FCDEffectParameter::Clone(clone);
clone->floatType = floatType;
clone->matrix = matrix;
return clone;
}
// Flattening: overwrite the target parameter with this parameter
void FCDEffectParameterMatrix::Overwrite(FCDEffectParameter* target)
{
if (target->GetType() == MATRIX)
{
FCDEffectParameterMatrix* s = (FCDEffectParameterMatrix*) target;
s->matrix = matrix;
}
}
FUStatus FCDEffectParameterMatrix::LoadFromXML(xmlNode* parameterNode)
{
FUStatus status = FCDEffectParameter::LoadFromXML(parameterNode);
xmlNode* valueNode = FindChildByType(parameterNode, DAE_FXCMN_FLOAT4X4_ELEMENT);
if (valueNode == NULL)
{
valueNode = FindChildByType(parameterNode, DAE_FXCMN_HALF4X4_ELEMENT);
floatType = HALF;
}
else floatType = FLOAT;
const char* valueString = ReadNodeContentDirect(valueNode);
if (valueString == NULL || *valueString == 0)
{
return status.Fail(FS("Bad value for matrix parameter: ") + TO_FSTRING(GetReference()), parameterNode->line);
}
FUStringConversion::ToMatrix(valueString, matrix, GetDocument()->GetLengthUnitConversion());
return status;
}
xmlNode* FCDEffectParameterMatrix::WriteToXML(xmlNode* parentNode) const
{
xmlNode* parameterNode = FCDEffectParameter::WriteToXML(parentNode);
string s = FUStringConversion::ToString(matrix);
AddChild(parameterNode, (floatType == FLOAT) ? DAE_FXCMN_FLOAT4X4_ELEMENT : DAE_FXCMN_HALF4X4_ELEMENT, s);
return parameterNode;
}

View File

@@ -0,0 +1,844 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
/**
@file FCDEffectParameter.h
This file contains the FCDEffectParameter interface and most of its derivate classes:
FCDEffectParameterSampler, FCDEffectParameterFloat, FCDEffectParameterVector...
*/
#ifndef _FCD_EFFECT_PARAMETER_H_
#define _FCD_EFFECT_PARAMETER_H_
#include "FCDocument/FCDObject.h"
class FCDEffectPass;
class FCDocument;
class FCDEffectParameterSurface;
/**
A COLLADA effect parameter.
This interface class is used to define all the valid
ColladaFX parameter types. There are many types of
parameters: integers, booleans, floating-point
values, 2D, 3D and 4D vectors of floating-point values,
matrices, strings, surfaces and their samplers.
A COLLADA effect parameter may generate a new
effect parameter, in which case it will declare a semantic
and a reference: to represent it within the COLLADA document.
@ingroup FCDEffect
*/
class FCOLLADA_EXPORT FCDEffectParameter : public FCDObject
{
public:
/** The type of the effect parameter class. */
enum Type
{
SAMPLER, /**< A sampler effect parameter. Points towards a surface parameter and adds extra texturing parameters. */
INTEGER, /**< A single integer effect parameter. */
BOOLEAN, /**< A single boolean effect parameter. */
FLOAT, /**< A single floating-pointer value effect parameter. */
FLOAT2, /**< A 2D vector of floating-pointer values. */
FLOAT3, /**< A 3D vector of floating-pointer values. */
VECTOR, /**< A 4D vector of floating-pointer values. */
MATRIX, /**< A 4x4 matrix. */
STRING, /**< A string effect parameter. */
SURFACE /**< A surface effect parameter. Contains a COLLADA image pointer. */
};
private:
bool isGenerator; // whether this effect parameter structure generates a new value or modifies an existing value (is <newparam>?)
string reference;
string semantic; // this is a Collada Semantic, not a Cg semantic
// [glaforte] These two members should be somewhere else
string bindSymbol; // this can be used in Cg to bind to the correct variable
bool isFragment; // parameter bound to the fragment program or the vertex one
public:
/** Constructor: do not use directly.
Instead, use the FCDEffectParameterList::AddParameter function.
@param document The COLLADA document that owns the effect parameter. */
FCDEffectParameter(FCDocument* document);
/** Destructor: do not use directly.
Instead, use the FCDEffectParameterList::ReleaseParameter function.
When released, the effect parameter list will also release all
its parameters, if it owns them. */
virtual ~FCDEffectParameter();
/** Retrieves the type of effect parameter class.
@return The type of the effect parameter class.*/
virtual Type GetType() const = 0;
/** Retrieves the reference for this effect parameter.
In the case of generators, the reference string contains the sub-id.
@return The reference. */
const string& GetReference() const { return reference; }
/** Retrieves the semantic for this effect parameter.
@return The semantic. */
const string& GetSemantic() const { return semantic; }
/** Sets the semantic for this effect parameter.
@param _semantic The semantic. */
void SetSemantic(const string& _semantic) { semantic = _semantic; }
/** Retrieves whether this effect parameter is a parameter generator.
A ColladaFX parameter must be generated to be modified or bound at
higher abstraction levels.
@return Whether this is a generator. */
bool IsGenerator() const { return isGenerator; }
/** Retrieves whether this effect parameter is a parameter modifier.
A ColladaFX parameter must be generated to be modified or bound at
higher abstraction levels.
@return Whether this is a modifier. */
bool IsModifier() const { return !isGenerator; }
/** @deprecated Retrieves the program bind symbol for
this parameter. This information should be available
per-shader, in the FCDEffectPassShader class.
@return The program bind symbol. */
const string& GetBindSymbol() const { return bindSymbol; }
/** @deprecated Sets the program bind symbol for this parameter.
This information is available per-shader, in the FCDEffectPassShader class.
@param _bindSymbol The program bind symbol. */
void SetBindSymbol(const string& _bindSymbol) { bindSymbol = _bindSymbol; }
/** @deprecated Retrieves whether the program bind symbol attached
to this parameter belongs to a fragment/pixel shader.
This information is available per-shader, in the FCDEffectPassShader class.
@return Whether it belongs to a fragment/pixel shader. */
bool IsFragment() const { return isFragment; }
/** @deprecated Sets whether the program bind symbol attached to this
parameter belongs to a fragment/pixel shader.
This information is available per-shader, in the FCDEffectPassShader class.
@param _isFragment Whether it belongs to a fragment/pixel shader. */
void SetFragment(bool _isFragment) { isFragment = _isFragment;}
/** Creates a full copy of the effect parameter.
@return The cloned effect parameter. You will need to delete this pointer. */
virtual FCDEffectParameter* Clone() = 0;
/** [INTERNAL] Overwrites the target parameter with this parameter.
This function is used during the flattening of materials.
@param target The target parameter to overwrite. */
virtual void Overwrite(FCDEffectParameter* target);
/** [INTERNAL] Reads in the effect parameter from a given COLLADA XML tree node.
@param parameterNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the parameter.*/
virtual FUStatus LoadFromXML(xmlNode* parameterNode);
/** [INTERNAL] Writes out the effect parameter to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the parameter.
@return The created element XML tree node. */
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
protected:
/** [INTERNAL] Copies into the given effect parameters, the variables
held by the FCDEffectParameter interface. This function is used by the classes
based on this interface during the cloning process.
@param clone The parameter to clone. */
void Clone(FCDEffectParameter* clone);
};
/**
A COLLADA sampler effect parameter.
A sampler parameter provides the extra texturing information necessary
to correctly sample a surface parameter.
There are four types of samplers supported: 1D, 2D, 3D and cube.
@ingroup FCDEffect
*/
class FCOLLADA_EXPORT FCDEffectParameterSampler : public FCDEffectParameter
{
public:
/** The type of sampling to execute. */
enum SamplerType
{
SAMPLER1D, /** 1D sampling. */
SAMPLER2D, /** 2D sampling. */
SAMPLER3D, /** 3D sampling. */
SAMPLERCUBE /** Cube-map sampling. */
};
private:
SamplerType samplerType;
string surfaceSid;
public:
/** Constructor: do not use directly.
Instead, use the FCDEffectParameterList::AddParameter function.
@param document The COLLADA document that owns the effect parameter. */
FCDEffectParameterSampler(FCDocument* document);
/** Destructor: do not use directly.
Instead, use the FCDEffectParameterList::ReleaseParameter function.
When released, the effect parameter list will also release all
its parameters, if it owns them. */
virtual ~FCDEffectParameterSampler();
/** Retrieves the type of effect parameter class.
@return The parameter class type: SAMPLER. */
virtual Type GetType() const { return SAMPLER; }
/** Retrieves the sub-id of the surface parameter.
You will want to search for that sub-id within the parameters to find the
FCDEffectParameterSurface object.
@return The sub-id. */
const char* GetSurfaceSid() const { return surfaceSid.c_str(); }
/** Sets the sub-id of the surface parameter to sample.
@param sid The surface parameter sub-id. */
void SetSurfaceSid(const char* sid) { surfaceSid = sid; }
/** Retrieves the type of sampling to do.
@return The sampling type. */
SamplerType GetSamplerType() const { return samplerType; }
/** Sets the type of sampling to do.
@param type The sampling type. */
void SetSamplerType(SamplerType type) { samplerType = type; }
/** Creates a full copy of the effect parameter.
@return The cloned effect parameter. You will need to delete this pointer. */
virtual FCDEffectParameter* Clone();
/** [INTERNAL] Overwrites the target parameter with this parameter.
This function is used during the flattening of materials.
@param target The target parameter to overwrite. */
virtual void Overwrite(FCDEffectParameter* target);
/** [INTERNAL] Reads in the effect parameter from a given COLLADA XML tree node.
@param parameterNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the parameter.*/
virtual FUStatus LoadFromXML(xmlNode* parameterNode);
/** [INTERNAL] Writes out the effect parameter to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the parameter.
@return The created element XML tree node. */
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
/**
A COLLADA integer effect parameter.
Contains a single, unanimated integer.
*/
class FCOLLADA_EXPORT FCDEffectParameterInt : public FCDEffectParameter
{
private:
int value;
public:
/** Constructor: do not use directly.
Instead, use the FCDEffectParameterList::AddParameter function.
@param document The COLLADA document that owns the effect parameter. */
FCDEffectParameterInt(FCDocument* document);
/** Destructor: do not use directly.
Instead, use the FCDEffectParameterList::ReleaseParameter function.
When released, the effect parameter list will also release all
its parameters, if it owns them. */
virtual ~FCDEffectParameterInt();
/** Retrieves the type of effect parameter class.
@return The parameter class type: INTEGER. */
virtual Type GetType() const { return INTEGER; }
/** Retrieves the value of the effect parameter.
@return The integer value. */
int GetValue() const { return value; }
/** Sets the integer value of the effect parameter.
@param _value The integer value. */
void SetValue(int _value) { value = _value; }
/** Creates a full copy of the effect parameter.
@return The cloned effect parameter. You will need to delete this pointer. */
virtual FCDEffectParameter* Clone();
/** [INTERNAL] Overwrites the target parameter with this parameter.
This function is used during the flattening of materials.
@param target The target parameter to overwrite. */
virtual void Overwrite(FCDEffectParameter* target);
/** [INTERNAL] Reads in the effect parameter from a given COLLADA XML tree node.
@param parameterNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the parameter.*/
virtual FUStatus LoadFromXML(xmlNode* parameterNode);
/** [INTERNAL] Writes out the effect parameter to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the parameter.
@return The created element XML tree node. */
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
/**
A COLLADA boolean effect parameter.
Contains a single, unanimated boolean.
*/
class FCOLLADA_EXPORT FCDEffectParameterBool : public FCDEffectParameter
{
private:
bool value;
public:
/** Constructor: do not use directly.
Instead, use the FCDEffectParameterList::AddParameter function.
@param document The COLLADA document that owns the effect parameter. */
FCDEffectParameterBool(FCDocument* document);
/** Destructor: do not use directly.
Instead, use the FCDEffectParameterList::ReleaseParameter function.
When released, the effect parameter list will also release all
its parameters, if it owns them. */
virtual ~FCDEffectParameterBool();
/** Retrieves the type of effect parameter class.
@return The parameter class type: BOOLEAN. */
virtual Type GetType() const { return BOOLEAN; }
/** Retrieves the boolean value of the effect parameter.
@return The boolean value. */
bool GetValue() const { return value; }
/** Sets the boolean value of the effect parameter.
@param _value The boolean value. */
void SetValue(bool _value) { value = _value; }
/** Creates a full copy of the effect parameter.
@return The cloned effect parameter. You will need to delete this pointer. */
virtual FCDEffectParameter* Clone();
/** [INTERNAL] Overwrites the target parameter with this parameter.
This function is used during the flattening of materials.
@param target The target parameter to overwrite. */
virtual void Overwrite(FCDEffectParameter* target);
/** [INTERNAL] Reads in the effect parameter from a given COLLADA XML tree node.
@param parameterNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the parameter.*/
virtual FUStatus LoadFromXML(xmlNode* parameterNode);
/** [INTERNAL] Writes out the effect parameter to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the parameter.
@return The created element XML tree node. */
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
/**
A COLLADA string effect parameter.
Contains a single, unanimated string.
*/
class FCOLLADA_EXPORT FCDEffectParameterString : public FCDEffectParameter
{
private:
string value;
public:
/** Constructor: do not use directly.
Instead, use the FCDEffectParameterList::AddParameter function.
@param document The COLLADA document that owns the effect parameter. */
FCDEffectParameterString(FCDocument* document);
/** Destructor: do not use directly.
Instead, use the FCDEffectParameterList::ReleaseParameter function.
When released, the effect parameter list will also release all
its parameters, if it owns them. */
virtual ~FCDEffectParameterString();
/** Retrieves the type of effect parameter class.
@return The parameter class type: STRING. */
virtual Type GetType() const { return STRING; }
/** Retrieves the string contained in the effect parameter.
@return The string. */
const string& GetValue() const { return value; }
/** Sets the string contained in the effect parameter.
@param _value The string. */
void SetValue(const string& _value) { value = _value; }
/** Creates a full copy of the effect parameter.
@return The cloned effect parameter. You will need to delete this pointer. */
virtual FCDEffectParameter* Clone();
/** [INTERNAL] Overwrites the target parameter with this parameter.
This function is used during the flattening of materials.
@param target The target parameter to overwrite. */
virtual void Overwrite(FCDEffectParameter* target);
/** [INTERNAL] Reads in the effect parameter from a given COLLADA XML tree node.
@param parameterNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the parameter.*/
virtual FUStatus LoadFromXML(xmlNode* parameterNode);
/** [INTERNAL] Writes out the effect parameter to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the parameter.
@return The created element XML tree node. */
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
/**
A COLLADA float effect parameter.
Contains a single, possibly animated, floating-point value.
The type of the floating-point value may be HALF or FLOAT.
*/
class FCOLLADA_EXPORT FCDEffectParameterFloat : public FCDEffectParameter
{
public:
/** The supported types of float-point values. */
enum FloatType
{
FLOAT, /** A full-fledged floating-point value. This is the default. */
HALF /** Probably implies a 16-bit floating-point value. */
};
private:
FloatType floatType;
float value;
float min;
float max;
public:
/** Constructor: do not use directly.
Instead, use the FCDEffectParameterList::AddParameter function.
@param document The COLLADA document that owns the effect parameter. */
FCDEffectParameterFloat(FCDocument* document);
/** Destructor: do not use directly.
Instead, use the FCDEffectParameterList::ReleaseParameter function.
When released, the effect parameter list will also release all
its parameters, if it owns them. */
virtual ~FCDEffectParameterFloat();
/** Retrieves the type of effect parameter class.
@return The parameter class type: FLOAT. */
virtual FCDEffectParameter::Type GetType() const { return FCDEffectParameter::FLOAT; }
/** Retrieves the type of floating-point value held by this effect parameter.
@return The type of floating-point value. */
FloatType GetFloatType() const { return floatType; }
/** Sets the type of floating-point value held by this effect parameter.
@param type The type of floating-point value. */
void SetFloatType(FloatType type) { floatType = type; }
/** Retrieves the floating-point value of the effect parameter.
@return The floating-point value. */
float& GetValue() { return value; }
const float& GetValue() const { return value; } /**< See above. */
/** Sets the floating-point value of the effect parameter.
@param _value The floating-point value. */
void SetValue(float _value) { value = _value; }
/** Retrieves the minimum value for the UI widget created for this effect parameter.
This value is for UI purposes only and has no real impact on the value.
@return The minimum value. */
float GetMin() const { return min; }
/** Sets the minimum value for the UI widget created for this effect parameter.
This value is for UI purposes only and has no real impact on the value.
@param _min The minimum value. */
void SetMin(float _min) { min = _min; }
/** Retrieves the maximum value for the UI widget created for this effect parameter.
This value is for UI purposes only and has no real impact on the value.
@return The maximum value. */
float GetMax() const { return max; }
/** Sets the maximum value for the UI widget created for this effect parameter.
This value is for UI purposes only and has no real impact on the value.
@param _max The maximum value. */
void SetMax(float _max) { max = _max; }
/** Creates a full copy of the effect parameter.
@return The cloned effect parameter. You will need to delete this pointer. */
virtual FCDEffectParameter* Clone();
/** [INTERNAL] Overwrites the target parameter with this parameter.
This function is used during the flattening of materials.
@param target The target parameter to overwrite. */
virtual void Overwrite(FCDEffectParameter* target);
/** [INTERNAL] Reads in the effect parameter from a given COLLADA XML tree node.
@param parameterNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the parameter.*/
virtual FUStatus LoadFromXML(xmlNode* parameterNode);
/** [INTERNAL] Writes out the effect parameter to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the parameter.
@return The created element XML tree node. */
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
/**
A COLLADA 2D vector of floats.
Contains two, possibly animated, floating-point values.
The type of the floating-point values may be HALF or FLOAT.
*/
class FCOLLADA_EXPORT FCDEffectParameterFloat2 : public FCDEffectParameter
{
public:
/** The supported types of float-point values. */
enum FloatType
{
FLOAT, /** A full-fledged floating-point value. This is the default. */
HALF /** Probably implies a 16-bit floating-point value. */
};
private:
FloatType floatType;
float value_x;
float value_y;
public:
/** Constructor: do not use directly.
Instead, use the FCDEffectParameterList::AddParameter function.
@param document The COLLADA document that owns the effect parameter. */
FCDEffectParameterFloat2(FCDocument* document);
/** Destructor: do not use directly.
Instead, use the FCDEffectParameterList::ReleaseParameter function.
When released, the effect parameter list will also release all
its parameters, if it owns them. */
virtual ~FCDEffectParameterFloat2();
/** Retrieves the type of effect parameter class.
@return The parameter class type: FLOAT2. */
virtual Type GetType() const { return FLOAT2; }
/** Retrieves the type of floating-point value held by this effect parameter.
@return The type of floating-point value. */
FloatType GetFloatType() const { return floatType; }
/** Sets the type of floating-point value held by this effect parameter.
@param type The type of floating-point value. */
void SetFloatType(FloatType type) { floatType = type; }
/** Retrieves the first floating-point value of the effect parameter.
@return The first floating-point value. */
float& GetValueX() { return value_x; }
const float& GetValueX() const { return value_x; } /**< See above. */
/** Sets the first floating-point value of the effect parameter.
@param value The first floating-point value. */
void SetValueX(float value) { value_x = value; }
/** Retrieves the second floating-point value of the effect parameter.
@return The second floating-point value. */
float& GetValueY() { return value_y; }
const float& GetValueY() const { return value_y; } /**< See above. */
/** Sets the second floating-point value of the effect parameter.
@param value The second floating-point value. */
void SetValueY(float value) { value_y = value; }
/** Creates a full copy of the effect parameter.
@return The cloned effect parameter. You will need to delete this pointer. */
virtual FCDEffectParameter* Clone();
/** [INTERNAL] Overwrites the target parameter with this parameter.
This function is used during the flattening of materials.
@param target The target parameter to overwrite. */
virtual void Overwrite(FCDEffectParameter* target);
/** [INTERNAL] Reads in the effect parameter from a given COLLADA XML tree node.
@param parameterNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the parameter.*/
virtual FUStatus LoadFromXML(xmlNode* parameterNode);
/** [INTERNAL] Writes out the effect parameter to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the parameter.
@return The created element XML tree node. */
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
/**
A COLLADA 3D vector of floats.
Contains three, possibly animated, floating-point values.
The type of the floating-point values may be HALF or FLOAT.
*/
class FCOLLADA_EXPORT FCDEffectParameterFloat3 : public FCDEffectParameter
{
public:
/** The supported types of float-point values. */
enum FloatType
{
FLOAT, /** A full-fledged floating-point value. This is the default. */
HALF /** Probably implies a 16-bit floating-point value. */
};
private:
FloatType floatType;
FMVector3 value;
public:
/** Constructor: do not use directly.
Instead, use the FCDEffectParameterList::AddParameter function.
@param document The COLLADA document that owns the effect parameter. */
FCDEffectParameterFloat3(FCDocument* document);
/** Destructor: do not use directly.
Instead, use the FCDEffectParameterList::ReleaseParameter function.
When released, the effect parameter list will also release all
its parameters, if it owns them. */
virtual ~FCDEffectParameterFloat3();
/** Retrieves the type of effect parameter class.
@return The parameter class type: FLOAT3. */
virtual Type GetType() const { return FLOAT3; }
/** Retrieves the type of floating-point value held by this effect parameter.
@return The type of floating-point value. */
FloatType GetFloatType() const { return floatType; }
/** Sets the type of floating-point value held by this effect parameter.
@param type The type of floating-point value. */
void SetFloatType(FloatType type) { floatType = type; }
/** Retrieves the first floating-point value of the effect parameter.
@return The first floating-point value. */
float& GetValueX() { return value.x; }
const float& GetValueX() const { return value.x; } /**< See above. */
/** Sets the first floating-point value of the effect parameter.
@param _value The first floating-point value. */
void SetValueX(float _value) { value.x = _value; }
/** Retrieves the second floating-point value of the effect parameter.
@return The second floating-point value. */
float& GetValueY() { return value.y; }
const float& GetValueY() const { return value.y; } /**< See above. */
/** Sets the second floating-point value of the effect parameter.
@param _value The second floating-point value. */
void SetValueY(float _value) { value.y = _value; }
/** Retrieves the third floating-point value of the effect parameter.
@return The third floating-point value. */
float& GetValueZ() { return value.z; }
const float& GetValueZ() const { return value.z; } /**< See above. */
/** Sets the third floating-point value of the effect parameter.
@param _value The third floating-point value. */
void SetValueZ(float _value) { value.z = _value; }
/** Creates a full copy of the effect parameter.
@return The cloned effect parameter. You will need to delete this pointer. */
virtual FCDEffectParameter* Clone();
/** [INTERNAL] Overwrites the target parameter with this parameter.
This function is used during the flattening of materials.
@param target The target parameter to overwrite. */
virtual void Overwrite(FCDEffectParameter* target);
/** [INTERNAL] Reads in the effect parameter from a given COLLADA XML tree node.
@param parameterNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the parameter.*/
virtual FUStatus LoadFromXML(xmlNode* parameterNode);
/** [INTERNAL] Writes out the effect parameter to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the parameter.
@return The created element XML tree node. */
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
/**
A COLLADA 4D vector of floats.
Contains four, possibly animated, floating-point values.
The type of the floating-point values may be HALF or FLOAT.
*/
class FCOLLADA_EXPORT FCDEffectParameterVector : public FCDEffectParameter
{
public:
/** The supported types of float-point values. */
enum FloatType
{
FLOAT, /** A full-fledged floating-point value. This is the default. */
HALF /** Probably implies a 16-bit floating-point value. */
};
private:
FloatType floatType;
float vector[4];
public:
/** Constructor: do not use directly.
Instead, use the FCDEffectParameterList::AddParameter function.
@param document The COLLADA document that owns the effect parameter. */
FCDEffectParameterVector(FCDocument* document);
/** Destructor: do not use directly.
Instead, use the FCDEffectParameterList::ReleaseParameter function.
When released, the effect parameter list will also release all
its parameters, if it owns them. */
virtual ~FCDEffectParameterVector();
/** Retrieves the type of effect parameter class.
@return The parameter class type: VECTOR. */
virtual Type GetType() const { return VECTOR; }
/** Retrieves the type of floating-point value held by this effect parameter.
@return The type of floating-point value. */
FloatType GetFloatType() const { return floatType; }
/** Sets the type of floating-point value held by this effect parameter.
@param type The type of floating-point value. */
void SetFloatType(FloatType type) { floatType = type; }
/** Sets the vector value of the effect parameter.
@return The vector value. */
float* GetVector() { return vector; }
const float* GetVector() const { return vector; } /**< See above. */
/** Retrieves the first floating-point value of the effect parameter.
@return The first floating-point value. */
float& GetValueX() { return vector[0]; }
const float& GetValueX() const { return vector[0]; } /**< See above. */
/** Sets the first floating-point value of the effect parameter.
@param _value The first floating-point value. */
void SetValueX(float _value) { vector[0] = _value; }
/** Retrieves the second floating-point value of the effect parameter.
@return The second floating-point value. */
float& GetValueY() { return vector[1]; }
const float& GetValueY() const { return vector[1]; } /**< See above. */
/** Sets the second floating-point value of the effect parameter.
@param _value The second floating-point value. */
void SetValueY(float _value) { vector[1] = _value; }
/** Retrieves the third floating-point value of the effect parameter.
@return The third floating-point value. */
float& GetValueZ() { return vector[2]; }
const float& GetValueZ() const { return vector[2]; } /**< See above. */
/** Sets the third floating-point value of the effect parameter.
@param _value The third floating-point value. */
void SetValueZ(float _value) { vector[2] = _value; }
/** Retrieves the fourth floating-point value of the effect parameter.
@return The fourth floating-point value. */
float& GetValueW() { return vector[3]; }
const float& GetValueW() const { return vector[3]; } /**< See above. */
/** Sets the fourth floating-point value of the effect parameter.
@param _value The fourth floating-point value. */
void SetValueW(float _value) { vector[3] = _value; }
/** Creates a full copy of the effect parameter.
@return The cloned effect parameter. You will need to delete this pointer. */
virtual FCDEffectParameter* Clone();
/** [INTERNAL] Overwrites the target parameter with this parameter.
This function is used during the flattening of materials.
@param target The target parameter to overwrite. */
virtual void Overwrite(FCDEffectParameter* target);
/** [INTERNAL] Reads in the effect parameter from a given COLLADA XML tree node.
@param parameterNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the parameter.*/
virtual FUStatus LoadFromXML(xmlNode* parameterNode);
/** [INTERNAL] Writes out the effect parameter to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the parameter.
@return The created element XML tree node. */
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
/**
A COLLADA 4x4 matrix.
Contains 16 floating-point values that represent a COLLADA column-major 4x4 matrix.
The type of the floating-point values may be HALF or FLOAT.
*/
class FCOLLADA_EXPORT FCDEffectParameterMatrix : public FCDEffectParameter
{
public:
/** The supported types of float-point values. */
enum FloatType
{
FLOAT, /** A full-fledged floating-point value. This is the default. */
HALF /** Probably implies a 16-bit floating-point value. */
};
private:
FloatType floatType;
FMMatrix44 matrix;
public:
/** Constructor: do not use directly.
Instead, use the FCDEffectParameterList::AddParameter function.
@param document The COLLADA document that owns the effect parameter. */
FCDEffectParameterMatrix(FCDocument* document);
/** Destructor: do not use directly.
Instead, use the FCDEffectParameterList::ReleaseParameter function.
When released, the effect parameter list will also release all
its parameters, if it owns them. */
virtual ~FCDEffectParameterMatrix();
/** Retrieves the type of effect parameter class.
@return The parameter class type: MATRIX. */
virtual Type GetType() const { return MATRIX; }
/** Retrieves the type of floating-point value held by this effect parameter.
@return The type of floating-point value. */
FloatType GetFloatType() const { return floatType; }
/** Sets the type of floating-point value held by this effect parameter.
@param type The type of floating-point value. */
void SetFloatType(FloatType type) { floatType = type; }
/** Retrieves the matrix contained within this effect parameter.
@return The matrix. */
FMMatrix44& GetMatrix() { return matrix; }
const FMMatrix44& GetMatrix() const { return matrix; } /**< See above. */
/** Sets the matrix contained within this effect parameter.
@param mx The matrix. */
void SetMatrix(const FMMatrix44& mx) { matrix = mx; }
/** Creates a full copy of the effect parameter.
@return The cloned effect parameter. You will need to delete this pointer. */
virtual FCDEffectParameter* Clone();
/** [INTERNAL] Overwrites the target parameter with this parameter.
This function is used during the flattening of materials.
@param target The target parameter to overwrite. */
virtual void Overwrite(FCDEffectParameter* target);
/** [INTERNAL] Reads in the effect parameter from a given COLLADA XML tree node.
@param parameterNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the parameter.*/
virtual FUStatus LoadFromXML(xmlNode* parameterNode);
/** [INTERNAL] Writes out the effect parameter to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the parameter.
@return The created element XML tree node. */
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif // _FCD_EFFECT_PARAMETER_H_

View File

@@ -0,0 +1,70 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDEffectParameter.h"
#include "FCDocument/FCDEffectParameterFactory.h"
#include "FCDocument/FCDEffectParameterSurface.h"
#include "FUtils/FUDaeParser.h"
// Creates a new effect parameter, given a type.
FCDEffectParameter* FCDEffectParameterFactory::Create(FCDocument* document, uint32 type)
{
FCDEffectParameter* parameter = NULL;
switch (type)
{
case FCDEffectParameter::SAMPLER: parameter = new FCDEffectParameterSampler(document); break;
case FCDEffectParameter::INTEGER: parameter = new FCDEffectParameterInt(document); break;
case FCDEffectParameter::BOOLEAN: parameter = new FCDEffectParameterBool(document); break;
case FCDEffectParameter::FLOAT: parameter = new FCDEffectParameterFloat(document); break;
case FCDEffectParameter::FLOAT2: parameter = new FCDEffectParameterFloat2(document); break;
case FCDEffectParameter::FLOAT3: parameter = new FCDEffectParameterFloat3(document); break;
case FCDEffectParameter::VECTOR: parameter = new FCDEffectParameterVector(document); break;
case FCDEffectParameter::MATRIX: parameter = new FCDEffectParameterMatrix(document); break;
case FCDEffectParameter::STRING: parameter = new FCDEffectParameterString(document); break;
case FCDEffectParameter::SURFACE: parameter = new FCDEffectParameterSurface(document); break;
default: break;
}
return parameter;
}
// Generates the effect parameter object for the given XML node tree
FCDEffectParameter* FCDEffectParameterFactory::LoadFromXML(FCDocument* document, xmlNode* parameterNode, FUStatus* status)
{
// Look for the type of the parameter.
FCDEffectParameter* parameter = NULL;
for (xmlNode* child = parameterNode->children; child != NULL && parameter == NULL; child = child->next)
{
if (child->type != XML_ELEMENT_NODE) continue;
if (IsEquivalent(child->name, DAE_FXCMN_BOOL_ELEMENT)) parameter = new FCDEffectParameterBool(document);
else if (IsEquivalent(child->name, DAE_FXCMN_FLOAT_ELEMENT)) parameter = new FCDEffectParameterFloat(document);
else if (IsEquivalent(child->name, DAE_FXCMN_FLOAT2_ELEMENT)) parameter = new FCDEffectParameterFloat2(document);
else if (IsEquivalent(child->name, DAE_FXCMN_FLOAT3_ELEMENT)) parameter = new FCDEffectParameterFloat3(document);
else if (IsEquivalent(child->name, DAE_FXCMN_FLOAT4_ELEMENT)) parameter = new FCDEffectParameterVector(document);
else if (IsEquivalent(child->name, DAE_FXCMN_FLOAT4X4_ELEMENT)) parameter = new FCDEffectParameterMatrix(document);
else if (IsEquivalent(child->name, DAE_FXCMN_HALF_ELEMENT)) parameter = new FCDEffectParameterFloat(document);
else if (IsEquivalent(child->name, DAE_FXCMN_HALF2_ELEMENT)) parameter = new FCDEffectParameterFloat2(document);
else if (IsEquivalent(child->name, DAE_FXCMN_HALF3_ELEMENT)) parameter = new FCDEffectParameterFloat3(document);
else if (IsEquivalent(child->name, DAE_FXCMN_HALF4_ELEMENT)) parameter = new FCDEffectParameterVector(document);
else if (IsEquivalent(child->name, DAE_FXCMN_HALF4X4_ELEMENT)) parameter = new FCDEffectParameterMatrix(document);
else if (IsEquivalent(child->name, DAE_FXCMN_INT_ELEMENT)) parameter = new FCDEffectParameterInt(document);
else if (IsEquivalent(child->name, DAE_FXCMN_SAMPLER1D_ELEMENT)) parameter = new FCDEffectParameterSampler(document);
else if (IsEquivalent(child->name, DAE_FXCMN_SAMPLER2D_ELEMENT)) parameter = new FCDEffectParameterSampler(document);
else if (IsEquivalent(child->name, DAE_FXCMN_SAMPLER3D_ELEMENT)) parameter = new FCDEffectParameterSampler(document);
else if (IsEquivalent(child->name, DAE_FXCMN_SAMPLERCUBE_ELEMENT)) parameter = new FCDEffectParameterSampler(document);
else if (IsEquivalent(child->name, DAE_FXCMN_SURFACE_ELEMENT)) parameter = new FCDEffectParameterSurface(document);
else if (IsEquivalent(child->name, DAE_FXCMN_STRING_ELEMENT)) parameter = new FCDEffectParameterString(document);
}
if (parameter != NULL)
{
FUStatus s = parameter->LoadFromXML(parameterNode);
if (status != NULL) status->AppendStatus(s);
}
return parameter;
}

View File

@@ -0,0 +1,47 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
/**
@file FCDEffectParameterFactory.h
This file contains the FCDEffectParameterFactory class.
*/
#ifndef _FCD_EFFECT_PARAMETER_FACTORY_H_
#define _FCD_EFFECT_PARAMETER_FACTORY_H_
class FCDocument;
/**
[INTERNAL] The factory for COLLADA effect parameters.
Takes in a COLLADA XML tree and returns a new
parameter that represent it, if one is possible.
@ingroup FCDEffect
*/
class FCOLLADA_EXPORT FCDEffectParameterFactory
{
private:
// Never instantiate: this is a static class
FCDEffectParameterFactory() {}
public:
/** [INTERNAL] Creates a new effect parameter, given a type.
To create new effect parameters, use the FCDEffectParameterList::AddParameter function.
@param document The COLLADA document that will own the effect parameter.
@param type The type of effect to create.
This value should reflect the FCDEffectParameter::Type enum. */
static FCDEffectParameter* Create(FCDocument* document, uint32 type);
/** [INTERNAL] Generates the effect parameter object for the given XML node tree.
@param document The COLLADA document that will own the effect parameter.
@param parameterNode The COLLADA XML tree node.
@param status An optional return status.
@return The new effect parameter. This pointer will be NULL if no parameter can be generated
from the given COLLADA XML tree node. */
static FCDEffectParameter* LoadFromXML(FCDocument* document, xmlNode* parameterNode, FUStatus* status);
};
#endif // _FCD_EFFECT_PARAMETER_FACTORY_H_

View File

@@ -0,0 +1,124 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDEffectParameter.h"
#include "FCDocument/FCDEffectParameterFactory.h"
#include "FCDocument/FCDEffectParameterList.h"
FCDEffectParameterList::FCDEffectParameterList(FCDocument* document, bool _ownParameters)
: FCDObject(document, "FCDEffectParameterList")
{
ownParameters = _ownParameters;
}
FCDEffectParameterList::~FCDEffectParameterList()
{
if (ownParameters)
{
size_t l = size();
for (size_t i = 0; i < l; ++i)
{
FCDEffectParameter* p = at(i);
SAFE_DELETE(p);
}
}
clear();
ownParameters = false;
}
FCDEffectParameter* FCDEffectParameterList::AddParameter(uint32 type)
{
FCDEffectParameter* parameter = NULL;
if (ownParameters)
{
parameter = FCDEffectParameterFactory::Create(GetDocument(), type);
push_back(parameter);
}
return parameter;
}
void FCDEffectParameterList::ReleaseParameter(FCDEffectParameter* parameter)
{
iterator it = std::find(begin(), end(), parameter);
if (it != end())
{
if (ownParameters) delete *it;
erase(it);
}
}
FCDEffectParameter* FCDEffectParameterList::FindReference(const char* reference)
{
for (iterator it = begin(); it != end(); ++it)
{
if ((*it)->GetReference() == reference) return (*it);
}
return NULL;
}
const FCDEffectParameter* FCDEffectParameterList::FindReference(const char* reference) const
{
for (const_iterator it = begin(); it != end(); ++it)
{
if ((*it)->GetReference() == reference) return (*it);
}
return NULL;
}
FCDEffectParameter* FCDEffectParameterList::FindSemantic(const char* semantic)
{
for (iterator it = begin(); it != end(); ++it)
{
if ((*it)->GetSemantic() == semantic) return (*it);
}
return NULL;
}
const FCDEffectParameter* FCDEffectParameterList::FindSemantic(const char* semantic) const
{
for (const_iterator it = begin(); it != end(); ++it)
{
if ((*it)->GetSemantic() == semantic) return (*it);
}
return NULL;
}
void FCDEffectParameterList::FindReference(const char* reference, FCDEffectParameterList& list)
{
for (iterator it = begin(); it != end(); ++it)
{
if ((*it)->GetReference() == reference) list.push_back(*it);
}
}
void FCDEffectParameterList::FindSemantic(const char* semantic, FCDEffectParameterList& list)
{
for (iterator it = begin(); it != end(); ++it)
{
if ((*it)->GetSemantic() == semantic) list.push_back(*it);
}
}
// Copy this list
FCDEffectParameterList* FCDEffectParameterList::Clone() const
{
FCDEffectParameterList* clone = new FCDEffectParameterList(GetDocument(), ownParameters);
if (!empty())
{
clone->reserve(size());
if (ownParameters)
{
for (const_iterator it = begin(); it != end(); ++it)
{
clone->push_back((*it)->Clone());
}
}
else
{
(*clone) = (*this);
}
}
return clone;
}

View File

@@ -0,0 +1,93 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
/**
@file FCDEffectParameterList.h
This file contains the FCDEffectParameterList class.
*/
#ifndef _FCD_EFFECT_PARAMETER_LIST_H_
#define _FCD_EFFECT_PARAMETER_LIST_H_
class FCDEffectParameter;
/**
A searchable list of COLLADA effect parameters.
This class is based on the STL vector class and adds some
useful search methods: by reference and by semantic.
@ingroup FCDEffect
*/
class FCOLLADA_EXPORT FCDEffectParameterList : public vector<FCDEffectParameter*>, public FCDObject
{
private:
bool ownParameters;
public:
/** Constructor.
All the objects that need a parameter list will create it when necessary.
You may also create new lists for the retrieval of parameters during a search.
@param document The COLLADA document that owns this parameter list. This pointer
can remain NULL unless you expect to create new parameters within this list.
@param ownParameters Whether this list should release the contained parameters
during its destruction. */
FCDEffectParameterList(FCDocument* document = NULL, bool ownParameters = false);
/** Destructor. */
virtual ~FCDEffectParameterList();
/** Creates a new parameters within this list.
@param type The effect parameter type.
@return The new effect parameter. This pointer will be NULL if this list does not own its parameters. */
FCDEffectParameter* AddParameter(uint32 type);
/** Releases a parameter contained within this list.
The memory used by this parameter will be released only if this list owns the parameters.
@param parameter The effect parameter to release. */
void ReleaseParameter(FCDEffectParameter* parameter);
/** Retrieves the first effect parameter with the given reference.
For effect parameter generators, the sub-id is used instead of the reference.
@param reference A reference to match.
@return The effect parameter that matches the reference. This pointer will be NULL,
if no parameter matches the reference. */
FCDEffectParameter* FindReference(const char* reference);
const FCDEffectParameter* FindReference(const char* reference) const; /**< See above. */
inline FCDEffectParameter* FindReference(const string& reference) { return FindReference(reference.c_str()); } /**< See above. */
inline const FCDEffectParameter* FindReference(const string& reference) const { return FindReference(reference.c_str()); } /**< See above. */
/** Retrieves the first effect parameter with the given semantic.
@param semantic A semantic to match.
@return The effect parameter that matches the semantic. This pointer will be NULL
if no parameter matches the semantic. */
FCDEffectParameter* FindSemantic(const char* semantic);
const FCDEffectParameter* FindSemantic(const char* semantic) const; /**< See above. */
inline FCDEffectParameter* FindSemantic(const string& semantic) { return FindReference(semantic.c_str()); } /**< See above. */
inline const FCDEffectParameter* FindSemantic(const string& semantic) const { return FindReference(semantic.c_str()); } /**< See above. */
/** Retrieves a subset of this parameter list.
All the effects that match the given reference will be added to the given list.
For effect parameter generators, the sub-id is used instead of the reference.
@param reference A reference to match.
@param list The effect parameter list to fill in with the matched parameters.
This list is not clear. */
void FindReference(const char* reference, FCDEffectParameterList& list);
inline void FindReference(const string& reference, FCDEffectParameterList& list) { return FindReference(reference.c_str(), list); } /**< See above. */
/** Retrieves a subset of this parameter list.
All the effects that match the given semantic will be added to the given list.
@param semantic A semantic to match.
@param list The effect parameter list to fill in with the matched parameters.
This list is not clear. */
void FindSemantic(const char* semantic, FCDEffectParameterList& list);
inline void FindSemantic(const string& semantic, FCDEffectParameterList& list) { return FindReference(semantic.c_str(), list); } /**< See above. */
/** Creates a full copy of the list of parameters and its content.
@return The cloned list. You will need to delete this pointer.*/
FCDEffectParameterList* Clone() const;
};
#endif // _FCD_EFFECT_PARAMETER_LIST_H_

View File

@@ -0,0 +1,589 @@
/*
Copyright (C) 2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDocument.h"
#include "FCDocument/FCDAnimated.h"
#include "FCDocument/FCDEffectPass.h"
#include "FCDocument/FCDEffectProfile.h"
#include "FCDocument/FCDEffectTechnique.h"
#include "FCDocument/FCDEffectParameter.h"
#include "FCDocument/FCDEffectParameterSurface.h"
#include "FCDocument/FCDImage.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
// surface type parameter
FCDEffectParameterSurface::FCDEffectParameterSurface(FCDocument* document) : FCDEffectParameter(document)
{
initMethod = NULL;
}
FCDEffectParameterSurface::~FCDEffectParameterSurface()
{
SAFE_DELETE(initMethod);
names.clear();
images.clear();
}
void FCDEffectParameterSurface::SetInitMethod(FCDEffectParameterSurfaceInit* method)
{
SAFE_DELETE(initMethod);
initMethod = method;
}
// Retrieves the index that matches the given image.
size_t FCDEffectParameterSurface::FindImage(const FCDImage* image) const
{
FCDImageList::const_iterator it = std::find(images.begin(), images.end(), image);
if (it != images.end())
{
return it - images.begin();
}
else return (size_t) -1;
}
// Adds an image to the list.
size_t FCDEffectParameterSurface::AddImage(FCDImage* image)
{
size_t index = FindImage(image);
if (index == (size_t) -1)
{
index = images.size();
images.push_back(image);
}
return index;
}
// Removes an image from the list.
void FCDEffectParameterSurface::RemoveImage(FCDImage* image)
{
size_t index = FindImage(image);
if (index != (size_t) -1)
{
images.erase(images.begin() + index);
if (initMethod != NULL && initMethod->GetInitType() == FCDEffectParameterSurfaceInitFactory::CUBE)
{
// Shift down all the indexes found within the cube map initialization.
FCDEffectParameterSurfaceInitCube* cube = (FCDEffectParameterSurfaceInitCube*) initMethod;
for (UInt16List::iterator itI = cube->order.begin(); itI != cube->order.end(); ++itI)
{
if ((*itI) == index) (*itI) = 0;
else if ((*itI) > index) --(*itI);
}
}
}
}
// Clone
FCDEffectParameter* FCDEffectParameterSurface::Clone()
{
FCDEffectParameterSurface* clone = new FCDEffectParameterSurface(GetDocument());
FCDEffectParameter::Clone(clone);
clone->images.clear();
for(uint32 i=0; i<images.size(); i++)
clone->images.push_back(images[i]);
clone->names.clear();
for(uint32 i=0; i<names.size(); i++)
clone->names.push_back(names[i]);
if(initMethod)
clone->initMethod = initMethod->Clone();
clone->size = size;
clone->viewportRatio = viewportRatio;
clone->mipLevelCount = mipLevelCount;
clone->generateMipmaps = generateMipmaps;
return clone;
}
// Flattening: overwrite the target parameter with this parameter
void FCDEffectParameterSurface::Overwrite(FCDEffectParameter* target)
{
if (target->GetType() == SURFACE)
{
FCDEffectParameterSurface* s = (FCDEffectParameterSurface*) target;
s->images.clear();
for(uint32 i=0; i<images.size(); i++)
s->images.push_back(images[i]);
s->names.clear();
for(uint32 i=0; i<names.size(); i++)
s->names.push_back(names[i]);
// s->initMethod->initType = initMethod->GetInitType();
s->size = size;
s->viewportRatio = viewportRatio;
s->mipLevelCount = mipLevelCount;
s->generateMipmaps = generateMipmaps;
}
}
FUStatus FCDEffectParameterSurface::LoadFromXML(xmlNode* parameterNode)
{
FUStatus status = FCDEffectParameter::LoadFromXML(parameterNode);
xmlNode* surfaceNode = FindChildByType(parameterNode, DAE_FXCMN_SURFACE_ELEMENT);
bool initialized = false;
xmlNode* valueNode = NULL;
//The surface can now contain many init_from elements (1.4.1)
xmlNodeList valueNodes;
FindChildrenByType(surfaceNode, DAE_INITFROM_ELEMENT, valueNodes);
for (xmlNodeList::iterator it = valueNodes.begin(); it != valueNodes.end(); ++it)
{
initialized = true;
if(!initMethod)
initMethod = new FCDEffectParameterSurfaceInitFrom();
FCDEffectParameterSurfaceInitFrom* ptrInit = (FCDEffectParameterSurfaceInitFrom*)initMethod;
StringList tempNames;
FUStringConversion::ToStringList(ReadNodeContentDirect(*it), tempNames);
if (tempNames.size() == 0 || tempNames[0].empty())
{
return status.Fail(FS("<init_from> element is empty in surface parameter: ") + TO_FSTRING(GetReference()), parameterNode->line);
}
if(tempNames.size() == 1) //might be 1.4.1, so allow the attributes mip, slice, face
{
if(HasNodeProperty(*it, DAE_MIP_ATTRIBUTE))
{
string mip = ReadNodeProperty(*it, DAE_MIP_ATTRIBUTE);
ptrInit->mip.push_back(mip);
}
if(HasNodeProperty(*it, DAE_SLICE_ATTRIBUTE))
{
string slice = ReadNodeProperty(*it, DAE_SLICE_ATTRIBUTE);
ptrInit->slice.push_back(slice);
}
if(HasNodeProperty(*it, DAE_FACE_ATTRIBUTE))
{
string face = ReadNodeProperty(*it, DAE_FACE_ATTRIBUTE);
ptrInit->face.push_back(face);
}
}
//go through the new names, get their images, and add update the image and name lists
for(uint32 i=0; i<tempNames.size(); i++)
{
names.push_back(tempNames[i]);
FCDImage* image = GetDocument()->FindImage(tempNames[i]);
if (image != NULL)
{
images.push_back(image);
}
//else return status.Fail(FS("Unable to find image source for surface parameter: ") + TO_FSTRING(GetReference()), parameterNode->line);
}
}
//Check if it's initialized AS NULL
if(!initialized)
{
valueNode = FindChildByType(surfaceNode, DAE_INITASNULL_ELEMENT);
if(valueNode)
{
initialized = true;
initMethod = FCDEffectParameterSurfaceInitFactory::Create(FCDEffectParameterSurfaceInitFactory::AS_NULL);
}
}
//Check if it's initialized AS TARGET
if(!initialized)
{
valueNode = FindChildByType(surfaceNode, DAE_INITASTARGET_ELEMENT);
if(valueNode)
{
initialized = true;
initMethod = FCDEffectParameterSurfaceInitFactory::Create(FCDEffectParameterSurfaceInitFactory::AS_TARGET);
}
}
//Check if it's initialized AS CUBE
if(!initialized)
{
valueNode = FindChildByType(surfaceNode, DAE_INITCUBE_ELEMENT);
if(valueNode)
{
initialized = true;
initMethod = FCDEffectParameterSurfaceInitFactory::Create(FCDEffectParameterSurfaceInitFactory::CUBE);
FCDEffectParameterSurfaceInitCube* ptrInit = (FCDEffectParameterSurfaceInitCube*) initMethod;
//Check if it's an ALL reference
xmlNode* refNode = FindChildByType(valueNode, DAE_ALL_ELEMENT);
if(refNode)
{
ptrInit->cubeType = FCDEffectParameterSurfaceInitCube::ALL;
string name = ReadNodeProperty(refNode, DAE_REF_ATTRIBUTE);
if (name.empty())
{
return status.Fail(FS("<init_cube>'s all reference is empty in surface parameter: ") + TO_FSTRING(GetReference()), surfaceNode->line);
}
names.push_back(name);
FCDImage* image = GetDocument()->FindImage(name);
if (image == NULL)
{
return status.Fail(FS("Unable to find image source for surface parameter: ") + TO_FSTRING(GetReference()), surfaceNode->line);
}
images.push_back(image);
}
//Check if it's a PRIMARY reference
if(!refNode)
{
refNode = FindChildByType(valueNode, DAE_PRIMARY_ELEMENT);
if(refNode)
{
ptrInit->cubeType = FCDEffectParameterSurfaceInitCube::PRIMARY;
string name = ReadNodeProperty(refNode, DAE_REF_ATTRIBUTE);
if (name.empty())
{
return status.Fail(FS("<init_cube>'s primary reference is empty in surface parameter: ") + TO_FSTRING(GetReference()), valueNode->line);
}
names.push_back(name);
FCDImage* image = GetDocument()->FindImage(name);
if (image == NULL)
{
return status.Fail(FS("Unable to find image source for surface parameter: ") + TO_FSTRING(GetReference()), valueNode->line);
}
images.push_back(image);
xmlNode* orderNode = FindChildByType(refNode, DAE_ORDER_ELEMENT);
if(orderNode)
{
//FIXME: complete when the spec has more info
}
}
}
//Check if it's a FACE reference
if(!refNode)
{
xmlNodeList faceNodes;
FindChildrenByType(valueNode, DAE_FACE_ELEMENT, faceNodes);
if(faceNodes.size()==6)
{
ptrInit->cubeType = FCDEffectParameterSurfaceInitCube::FACE;
for(uint8 ii=0; ii<faceNodes.size(); ii++)
{
string valueName = ReadNodeProperty(faceNodes[ii], DAE_REF_ATTRIBUTE);
if (valueName.empty())
{
return status.Fail(FS("<init_cube>'s face reference is empty in surface parameter: ") + TO_FSTRING(GetReference()), refNode->line);
}
names.push_back(valueName);
FCDImage* image = GetDocument()->FindImage(valueName);
if (image == NULL)
{
return status.Fail(FS("Unable to find image source for surface parameter: ") + TO_FSTRING(GetReference()), refNode->line);
}
images.push_back(image);
}
}
}
}
}
//Check if it's initialized AS VOLUME
if(!initialized)
{
valueNode = FindChildByType(surfaceNode, DAE_INITVOLUME_ELEMENT);
if(valueNode)
{
initialized = true;
initMethod = FCDEffectParameterSurfaceInitFactory::Create(FCDEffectParameterSurfaceInitFactory::VOLUME);
FCDEffectParameterSurfaceInitVolume* ptrInit = (FCDEffectParameterSurfaceInitVolume*) initMethod;
//Check if it's an ALL reference
xmlNode* refNode = FindChildByType(valueNode, DAE_ALL_ELEMENT);
if(refNode)
{
ptrInit->volumeType = FCDEffectParameterSurfaceInitVolume::ALL;
string name = ReadNodeProperty(refNode, DAE_REF_ATTRIBUTE);
if (name.empty())
{
return status.Fail(FS("<init_cube>'s all reference is empty in surface parameter: ") + TO_FSTRING(GetReference()), refNode->line);
}
names.push_back(name);
FCDImage* image = GetDocument()->FindImage(name);
if (image == NULL)
{
return status.Fail(FS("Unable to find image source for surface parameter: ") + TO_FSTRING(GetReference()), refNode->line);
}
images.push_back(image);
}
//Check if it's a PRIMARY reference
if(!refNode)
{
refNode = FindChildByType(valueNode, DAE_PRIMARY_ELEMENT);
if(refNode)
{
ptrInit->volumeType = FCDEffectParameterSurfaceInitVolume::PRIMARY;
string name = ReadNodeProperty(refNode, DAE_REF_ATTRIBUTE);
if (name.empty())
{
return status.Fail(FS("<init_cube>'s primary reference is empty in surface parameter: ") + TO_FSTRING(GetReference()), valueNode->line);
}
names.push_back(name);
FCDImage* image = GetDocument()->FindImage(name);
if (image == NULL)
{
return status.Fail(FS("Unable to find image source for surface parameter: ") + TO_FSTRING(GetReference()), valueNode->line);
}
images.push_back(image);
}
}
}
}
//Check if it's initialized as PLANAR
if(!initialized)
{
valueNode = FindChildByType(surfaceNode, DAE_INITPLANAR_ELEMENT);
if(valueNode)
{
initialized = true;
initMethod = FCDEffectParameterSurfaceInitFactory::Create(FCDEffectParameterSurfaceInitFactory::PLANAR);
//Check if it's an ALL reference
xmlNode* refNode = FindChildByType(valueNode, DAE_ALL_ELEMENT);
if(refNode)
{
string name = ReadNodeProperty(refNode, DAE_REF_ATTRIBUTE);
if (name.empty())
{
return status.Fail(FS("<init_planar>'s all reference is empty in surface parameter: ") + TO_FSTRING(GetReference()), refNode->line);
}
names.push_back(name);
FCDImage* image = GetDocument()->FindImage(name);
if (image == NULL)
{
return status.Fail(FS("Unable to find image source for surface parameter: ") + TO_FSTRING(GetReference()), refNode->line);
}
images.push_back(image);
}
}
}
// It is acceptable for a surface not to have an initialization option
//but we should flag a warning
if(!initialized)
{
DebugOut("Warning: surface %s not initialized", GetReference().c_str());
}
xmlNode* sizeNode = FindChildByType(parameterNode, DAE_SIZE_ELEMENT);
size = FUStringConversion::ToPoint(ReadNodeContentDirect(sizeNode));
xmlNode* viewportRatioNode = FindChildByType(parameterNode, DAE_VIEWPORT_RATIO);
viewportRatio = FUStringConversion::ToFloat(ReadNodeContentDirect(viewportRatioNode));
xmlNode* mipLevelsNode = FindChildByType(parameterNode, DAE_MIP_LEVELS);
mipLevelCount = (uint16) FUStringConversion::ToInt32(ReadNodeContentDirect(mipLevelsNode));
xmlNode* mipmapGenerateNode = FindChildByType(parameterNode, DAE_MIPMAP_GENERATE);
generateMipmaps = FUStringConversion::ToBoolean(ReadNodeContentDirect(mipmapGenerateNode));
return status;
}
xmlNode* FCDEffectParameterSurface::WriteToXML(xmlNode* parentNode) const
{
xmlNode* parameterNode = FCDEffectParameter::WriteToXML(parentNode);
xmlNode* surfaceNode = AddChild(parameterNode, DAE_FXCMN_SURFACE_ELEMENT);
if (!images.empty() && initMethod != NULL)
{
switch (initMethod->GetInitType())
{
case FCDEffectParameterSurfaceInitFactory::FROM:
{
//Since 1.4.1, there are two possibilities here.
//Possibility 1
//<init_from> image1 image2...imageN </init_from>
//Possibility 2
//<init_from mip=... face=... slice=...> image1 </init_from>
//<init_from mip=... face=... slice=...> image2 </init_from>
FCDEffectParameterSurfaceInitFrom* in = (FCDEffectParameterSurfaceInitFrom*)initMethod;
size_t size = images.size(); //images.size() should always be equal to names.size()
if( size == in->face.size() || size == in->mip.size() || size == in->slice.size())
{
//This is possibility 2
for(uint32 i=0; i<size; i++)
{
xmlNode* childNode = AddChild(surfaceNode, DAE_INITFROM_ELEMENT, images[i]->GetDaeId());
AddAttribute(childNode, DAE_MIP_ATTRIBUTE, in->mip[i]);
AddAttribute(childNode, DAE_SLICE_ATTRIBUTE, in->slice[i]);
AddAttribute(childNode, DAE_FACE_ATTRIBUTE, in->face[i]);
}
}
else
{
//This is possibility 1
globalSBuilder.reserve(size * 18); // Pulled out of a hat
StringList::const_iterator itV = names.begin();
globalSBuilder.set(*itV);
for (++itV; itV != names.end(); ++itV)
{
globalSBuilder.append(' ');
globalSBuilder.append(*itV);
}
xmlNode* childNode = AddChild(surfaceNode, DAE_INITFROM_ELEMENT);
AddContent(childNode, globalSBuilder.ToString());
}
break;
}
case FCDEffectParameterSurfaceInitFactory::AS_NULL:
{
AddChild(surfaceNode, DAE_INITASNULL_ELEMENT);
break;
}
case FCDEffectParameterSurfaceInitFactory::AS_TARGET:
{
AddChild(surfaceNode, DAE_INITASTARGET_ELEMENT);
break;
}
case FCDEffectParameterSurfaceInitFactory::VOLUME:
{
FCDEffectParameterSurfaceInitVolume* in = (FCDEffectParameterSurfaceInitVolume*)initMethod;
xmlNode* childNode = AddChild(surfaceNode, DAE_INITVOLUME_ELEMENT);
if(in->volumeType == FCDEffectParameterSurfaceInitVolume::ALL)
{
xmlNode* typeNode = AddChild(childNode, DAE_ALL_ELEMENT);
AddAttribute(typeNode, DAE_REF_ATTRIBUTE, names[0]);
}
else if(in->volumeType == FCDEffectParameterSurfaceInitVolume::PRIMARY)
{
xmlNode* typeNode = AddChild(childNode, DAE_PRIMARY_ELEMENT);
AddAttribute(typeNode, DAE_REF_ATTRIBUTE, names[0]);
}
break;
}
case FCDEffectParameterSurfaceInitFactory::CUBE:
{
FCDEffectParameterSurfaceInitCube* in = (FCDEffectParameterSurfaceInitCube*)initMethod;
xmlNode* childNode = AddChild(surfaceNode, DAE_INITCUBE_ELEMENT);
if(in->cubeType == FCDEffectParameterSurfaceInitCube::ALL)
{
xmlNode* typeNode = AddChild(childNode, DAE_ALL_ELEMENT);
AddAttribute(typeNode, DAE_REF_ATTRIBUTE, names[0]);
}
else if(in->cubeType == FCDEffectParameterSurfaceInitCube::PRIMARY)
{
xmlNode* typeNode = AddChild(childNode, DAE_PRIMARY_ELEMENT);
AddChild(typeNode, DAE_ORDER_ELEMENT); //FIXME: complete when the spec gets more info.
AddAttribute(typeNode, DAE_REF_ATTRIBUTE, names[0]);
}
if(in->cubeType == FCDEffectParameterSurfaceInitCube::FACE)
{
xmlNode* childNode = AddChild(surfaceNode, DAE_FACE_ELEMENT);
AddAttribute(childNode, DAE_REF_ATTRIBUTE, names[0]);
}
break;
}
case FCDEffectParameterSurfaceInitFactory::PLANAR:
{
xmlNode* childNode = AddChild(surfaceNode, DAE_INITPLANAR_ELEMENT);
xmlNode* typeNode = AddChild(childNode, DAE_ALL_ELEMENT);
AddAttribute(typeNode, DAE_REF_ATTRIBUTE, names[0]);
break;
}
default:
break;
}
}
return parameterNode;
}
void FCDEffectParameterSurfaceInit::Clone(FCDEffectParameterSurfaceInit* UNUSED(clone))
{
//no member variables to copy in this class, but leave this for future use.
}
FCDEffectParameterSurfaceInitCube::FCDEffectParameterSurfaceInitCube()
{
cubeType = ALL;
}
FCDEffectParameterSurfaceInit* FCDEffectParameterSurfaceInitCube::Clone()
{
FCDEffectParameterSurfaceInitCube* clone = new FCDEffectParameterSurfaceInitCube();
FCDEffectParameterSurfaceInit::Clone(clone);
clone->cubeType = cubeType;
return clone;
}
FCDEffectParameterSurfaceInit* FCDEffectParameterSurfaceInitFrom::Clone()
{
FCDEffectParameterSurfaceInitFrom* clone = new FCDEffectParameterSurfaceInitFrom();
FCDEffectParameterSurfaceInit::Clone(clone);
clone->face = face;
clone->mip = mip;
clone->slice = slice;
return clone;
}
FCDEffectParameterSurfaceInitVolume::FCDEffectParameterSurfaceInitVolume()
{
volumeType = ALL;
}
FCDEffectParameterSurfaceInit* FCDEffectParameterSurfaceInitVolume::Clone()
{
FCDEffectParameterSurfaceInitVolume* clone = new FCDEffectParameterSurfaceInitVolume();
FCDEffectParameterSurfaceInit::Clone(clone);
clone->volumeType = volumeType;
return clone;
}
FCDEffectParameterSurfaceInit* FCDEffectParameterSurfaceInitAsNull::Clone()
{
FCDEffectParameterSurfaceInitAsNull* clone = new FCDEffectParameterSurfaceInitAsNull();
FCDEffectParameterSurfaceInit::Clone(clone);
return clone;
}
FCDEffectParameterSurfaceInit* FCDEffectParameterSurfaceInitAsTarget::Clone()
{
FCDEffectParameterSurfaceInitAsTarget* clone = new FCDEffectParameterSurfaceInitAsTarget();
FCDEffectParameterSurfaceInit::Clone(clone);
return clone;
}
FCDEffectParameterSurfaceInit* FCDEffectParameterSurfaceInitPlanar::Clone()
{
FCDEffectParameterSurfaceInitPlanar* clone = new FCDEffectParameterSurfaceInitPlanar();
FCDEffectParameterSurfaceInit::Clone(clone);
return clone;
}
FCDEffectParameterSurfaceInit* FCDEffectParameterSurfaceInitFactory::Create(InitType type)
{
FCDEffectParameterSurfaceInit* parameter = NULL;
switch (type)
{
case FCDEffectParameterSurfaceInitFactory::AS_NULL: parameter = new FCDEffectParameterSurfaceInitAsNull(); break;
case FCDEffectParameterSurfaceInitFactory::AS_TARGET: parameter = new FCDEffectParameterSurfaceInitAsTarget(); break;
case FCDEffectParameterSurfaceInitFactory::CUBE: parameter = new FCDEffectParameterSurfaceInitCube(); break;
case FCDEffectParameterSurfaceInitFactory::FROM: parameter = new FCDEffectParameterSurfaceInitFrom(); break;
case FCDEffectParameterSurfaceInitFactory::PLANAR: parameter = new FCDEffectParameterSurfaceInitPlanar(); break;
case FCDEffectParameterSurfaceInitFactory::VOLUME: parameter = new FCDEffectParameterSurfaceInitVolume(); break;
default: break;
}
return parameter;
}

View File

@@ -0,0 +1,435 @@
/*
Copyright (C) 2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
/**
@file FCDEffectParameterSurface.h
This file contains the FCDEffectParameterSurface class,
the FCDEffectParameterSurfaceInit interface and its derivate classes.
*/
#ifndef _FCD_EFFECT_PARAMETER_SURFACE_H_
#define _FCD_EFFECT_PARAMETER_SURFACE_H_
#include "FCDocument/FCDEffectParameter.h"
class FCDEffectParameterSurfaceInit;
/** A dynamically-sized array of COLLADA images */
typedef std::vector<FCDImage*> FCDImageList;
/**
A COLLADA surface parameter.
This parameters hold the texture loading information. The texture
placement information should be held by the sampler parameter.
@see FCDEffectParameterSampler
@ingroup FCDEffect
*/
class FCOLLADA_EXPORT FCDEffectParameterSurface : public FCDEffectParameter
{
private:
StringList names;
FCDImageList images;
FCDEffectParameterSurfaceInit* initMethod;
FMVector3 size;
float viewportRatio;
uint16 mipLevelCount;
bool generateMipmaps;
public:
/** Constructor: do not use directly.
Instead, use the FCDEffectParameterList::AddParameter function.
@param document The COLLADA document that owns the effect parameter. */
FCDEffectParameterSurface(FCDocument* document);
/** Destructor: do not use directly.
Instead, use the FCDEffectParameterList::ReleaseParameter function.
When released, the effect parameter list will also release all
its parameters, if it owns them. */
virtual ~FCDEffectParameterSurface();
/** Retrieves the type of effect parameter class.
@return The parameter class type: SURFACE. */
virtual Type GetType() const { return SURFACE; }
/** Retrieves the initialization method for the surface parameter.
The initialization method is a powerful method of describing how
to build complex textures, such as cube maps, from one or
multiple image files.
@return The surface initialization method. This pointer will be NULL,
if no initialization method is provided. */
FCDEffectParameterSurfaceInit* GetInitMethod() { return initMethod; }
const FCDEffectParameterSurfaceInit* GetInitMethod() const { return initMethod; } /**< See above. */
/** Sets the initialization method for the surface parameter.
The initialization method is a powerful method of describing how
to build complex textures, such as cube maps, from one or
multiple image files.
@param method The new initialization method.
The old initialization method will be released.
You should create a new initialization method
for each surface parameter. */
void SetInitMethod(FCDEffectParameterSurfaceInit* method);
/** Retrieves the number of COLLADA images that make up this surface.
There should never be more than six images to build a surface.
In the large majority of cases, expect one image.
@return The number of images. */
size_t GetImageCount() const { return images.size(); }
/** Retrieves the list of images that make up this surface.
There should never be more than six images to build a surface.
In the large majority of cases, expect one image.
@return The list of images. */
FCDImageList& GetImages() { return images; }
const FCDImageList& GetImages() const { return images; } /**< See above. */
/** Retrieves a specific image.
@param index The index of the image.
@return The image. This pointer will be NULL if the index is out-of-bounds. */
FCDImage* GetImage(size_t index = 0) { return index < images.size() ? images.at(index) : NULL; }
const FCDImage* GetImage(size_t index = 0) const { return index < images.size() ? images.at(index) : NULL; } /**< See above. */
/** Retrieves the index that matches the given image.
@param image The image to match.
@return The index within the list for this image.
This index may be -1 if no match was found. */
size_t FindImage(const FCDImage* image) const;
/** Adds an image to the list.
The initialization method indexes the images from this list.
This function will verify that this image does not already exist within the list,
so use the returned index.
@param image The new image.
@return The index of the image within the list. */
size_t AddImage(FCDImage* image);
/** Removes an image from the list.
The initialization method indexes the images from this list.
This function will shift all the indexes in the initialization method
so that they continue matching the correct image.
@param image The image to remove. Its memory is not released. */
void RemoveImage(FCDImage* image);
/** Retrieves the wanted dimensions of the surface.
This parameter is optional and may contain all zeroes to indicate
that you should read the surface dimensions from the image file(s).
@return The wanted dimensions. */
const FMVector3& GetSize() const { return size; }
/** Sets the wanted dimensions of the surface.
This parameter is optional and can contain all zeroes to indicate
that you should read the surface dimensions from the image file(s).
@param dimensions The wanted dimensions. */
void SetSize(const FMVector3& dimensions) { size = dimensions; }
/** Retrieves the viewport ratio to use when the surface is a render target.
@return The viewport ratio. */
float GetViewportRatio() const { return viewportRatio; }
/** Sets the viewport ratio to use when the surface is a render target.
@param ratio The viewport ratio. */
void SetViewportRatio(float ratio) { viewportRatio = ratio; }
/** Retrieves the wanted number of mip-levels.
This parameter is optional and may be zero to indicate that you should
retrieve the mip-levels from the image file(s) or generate a full
mip-chain, depending on the mip-map generate flag.
@see GetMipMapGenerate
@return The wanted number of mip-levels. */
uint16 GetMipLevelCount() const { return mipLevelCount; }
/** Sets the wanted number of mip-levels.
This parameter is optional and can be zero to indicate that you should
retrieve the mip-levels from the image file(s) or generate a full
mip-chain, depending on the mip-map generate flag.
@param levelCount The wanted number of mip-levels. */
void SetMipLevelCount(uint16 levelCount) { mipLevelCount = levelCount; }
/** Retrieves whether to generate the mip-map levels on load.
The alternative is to load the mip-map levels from the image files.
@return Whether to generate the mip-map levels on load. */
bool IsGenerateMipMaps() const { return generateMipmaps; }
/** Sets whether to generate the mip-map levels of load.
The alternative is to load the mip-map levels from the image files.
@param _generateMipmaps Whether to generate the mip-map levels on load. */
void SetGenerateMipMaps(bool _generateMipmaps) { generateMipmaps = _generateMipmaps; }
/** Retrieves a specific sub-id.
@todo I'm not too sure of the implications of the names,
at this level of abstraction: once I'm clear why they exists, add the
necessary interface to access/pull/push items from/to the list.
@param index The sub-id index.
@return The sub-id. This pointer will be NULL if the index is out-of-bounds. */
const char* GetName(size_t index = 0) const { return (index < names.size()) ? names[index].c_str() : NULL; }
/** Creates a full copy of the effect parameter.
@todo The cloning does not clone the initialization method correctly.
@return The cloned effect parameter. You will need to delete this pointer. */
virtual FCDEffectParameter* Clone();
/** [INTERNAL] Overwrites the target parameter with this parameter.
This function is used during the flattening of materials.
@param target The target parameter to overwrite. */
virtual void Overwrite(FCDEffectParameter* target);
/** [INTERNAL] Reads in the effect parameter from a given COLLADA XML tree node.
@param parameterNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the parameter.*/
virtual FUStatus LoadFromXML(xmlNode* parameterNode);
/** [INTERNAL] Writes out the effect parameter to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the parameter.
@return The created element XML tree node. */
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
/**
[INTERNAL] The factory for COLLADA effect parameter surface initialization.
@ingroup FCDEffect
*/
class FCOLLADA_EXPORT FCDEffectParameterSurfaceInitFactory
{
private:
// Never instantiate: this is a static class
FCDEffectParameterSurfaceInitFactory() {}
public:
/** The supported initialization types. */
enum InitType
{
FROM, /**< Loads a surface from one simple image file. @see FCDEffectParameterSurfaceInitFrom */
AS_NULL, /**< No initialization. This surface may be initialized by some future effect parameter override. */
AS_TARGET, /**< Initializes an engine-specific render target for offscreen rendering. In this case, the dimensions should be provided by the surface effect parameter. */
CUBE, /**< Loads a cube-map from one complex image file or six simple image files. @see FCDEffectParameterSurfaceInitCube */
VOLUME, /**< Loads a 3D images for one image file. @see FCDEffectParameterSurfaceInitVolume */
PLANAR /**< Loads a surface from one simple image file. */
};
/** [INTERNAL] Creates a new effect surface initialization parameter, given a type.
@param type The type of initialization parameter to create.*/
static FCDEffectParameterSurfaceInit* Create(InitType type);
};
/**
A surface initialization method.
In COLLADA 1.4.1, this information was added to support complex surface types.
There are six types of initialization methods, described in the InitType enumerated type.
Expect the FROM initialization type in the large majority of cases.
@ingroup FCDEffect
*/
class FCOLLADA_EXPORT FCDEffectParameterSurfaceInit
{
public:
/** Constructor: builds a new surface initialization method. */
FCDEffectParameterSurfaceInit() {}
/** Destructor. */
virtual ~FCDEffectParameterSurfaceInit() {}
/** Retrieves the initialization type. You cannot modify this value.
To change the initialization type of a surface parameter, create a new
surface initialization structure of the correct type.
@return The initialization type. */
virtual FCDEffectParameterSurfaceInitFactory::InitType GetInitType() const = 0;
/** Copies all member variables into clone.
@param clone a valid pointer to a FCDEffectParameterSurfaceInit object*/
void Clone(FCDEffectParameterSurfaceInit* clone);
/** Creates a full copy of the surface initialization parameter.
@return The surface initialization parameter. You will need to delete this pointer. */
virtual FCDEffectParameterSurfaceInit* Clone() = 0;
};
/**
A cube-map surface initialization method.
*/
class FCOLLADA_EXPORT FCDEffectParameterSurfaceInitCube : public FCDEffectParameterSurfaceInit
{
public:
/** The types of cube-map initializations. */
enum CubeType
{
ALL, /** Load all the mip-levels of all the cube-map faces from one image file. */
PRIMARY, /** Load the first mip-level of all the cube-map faces from one image file. */
FACE /** Load all the cube-map faces from separate image files. */
};
public:
/** Constructor: builds a new cube-map initialization method. */
FCDEffectParameterSurfaceInitCube();
/** Destructor. */
virtual ~FCDEffectParameterSurfaceInitCube() {}
/** Retrieves the initialization type. You cannot modify this value.
To change the initialization type of a surface parameter, create a new
surface initialization structure of the correct type.
@return The initialization type. */
virtual FCDEffectParameterSurfaceInitFactory::InitType GetInitType() const {return FCDEffectParameterSurfaceInitFactory::CUBE;}
/** Creates a full copy of the surface initialization parameter.
@return The surface initialization parameter. You will need to delete this pointer. */
virtual FCDEffectParameterSurfaceInit* Clone();
/** The type of cube-map initialization. */
CubeType cubeType;
/** The list of image indices.
The images are contained within the surface effect parameter.
This is used only for the FACE cube-map initialization type and indicates
how to match the faces of faces of the cube-map with the images in the surface effect parameter. */
UInt16List order;
};
/**
A volumetric surface initialization method.
*/
class FCOLLADA_EXPORT FCDEffectParameterSurfaceInitVolume : public FCDEffectParameterSurfaceInit
{
public:
/** The types of volumetric surfaces initialization. */
enum VolumeType
{
ALL, /** Load all the mip-levels from the image file. */
PRIMARY /** Load the first mip-level from the image file. */
};
public:
/** Constructor: builds a new volumetric surface initialization method. */
FCDEffectParameterSurfaceInitVolume();
/** Destructor. */
virtual ~FCDEffectParameterSurfaceInitVolume() {}
/** Retrieves the initialization type. You cannot modify this value.
To change the initialization type of a surface parameter, create a new
surface initialization structure of the correct type.
@return The initialization type. */
virtual FCDEffectParameterSurfaceInitFactory::InitType GetInitType() const {return FCDEffectParameterSurfaceInitFactory::VOLUME;}
/** Creates a full copy of the surface initialization parameter.
@return The surface initialization parameter. You will need to delete this pointer. */
virtual FCDEffectParameterSurfaceInit* Clone();
/** The type of volumetric initialization. */
VolumeType volumeType;
};
/**
A simple file surface initialization method.
This is the method used for backward-compatibility.
*/
class FCOLLADA_EXPORT FCDEffectParameterSurfaceInitFrom : public FCDEffectParameterSurfaceInit
{
public:
/** Constructor: builds a new file surface initialization method. */
FCDEffectParameterSurfaceInitFrom() {}
/** Destructor. */
virtual ~FCDEffectParameterSurfaceInitFrom() {}
/** Retrieves the initialization type. You cannot modify this value.
To change the initialization type of a surface parameter, create a new
surface initialization structure of the correct type.
@return The initialization type. */
virtual FCDEffectParameterSurfaceInitFactory::InitType GetInitType() const {return FCDEffectParameterSurfaceInitFactory::FROM;}
/** Creates a full copy of the surface initialization parameter.
@return The surface initialization parameter. You will need to delete this pointer. */
virtual FCDEffectParameterSurfaceInit* Clone();
/** The list of mip levels. */
StringList mip;
/** The list of matching slices. */
StringList slice;
/** The list of matching faces. */
StringList face;
};
/**
This method allows to initialize the surface at a later point.
*/
class FCOLLADA_EXPORT FCDEffectParameterSurfaceInitAsNull : public FCDEffectParameterSurfaceInit
{
public:
/** Constructor: builds a new file surface initialization method. */
FCDEffectParameterSurfaceInitAsNull() {}
/** Destructor. */
virtual ~FCDEffectParameterSurfaceInitAsNull() {}
/** Retrieves the initialization type. You cannot modify this value.
To change the initialization type of a surface parameter, create a new
surface initialization structure of the correct type.
@return The initialization type. */
virtual FCDEffectParameterSurfaceInitFactory::InitType GetInitType() const {return FCDEffectParameterSurfaceInitFactory::AS_NULL;}
/** Creates a full copy of the surface initialization parameter.
@return The surface initialization parameter. You will need to delete this pointer. */
virtual FCDEffectParameterSurfaceInit* Clone();
};
/**
This method allows to initialize the surface as a rendering target.
*/
class FCOLLADA_EXPORT FCDEffectParameterSurfaceInitAsTarget : public FCDEffectParameterSurfaceInit
{
public:
/** Constructor: builds a new file surface initialization method. */
FCDEffectParameterSurfaceInitAsTarget() {};
/** Destructor. */
virtual ~FCDEffectParameterSurfaceInitAsTarget() {}
/** Retrieves the initialization type. You cannot modify this value.
To change the initialization type of a surface parameter, create a new
surface initialization structure of the correct type.
@return The initialization type. */
virtual FCDEffectParameterSurfaceInitFactory::InitType GetInitType() const {return FCDEffectParameterSurfaceInitFactory::AS_TARGET;}
/** Creates a full copy of the surface initialization parameter.
@return The surface initialization parameter. You will need to delete this pointer. */
virtual FCDEffectParameterSurfaceInit* Clone();
};
/**
This method allows to initialize the surface as planar.
*/
class FCOLLADA_EXPORT FCDEffectParameterSurfaceInitPlanar : public FCDEffectParameterSurfaceInit
{
public:
/** Constructor: builds a new file surface initialization method. */
FCDEffectParameterSurfaceInitPlanar() {};
/** Destructor. */
virtual ~FCDEffectParameterSurfaceInitPlanar() {}
/** Retrieves the initialization type. You cannot modify this value.
To change the initialization type of a surface parameter, create a new
surface initialization structure of the correct type.
@return The initialization type. */
virtual FCDEffectParameterSurfaceInitFactory::InitType GetInitType() const {return FCDEffectParameterSurfaceInitFactory::PLANAR;}
/** Creates a full copy of the surface initialization parameter.
@return The surface initialization parameter. You will need to delete this pointer. */
virtual FCDEffectParameterSurfaceInit* Clone();
};
#endif // _FCD_EFFECT_PARAMETER_SURFACE_H_

View File

@@ -0,0 +1,194 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDEffectTechnique.h"
#include "FCDocument/FCDocument.h"
#include "FCDocument/FCDEffectPass.h"
#include "FCDocument/FCDEffectPassShader.h"
#include "FCDocument/FCDEffectParameter.h"
#include "FCDocument/FCDEffectParameterList.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDEffectPass::FCDEffectPass(FCDocument* document, FCDEffectTechnique *_parent) : FCDObject(document, "FCDEffectPass")
{
parent = _parent;
}
FCDEffectPass::~FCDEffectPass()
{
CLEAR_POINTER_VECTOR(shaders);
meshdata.clear();
parent = NULL;
}
// Adds a new shader to the pass.
FCDEffectPassShader* FCDEffectPass::AddShader()
{
FCDEffectPassShader* shader = new FCDEffectPassShader(GetDocument(), this);
shaders.push_back(shader);
return shader;
}
// Releases a shader contained within the pass.
void FCDEffectPass::ReleaseShader(FCDEffectPassShader* shader)
{
FCDEffectPassShaderList::iterator it = std::find(shaders.begin(), shaders.end(), shader);
if (it != shaders.end())
{
delete *it;
shaders.push_back(shader);
}
}
// Adds a new vertex shader to the pass.
// If a vertex shader already exists within the pass, it will be released.
FCDEffectPassShader* FCDEffectPass::AddVertexShader()
{
FCDEffectPassShader* vertexShader;
for (vertexShader = GetVertexShader(); vertexShader != NULL; vertexShader = GetVertexShader())
{
ReleaseShader(vertexShader);
}
vertexShader = AddShader();
vertexShader->AffectsVertices();
return vertexShader;
}
// Adds a new fragment shader to the pass.
// If a fragment shader already exists within the pass, it will be released.
FCDEffectPassShader* FCDEffectPass::AddFragmentShader()
{
FCDEffectPassShader* fragmentShader;
for (fragmentShader = GetFragmentShader(); fragmentShader != NULL; fragmentShader = GetFragmentShader())
{
ReleaseShader(fragmentShader);
}
fragmentShader = AddShader();
fragmentShader->AffectsFragments();
return fragmentShader;
}
FCDEffectPass* FCDEffectPass::Clone(FCDEffectTechnique* newParent) const
{
FCDEffectPass* clone = new FCDEffectPass(GetDocument(), newParent);
clone->name = name;
clone->meshdata = meshdata;
// Clone the shaderss
clone->shaders.reserve(shaders.size());
for (FCDEffectPassShaderList::const_iterator itS = shaders.begin(); itS != shaders.end(); ++itS)
{
clone->shaders.push_back((*itS)->Clone(clone));
}
return clone;
}
const string& FCDEffectPass::GetDaeId() const
{
return parent->GetDaeId();
}
// Retrieve the type-specific shaders
FCDEffectPassShader* FCDEffectPass::GetVertexShader()
{
for (FCDEffectPassShaderList::iterator itS = shaders.begin(); itS != shaders.end(); ++itS)
{
if ((*itS)->IsVertexShader()) return (*itS);
}
return NULL;
}
const FCDEffectPassShader* FCDEffectPass::GetVertexShader() const
{
for (FCDEffectPassShaderList::const_iterator itS = shaders.begin(); itS != shaders.end(); ++itS)
{
if ((*itS)->IsVertexShader()) return (*itS);
}
return NULL;
}
FCDEffectPassShader* FCDEffectPass::GetFragmentShader()
{
for (FCDEffectPassShaderList::iterator itS = shaders.begin(); itS != shaders.end(); ++itS)
{
if ((*itS)->IsFragmentShader()) return (*itS);
}
return NULL;
}
const FCDEffectPassShader* FCDEffectPass::GetFragmentShader() const
{
for (FCDEffectPassShaderList::const_iterator itS = shaders.begin(); itS != shaders.end(); ++itS)
{
if ((*itS)->IsFragmentShader()) return (*itS);
}
return NULL;
}
FUStatus FCDEffectPass::LoadFromXML(xmlNode* passNode, xmlNode* techniqueNode, xmlNode* profileNode)
{
FUStatus status;
if (!IsEquivalent(passNode->name, DAE_PASS_ELEMENT))
{
return status.Warning(FS("Pass contains unknown element."), passNode->line);
}
name = TO_FSTRING(ReadNodeProperty(passNode, DAE_SID_ATTRIBUTE));
// parse mesh data
const char* smdnames[10] = { "COLOR0", "COLOR1", "TEXCOORD0", "TEXCOORD1", "TEXCOORD2", "TEXCOORD3", "TEXCOORD4", "TEXCOORD5", "TEXCOORD6", "TEXCOORD7" };
for(uint32 i = 0; i < 10; ++i)
{
string smdname = smdnames[i];
string smdata = "";
xmlNode *mdataNode = FindChildByProperty(profileNode, "sid", smdname.c_str() );
if(mdataNode == NULL)
mdataNode = FindChildByProperty(techniqueNode, "sid", smdname.c_str() );
if( mdataNode != NULL )
{
xmlNode *stringNode = FindChildByType(mdataNode, "string" );
smdata = ReadNodeContentDirect(stringNode);
}
meshdata.push_back(smdata);
}
// Look for the <shader> elements
xmlNodeList shaderNodes;
FindChildrenByType(passNode, DAE_SHADER_ELEMENT, shaderNodes);
for (xmlNodeList::iterator itS = shaderNodes.begin(); itS != shaderNodes.end(); ++itS)
{
FCDEffectPassShader* shader = new FCDEffectPassShader(GetDocument(), this);
shaders.push_back(shader);
status.AppendStatus(shader->LoadFromXML(*itS));
}
return status;
}
// Write out the pass to the COLLADA xml node tree
xmlNode* FCDEffectPass::WriteToXML(xmlNode* parentNode) const
{
// Write out the <pass> element, with the shader's name
xmlNode* passNode = AddChild(parentNode, DAE_PASS_ELEMENT);
if (!name.empty())
{
const_cast<FCDEffectPass*>(this)->name = TO_FSTRING(AddNodeSid(passNode, TO_STRING(name).c_str()));
}
// Write out the shaders
for (FCDEffectPassShaderList::const_iterator itS = shaders.begin(); itS != shaders.end(); ++itS)
{
(*itS)->WriteToXML(passNode);
}
return passNode;
}

View File

@@ -0,0 +1,140 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
/**
@file FCDEffectPass.h
This file contains the FCDEffectPass class.
*/
#ifndef _FCD_EFFECT_PASS_H_
#define _FCD_EFFECT_PASS_H_
#include "FCDocument/FCDObject.h"
class FCDEffectTechnique;
class FCDEffectParameter;
class FCDEffectParameterList;
class FCDEffectPassShader;
typedef vector<FCDEffectPassShader*> FCDEffectPassShaderList; /**< A dynamically-sized array of shaders. */
typedef vector<string> MeshDataList; /**< @deprecated A dynamically-sized array of mesh bindings. These should be bound using the \<bind\> element, at the instantiation level! */
/**
A COLLADA effect pass.
The effect pass contains a list of effect shaders. While they
may be missing, it does not make sense for the effect pass to
contain more than two shaders: a vertex shader and a fragment/pixel shader.
For this reason, we provide the GetVertexShader and the GetFragmentShader
which we expect will be used for most applications, rather than looking
through the list of shader objects.
@ingroup FCDEffect
*/
class FCOLLADA_EXPORT FCDEffectPass : public FCDObject
{
private:
fstring name;
FCDEffectTechnique* parent;
FCDEffectPassShaderList shaders;
MeshDataList meshdata;
public:
/** Constructor: do not use directly.
Instead, use the FCDEffectTechnique::AddPass function.
@param document The COLLADA document that owns this effect pass.
@param _parent The effect technique that contains this effect pass. */
FCDEffectPass(FCDocument* document, FCDEffectTechnique *_parent);
/** Destructor: do not use directly.
Instead, use the FCDEffectTechnique::ReleasePass function. */
virtual ~FCDEffectPass();
/** Retrieves the effect techniques which contains this effect pass.
@return The parent technique. */
FCDEffectTechnique* GetParent() { return parent; }
const FCDEffectTechnique* GetParent() const { return parent; } /**< See above. */
/** Retrieves the COLLADA id of the parent effect.
This function is mostly useful as a shortcut for debugging and reporting.
@return The COLLADA id of the parent effect. */
const string& GetDaeId() const;
/** Retrieves the sub-id of the effect pass.
This sub-id is optional.
@return The sub-id. */
const fstring& GetPassName() const { return name; }
/** Sets the optional sub-id for the effect pass.
This sub-id is optional.
@param _name The sub-id. */
void SetPassName(const fstring& _name) { name = _name; }
/** @deprecated Retrieves the list of mesh data bindings.
This patches bad export data in ColladaMaya and will be removed soon.
@return The list of mesh data bindings. */
const MeshDataList& GetMeshData() const { return meshdata; }
/** Retrieves the number of shaders contained within the effect pass.
@return The number of shaders. */
size_t GetShaderCount() const { return shaders.size(); }
/** Retrieves a specific shader.
@param index The index of the shader.
@return The shader. This pointer will be NULL if the index is out-of-bounds. */
FCDEffectPassShader* GetShader(size_t index) { FUAssert(index < GetShaderCount(), return NULL); return shaders.at(index); }
const FCDEffectPassShader* GetShader(size_t index) const { FUAssert(index < GetShaderCount(), return NULL); return shaders.at(index); } /**< See above. */
/** Adds a new shader to the pass.
@return The new shader. */
FCDEffectPassShader* AddShader();
/** Releases a shader contained within the pass.
@param shader The shader to release. */
void ReleaseShader(FCDEffectPassShader* shader);
/** Retrieves the vertex shader for this effect pass.
@return The vertex shader. This pointer will be NULL if no
shader within the pass affects vertices. */
FCDEffectPassShader* GetVertexShader();
const FCDEffectPassShader* GetVertexShader() const; /**< See above. */
/** Retrieves the fragment shader for this effect pass.
@return The fragment shader. This pointer will be NULL if no
shader within the pass affects pixels/fragments. */
FCDEffectPassShader* GetFragmentShader();
const FCDEffectPassShader* GetFragmentShader() const; /**< See above. */
/** Adds a new vertex shader to the pass.
If a vertex shader already exists within the pass, it will be released.
@return The new vertex shader. */
FCDEffectPassShader* AddVertexShader();
/** Adds a new fragment shader to the pass.
If a fragment shader already exists within the pass, it will be released.
@return The new fragment shader. */
FCDEffectPassShader* AddFragmentShader();
/** [INTERNAL] Clones the full effect pass.
@param newParent The effect technique that will contain the cloned profile.
@return The cloned pass. This pointer will never be NULL. */
FCDEffectPass* Clone(FCDEffectTechnique* newParent) const;
/** [INTERNAL] Reads in the effect pass from a given COLLADA XML tree node.
@param passNode The COLLADA XML tree node.
@param techniqueNode X @deprecated bad interface : this dependency must be taken out[3]
@param profileNode X @deprecated bad interface : this dependency must be taken out[2]
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the effect pass.*/
FUStatus LoadFromXML(xmlNode* passNode, xmlNode* techniqueNode, xmlNode* profileNode);
/** [INTERNAL] Writes out the effect pass to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the effect pass.
@return The created element XML tree node. */
xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif

View File

@@ -0,0 +1,148 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDocument.h"
#include "FCDocument/FCDEffectCode.h"
#include "FCDocument/FCDEffectPass.h"
#include "FCDocument/FCDEffectPassShader.h"
#include "FCDocument/FCDEffectProfileFX.h"
#include "FCDocument/FCDEffectTechnique.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDEffectPassShader::FCDEffectPassShader(FCDocument* document, FCDEffectPass* _parent) : FCDObject(document, "FCDEffectPassShader")
{
parent = _parent;
isFragment = false;
code = NULL;
}
FCDEffectPassShader::~FCDEffectPassShader()
{
parent = NULL;
code = NULL;
}
// Adds a new binding to this shader.
FCDEffectPassBind* FCDEffectPassShader::AddBinding()
{
bindings.push_back(FCDEffectPassBind());
return &bindings.back();
}
// Releases a binding contained within this shader.
void FCDEffectPassShader::ReleaseBinding(FCDEffectPassBind* binding)
{
for (FCDEffectPassBindList::iterator it = bindings.begin(); it != bindings.end(); ++it)
{
if (&(*it) == binding)
{
bindings.erase(it);
break;
}
}
}
// Cloning
FCDEffectPassShader* FCDEffectPassShader::Clone(FCDEffectPass* newParent) const
{
FCDEffectPassShader* clone = new FCDEffectPassShader(GetDocument(), newParent);
clone->isFragment = isFragment;
clone->bindings = bindings;
clone->compilerTarget = compilerTarget;
clone->compilerOptions = compilerOptions;
clone->name = name;
// Look for the new code within the parent.
if (code != NULL)
{
clone->code = newParent->GetParent()->FindCode(code->GetSid());
if (clone->code == NULL) clone->code = newParent->GetParent()->GetParent()->FindCode(code->GetSid());
}
return clone;
}
// Read in the ColladaFX pass shader from the xml node tree
FUStatus FCDEffectPassShader::LoadFromXML(xmlNode* shaderNode)
{
FUStatus status;
if (!IsEquivalent(shaderNode->name, DAE_SHADER_ELEMENT))
{
return status.Warning(FS("Pass shader contains unknown element."), shaderNode->line);
}
// Read in the shader's name and stage
xmlNode* nameNode = FindChildByType(shaderNode, DAE_FXCMN_NAME_ELEMENT);
name = ReadNodeContentDirect(nameNode);
string codeSource = ReadNodeProperty(nameNode, DAE_SOURCE_ATTRIBUTE);
if (name.empty())
{
return status.Warning(FS("Unnamed effect pass shader found."), shaderNode->line);
}
string stage = ReadNodeStage(shaderNode);
isFragment = stage == DAE_FXCMN_FRAGMENT_SHADER;
if (!isFragment && stage != DAE_FXCMN_VERTEX_SHADER)
{
return status.Warning(FS("Unknown stage for effect pass shader: ") + TO_FSTRING(name), shaderNode->line);
}
// Look-up the code filename for this shader, if available
code = parent->GetParent()->FindCode(codeSource);
if (code == NULL) code = parent->GetParent()->GetParent()->FindCode(codeSource);
// Read in the compiler-related elements
xmlNode* compilerTargetNode = FindChildByType(shaderNode, DAE_FXCMN_COMPILERTARGET_ELEMENT);
compilerTarget = TO_FSTRING(ReadNodeContentDirect(compilerTargetNode));
xmlNode* compilerOptionsNode = FindChildByType(shaderNode, DAE_FXCMN_COMPILEROPTIONS_ELEMENT);
compilerOptions = TO_FSTRING(ReadNodeContentDirect(compilerOptionsNode));
// Read in the bind parameters
xmlNodeList bindNodes;
FindChildrenByType(shaderNode, DAE_FXCMN_BIND_ELEMENT, bindNodes);
for (xmlNodeList::iterator itB = bindNodes.begin(); itB != bindNodes.end(); ++itB)
{
xmlNode* paramNode = FindChildByType(*itB, DAE_PARAMETER_ELEMENT);
FCDEffectPassBind& bind = *(bindings.insert(bindings.end(), FCDEffectPassBind()));
bind.symbol = ReadNodeProperty((*itB), DAE_SYMBOL_ATTRIBUTE);
bind.reference = ReadNodeProperty(paramNode, DAE_REF_ATTRIBUTE);
}
return status;
}
// Write out the pass shader to the COLLADA xml node tree
xmlNode* FCDEffectPassShader::WriteToXML(xmlNode* parentNode) const
{
xmlNode* shaderNode = AddChild(parentNode, DAE_SHADER_ELEMENT);
// Write out the compiler information and the shader's name/stage
if (!compilerTarget.empty()) AddChild(shaderNode, DAE_FXCMN_COMPILERTARGET_ELEMENT, compilerTarget);
if (!compilerOptions.empty()) AddChild(shaderNode, DAE_FXCMN_COMPILEROPTIONS_ELEMENT, compilerOptions);
AddAttribute(shaderNode, DAE_STAGE_ATTRIBUTE, isFragment ? DAE_FXCMN_FRAGMENT_SHADER : DAE_FXCMN_VERTEX_SHADER);
if (!name.empty())
{
xmlNode* nameNode = AddChild(shaderNode, DAE_FXCMN_NAME_ELEMENT, name);
if (code != NULL) AddAttribute(nameNode, DAE_SOURCE_ATTRIBUTE, code->GetSid());
}
// Write out the bindings
for (FCDEffectPassBindList::const_iterator itB = bindings.begin(); itB != bindings.end(); ++itB)
{
const FCDEffectPassBind& b = (*itB);
if (!b.reference.empty() && !b.symbol.empty())
{
xmlNode* bindNode = AddChild(shaderNode, DAE_BIND_ELEMENT);
AddAttribute(bindNode, DAE_SYMBOL_ATTRIBUTE, b.symbol);
xmlNode* paramNode = AddChild(bindNode, DAE_PARAMETER_ELEMENT);
AddAttribute(paramNode, DAE_REF_ATTRIBUTE, b.reference);
}
}
return shaderNode;
}

View File

@@ -0,0 +1,169 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
/**
@file FCDEffectPassShader.h
This file contains the FCDEffectPassShader and the FCDEffectPassBind classes.
*/
#ifndef _FCD_EFFECT_PASS_SHADER_H_
#define _FCD_EFFECT_PASS_SHADER_H_
#include "FCDocument/FCDObject.h"
class FCDocument;
class FCDEffectCode;
/**
A COLLADA shader binding.
Binds an external symbol to a COLLADA effect parameter, by reference.
@ingroup FCDEffect
*/
class FCOLLADA_EXPORT FCDEffectPassBind
{
public:
string reference; /**< A COLLADA effect parameter reference. */
string symbol; /**< An external symbol, used within the shader code. */
};
typedef vector<FCDEffectPassBind> FCDEffectPassBindList; /**< A dynamically-sized array of shader bindings. */
/**
A COLLADA shader.
The shader abstraction level in ColladaFX is contained within the effect passes.
There are two types of shaders: vertex shaders and fragment/pixel shaders.
A COLLADA shader contains a list of bindings to attach the effect parameters to the
shader input parameters.
The shader object also contains the compiler information necessary to build
the shader: its code, the compiler target and the compiler options.
*/
class FCOLLADA_EXPORT FCDEffectPassShader : public FCDObject
{
private:
FCDEffectPass* parent;
FCDEffectPassBindList bindings;
fstring compilerTarget;
fstring compilerOptions;
string name;
bool isFragment;
FCDEffectCode* code;
public:
/** Constructor: do not use directly. Instead, use the FCDEffectPass::AddShader,
FCDEffectPass::AddVertexShader or FCDEffectPass::AddFragmentShader functions.
@param document The COLLADA document that owns this shader.
@param parent The effect pass that contains this shader. */
FCDEffectPassShader(FCDocument* document, FCDEffectPass* parent);
/** Destructor: do not use directly.
Instead, use the FCDEffectPass::ReleaseShader function. */
virtual ~FCDEffectPassShader();
/** Retrieves the effect pass that contains this shader.
@return The effect pass. */
inline FCDEffectPass* GetParent() { return parent; }
inline const FCDEffectPass* GetParent() const { return parent; } /**< See above. */
/** Sets this shader as affecting vertices.
This sets the stage of the shader to the vertex pipeline. */
inline void AffectsVertices() { isFragment = false; }
/** Sets this shader as affecting fragments/pixels.
This sets the stage of the shader to the fragment/pixel pipeline. */
inline void AffectsFragments() { isFragment = true; }
/** Retrieves whether this shader affects fragments/pixels.
@return Whether this shader affects fragments/pixels. */
inline bool IsFragmentShader() const { return isFragment; }
/** Retrieves whether this shader affects vertices.
@return Whether this shader affects vertices. */
inline bool IsVertexShader() const { return !isFragment; }
/** Retrieves the list of bindings for this shader.
@return The list of bindings. */
inline FCDEffectPassBindList& GetBindings() { return bindings; }
inline const FCDEffectPassBindList& GetBindings() const { return bindings; } /**< See above. */
/** Retrieves the number of bindings for this shader.
@return The number of bindings. */
inline size_t GetBindingCount() const { return bindings.size(); }
/** Retrieves a binding contained in this shader.
@param index The index of the binding.
@return The binding. This pointer will be NULL if the index is out-of-bounds. */
inline FCDEffectPassBind* GetBinding(size_t index) { FUAssert(index < GetBindingCount(), return NULL); return &bindings.at(index); }
inline const FCDEffectPassBind* GetBinding(size_t index) const { FUAssert(index < GetBindingCount(), return NULL); return &bindings.at(index); } /**< See above. */
/** Adds a new binding to this shader.
@return The new binding. */
FCDEffectPassBind* AddBinding();
/** Releases a binding contained within this shader.
@param binding The binding to release. */
void ReleaseBinding(FCDEffectPassBind* binding);
/** Retrieves the compiler target information.
The validity of this string depends on the type of the profile that contains this shader.
@return The compiler target information string. */
inline const fstring& GetCompilerTarget() const { return compilerTarget; }
/** Sets the compiler target information string.
The validity of this string depends on the type of the profile that contains this shader.
@param _compilerTarget The compiler target information. */
inline void SetCompilerTarget(const fstring& _compilerTarget) { compilerTarget = _compilerTarget; }
/** Retrieves the compiler option string.
The validity of this string depends on the type of the profile that contains this shader.
@return The compiler option string. */
inline const fstring& GetCompilerOptions() const { return compilerOptions; }
/** Sets the compiler option string.
The validity of this string depends on the type of the profile that contains this shader.
@param _compilerOptions The compiler option string. */
inline void SetCompilerOptions(const fstring& _compilerOptions) { compilerOptions = _compilerOptions; }
/** Retrieves the sub-id of the shader.
@return The sub-id. */
inline const string& GetName() const { return name; }
/** Sets the sub-id of the shader.
@param _name The sub-id. */
inline void SetName(const string& _name) { name = _name; }
/** Retrieves the code inclusion that contains the code for this shader.
@return The code inclusion. This pointer will be NULL if this shader
is not yet attached to any code. */
inline FCDEffectCode* GetCode() { return code; }
inline const FCDEffectCode* GetCode() const { return code; } /**< See above. */
/** Sets the code inclusion that contains the code for this shader.
@param _code The code inclusion. This pointer will be NULL to detach
a shader from its code. */
inline void SetCode(FCDEffectCode* _code) { code = _code; }
/** [INTERNAL] Clones this shader. You must manually delete the clone.
@param newParent The effect pass that will contain the clone.
@return The cloned shader. */
FCDEffectPassShader* Clone(FCDEffectPass* newParent) const;
/** [INTERNAL] Reads in the pass shader from a given COLLADA XML tree node.
@param shaderNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the shader.*/
FUStatus LoadFromXML(xmlNode* shaderNode);
/** [INTERNAL] Writes out the pass shader to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the effect profile.
@return The created element XML tree node. */
xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif // _FCD_EFFECT_PASS_SHADER_H_

View File

@@ -0,0 +1,24 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDocument.h"
#include "FCDocument/FCDEffect.h"
#include "FCDocument/FCDEffectProfile.h"
FCDEffectProfile::FCDEffectProfile(FCDocument* document, FCDEffect* _parent) : FCDObject(document, "FCDEffectProfile")
{
parent = _parent;
}
FCDEffectProfile::~FCDEffectProfile()
{
parent = NULL;
}
const string& FCDEffectProfile::GetDaeId() const
{
return parent->GetDaeId();
}

View File

@@ -0,0 +1,111 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
/**
@file FCDEffectProfile.h
This file contains the FCDEffectProfile abstract class.
*/
#ifndef _FCD_EFFECT_PROFILE_H_
#define _FCD_EFFECT_PROFILE_H_
#include "FUtils/FUDaeEnum.h"
#include "FCDocument/FCDObject.h"
class FCDocument;
class FCDEffect;
/**
The base for a COLLADA effect profile.
COLLADA has multiple effect profiles: CG, HLSL, GLSL, GLES and the COMMON profile.
For each profile, there is a class which implements this abstract class.
This abstract class solely holds the parent effect and allows access to the
profile type.
@see FCDEffectProfileFX FCDEffectStandard
@ingroup FCDEffect
*/
class FCOLLADA_EXPORT FCDEffectProfile : public FCDObject
{
private:
FCDEffect* parent;
public:
/** Constructor: do not use directly.
Instead, use the FCDEffect::AddProfile function.
@param document The COLLADA document that owns this effect profile.
@param parent The effect which contains this profile. */
FCDEffectProfile(FCDocument* document, FCDEffect* parent);
/** Destructor: do not use directly.
Instead, use the FCDEffect::ReleaseProfile function. */
virtual ~FCDEffectProfile();
/** Retrieves the profile type for this effect.
This function allows you to up-cast the pointer safely to a more specific
effect profile class.
@return The profile type. */
virtual FUDaeProfileType::Type GetType() const = 0;
/** Retrieves the parent effect.
This is the effect which contains this profile.
@return The parent effect. This pointer will never be NULL. */
FCDEffect* GetParent() { return parent; }
const FCDEffect* GetParent() const { return parent; } /**< See above. */
/** [INTERNAL] Retrieves the COLLADA id of the parent effect.
This function is useful when reporting errors and warnings.
@return The COLLADA id of the parent effect. */
const string& GetDaeId() const;
/** Retrieves an effect parameter. Looks for the effect parameter with the correct
semantic, in order to bind or override its value.
This function searches through the effect profile and the level of abstractions below.
@param semantic The effect parameter semantic to match.
@return The effect parameter that matches the semantic. This pointer will be NULL
if no effect parameter matches the given semantic. */
virtual FCDEffectParameter* FindParameterBySemantic(const string& semantic) = 0;
/** Retrieves a subset of the effect parameter list.
Look for effect parameters with the correct semantic.
This function searches through the effect profile and the level of abstractions below.
@param semantic The effect parameter semantic to match.
@param parameters The list of parameters to fill in. This list is not cleared. */
virtual void FindParametersBySemantic(const string& semantic, FCDEffectParameterList& parameters) = 0;
/** Retrieves a subset of the effect parameter list.
Look for effect parameters with the correct reference.
This function searches through the effect profile and the level of abstractions below.
@param reference The effect parameter reference to match. In the case of effect
parameter generators, the reference is replaced by the sub-id.
@param parameters The list of parameters to fill in. This list is not cleared. */
virtual void FindParametersByReference(const string& reference, FCDEffectParameterList& parameters) = 0;
/** [INTERNAL] Clones the profile effect and its parameters.
@param newParent The effect that will contain the cloned profile.
@return The cloned profile. This pointer will never be NULL. */
virtual FCDEffectProfile* Clone(FCDEffect* newParent) = 0;
/** [INTERNAL] Flattens this effect profile, pushing all the effect parameter overrides
into the effect parameter generators and moving all the parameters to the
effect technique level of abstraction. To flatten the material, use the
FCDMaterialInstance::FlattenMaterial function. */
virtual void Flatten() = 0;
/** [INTERNAL] Reads in the effect profile from a given COLLADA XML tree node.
@param profileNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the effect profile.*/
virtual FUStatus LoadFromXML(xmlNode* profileNode) = 0;
/** [INTERNAL] Writes out the effect profile to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the effect profile.
@return The created element XML tree node. */
virtual xmlNode* WriteToXML(xmlNode* parentNode) const = 0;
};
#endif // _FCD_EFFECT_PROFILE_H_

View File

@@ -0,0 +1,282 @@
/*
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/FCDEffect.h"
#include "FCDocument/FCDEffectCode.h"
#include "FCDocument/FCDEffectProfileFX.h"
#include "FCDocument/FCDEffectParameter.h"
#include "FCDocument/FCDEffectParameterList.h"
#include "FCDocument/FCDEffectParameterFactory.h"
#include "FCDocument/FCDEffectTechnique.h"
#include "FCDocument/FCDLibrary.h"
#include "FCDocument/FCDImage.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDEffectProfileFX::FCDEffectProfileFX(FCDocument* document, FCDEffect* _parent, FUDaeProfileType::Type _type) : FCDEffectProfile(document, _parent)
{
type = _type;
parameters = new FCDEffectParameterList(GetDocument(), true);
}
FCDEffectProfileFX::~FCDEffectProfileFX()
{
CLEAR_POINTER_VECTOR(techniques);
CLEAR_POINTER_VECTOR(codes);
SAFE_DELETE(parameters);
}
FCDEffectTechnique* FCDEffectProfileFX::AddTechnique()
{
FCDEffectTechnique* technique = new FCDEffectTechnique(GetDocument(), this);
techniques.push_back(technique);
return technique;
}
void FCDEffectProfileFX::ReleaseTechnique(FCDEffectTechnique* technique)
{
FCDEffectTechniqueList::iterator it = std::find(techniques.begin(), techniques.end(), technique);
if (it != techniques.end())
{
delete *it;
techniques.erase(it);
}
}
void FCDEffectProfileFX::AddParameter(FCDEffectParameter* parameter)
{
parameters->push_back(parameter);
}
// Look for the parameter with the given reference.
const FCDEffectParameter* FCDEffectProfileFX::FindParameter(const char* ref) const
{
const FCDEffectParameter* parameter = parameters->FindReference(ref);
for (FCDEffectTechniqueList::const_iterator it = techniques.begin(); it != techniques.end() && parameter == NULL; ++it)
{
parameter = (*it)->FindParameter(ref);
}
return parameter;
}
// Look for the effect parameter with the correct semantic, in order to bind/set its value
FCDEffectParameter* FCDEffectProfileFX::FindParameterBySemantic(const string& semantic)
{
FCDEffectParameter* parameter = parameters->FindSemantic(semantic);
for (FCDEffectTechniqueList::iterator it = techniques.begin(); it != techniques.end() && parameter == NULL; ++it)
{
parameter = (*it)->FindParameterBySemantic(semantic);
}
return parameter;
}
void FCDEffectProfileFX::FindParametersBySemantic(const string& semantic, FCDEffectParameterList& _parameters)
{
// Look in the local parameters
parameters->FindSemantic(semantic, _parameters);
// Look in the techniques
for( FCDEffectTechniqueList::iterator it = techniques.begin(); it != techniques.end(); ++it)
{
(*it)->FindParametersBySemantic(semantic, _parameters);
}
}
void FCDEffectProfileFX::FindParametersByReference(const string& reference, FCDEffectParameterList& _parameters)
{
// Look in the local parameters
parameters->FindReference(reference, _parameters);
// Look in the techniques
for( FCDEffectTechniqueList::iterator it = techniques.begin(); it != techniques.end(); ++it)
{
(*it)->FindParametersBySemantic(reference, _parameters);
}
}
FCDEffectCode* FCDEffectProfileFX::FindCode(const string& sid)
{
for (FCDEffectCodeList::iterator itC = codes.begin(); itC != codes.end(); ++itC)
{
if ((*itC)->GetSid() == sid) return (*itC);
}
return NULL;
}
const FCDEffectCode* FCDEffectProfileFX::FindCode(const string& sid) const
{
for (FCDEffectCodeList::const_iterator itC = codes.begin(); itC != codes.end(); ++itC)
{
if ((*itC)->GetSid() == sid) return (*itC);
}
return NULL;
}
// Adds a new code inclusion to this effect profile.
FCDEffectCode* FCDEffectProfileFX::AddCode()
{
FCDEffectCode* code = new FCDEffectCode(GetDocument());
codes.push_back(code);
return code;
}
// Releases a code inclusion contained within this effect profile.
void FCDEffectProfileFX::ReleaseCode(FCDEffectCode* code)
{
FCDEffectCodeList::iterator itC = std::find(codes.begin(), codes.end(), code);
if (itC != codes.end())
{
delete *itC;
codes.erase(itC);
}
}
// Clone the profile effect and its parameters
FCDEffectProfile* FCDEffectProfileFX::Clone(FCDEffect* newParent)
{
// Hack, because I'm time-bound right now.
FCDEffectProfileFX* clone = new FCDEffectProfileFX(GetDocument(), newParent, type);
SAFE_DELETE(clone->parameters);
clone->parameters = parameters->Clone();
clone->includeFilename = includeFilename;
// Clone the codes: needs to happen before the techniques are cloned.
clone->codes.reserve(codes.size());
for (FCDEffectCodeList::const_iterator itC = codes.begin(); itC != codes.end(); ++itC)
{
clone->codes.push_back((*itC)->Clone());
}
// Clone the techniques
clone->techniques.reserve(techniques.size());
for (FCDEffectTechniqueList::iterator itPs = techniques.begin(); itPs != techniques.end(); ++itPs)
{
clone->techniques.push_back((*itPs)->Clone(clone));
}
return clone;
}
// Flatten this effect profile: trickling down all the parameters to the techniques
void FCDEffectProfileFX::Flatten()
{
for (FCDEffectParameterList::iterator itP = parameters->begin(); itP != parameters->end(); ++itP)
{
FCDEffectParameterList generators;
if ((*itP)->IsModifier())
{
// Overwrite the generators
FindParametersByReference((*itP)->GetReference(), generators);
for (FCDEffectParameterList::iterator itQ = generators.begin(); itQ != generators.end(); ++itQ)
{
if ((*itP) != (*itQ))
{
(*itP)->Overwrite(*itQ);
}
}
}
else
{
// Add this parameter to the techniques
for (FCDEffectTechniqueList::iterator itT = techniques.begin(); itT != techniques.end(); ++itT)
{
(*itT)->AddParameter((*itP)->Clone());
}
}
}
CLEAR_POINTER_VECTOR(*parameters);
// Flatten the techniques
for (FCDEffectTechniqueList::iterator itT = techniques.begin(); itT != techniques.end(); ++itT)
{
(*itT)->Flatten();
}
}
// Read a <profile_X> node for a given COLLADA effect
// Note that this function should do most of the work, except for profile-specific states
FUStatus FCDEffectProfileFX::LoadFromXML(xmlNode* profileNode)
{
FUStatus status;
// Verify that we are given a valid XML input node.
const char* profileName = FUDaeProfileType::ToString(type);
if (!IsEquivalent(profileNode->name, profileName))
{
return status.Warning(FS("Invalid profile input node for effect") + TO_FSTRING(GetDaeId()), profileNode->line);
}
// Read in the target platform for this effect profile
platform = TO_FSTRING(ReadNodeProperty(profileNode, DAE_PLATFORM_ATTRIBUTE));
// Parse in the child elements: parameters and techniques
SAFE_DELETE(parameters);
parameters = new FCDEffectParameterList(GetDocument(), true);
for (xmlNode* child = profileNode->children; child != NULL; child = child->next)
{
if (child->type != XML_ELEMENT_NODE) continue;
if (IsEquivalent(child->name, DAE_TECHNIQUE_ELEMENT))
{
FCDEffectTechnique* technique = AddTechnique();
status.AppendStatus(technique->LoadFromXML(child, profileNode));
}
else if (IsEquivalent(child->name, DAE_FXCMN_NEWPARAM_ELEMENT))
{
AddParameter(FCDEffectParameterFactory::LoadFromXML(GetDocument(), child, &status));
}
else if (IsEquivalent(child->name, DAE_FXCMN_CODE_ELEMENT) || IsEquivalent(child->name, DAE_FXCMN_INCLUDE_ELEMENT))
{
FCDEffectCode* code = AddCode();
status.AppendStatus(code->LoadFromXML(child));
}
else if (IsEquivalent(child->name, DAE_IMAGE_ELEMENT))
{
// You can create images within the ColladaFX profile: tell the image library about it.
FCDImage* image = GetDocument()->GetImageLibrary()->AddEntity();
status.AppendStatus(image->LoadFromXML(child));
}
}
return status;
}
xmlNode* FCDEffectProfileFX::WriteToXML(xmlNode* parentNode) const
{
xmlNode* profileNode = AddChild(parentNode, FUDaeProfileType::ToString(type));
// Write out the profile properties/base elements
if (!platform.empty()) AddAttribute(profileNode, DAE_PLATFORM_ATTRIBUTE, platform);
if (!includeFilename.empty()) AddChild(profileNode, DAE_FXCMN_INCLUDE_ELEMENT, includeFilename);
// Write out the code/includes
for (FCDEffectCodeList::const_iterator itC = codes.begin(); itC != codes.end(); ++itC)
{
(*itC)->WriteToXML(profileNode);
}
// Write out the parameters
for (FCDEffectParameterList::const_iterator itP = parameters->begin(); itP != parameters->end(); ++itP)
{
(*itP)->WriteToXML(profileNode);
}
// Write out the techniques
for (FCDEffectTechniqueList::const_iterator itT = techniques.begin(); itT != techniques.end(); ++itT)
{
(*itT)->WriteToXML(profileNode);
}
return profileNode;
}

View File

@@ -0,0 +1,219 @@
/*
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
*/
/**
@file FCDEffectProfileFX.h
This file declares the FCDEffectProfileFX class.
*/
#ifndef _FCD_EFFECT_PROFILE_FX_H_
#define _FCD_EFFECT_PROFILE_FX_H_
#include "FUtils/FUDaeEnum.h"
#include "FCDocument/FCDEffectProfile.h"
class FCDocument;
class FCDEffect;
class FCDEffectCode;
class FCDEffectParameter;
class FCDEffectParameterSurface;
class FCDEffectTechnique;
class FCDEffectParameterList;
typedef vector<FCDEffectTechnique*> FCDEffectTechniqueList; /**< A dynamically-sized array of effect techniques. */
typedef vector<FCDEffectCode*> FCDEffectCodeList; /**< A dynamically-sized array of effect code inclusion. */
/**
A general effect profile description.
The general effect profile contains all the information necessary
to implement the advanced effect profiles, such as CG, HLSL, GLSL and GLES.
Since these effect profiles contains extremely similar information, they
use the same description structure. For the COMMON profile,
see the FCDEffectStandard class.
You should use the GetType function to figure out which profile this structure
addresses. You can then retrieve one or many of the FCDEffectTechnique objects
that describe how to render for this profile. You may want to check the
FCDEffectMaterialTechniqueHint objects at the FCDMaterial level, in order to
determine which technique(s) to use for your platform. At the profile
level of abstraction, parameters may be generated within the FCDEffectParamterList.
@ingroup FCDEffect
*/
class FCOLLADA_EXPORT FCDEffectProfileFX : public FCDEffectProfile
{
private:
FUDaeProfileType::Type type;
string includeFilename;
fstring platform;
FCDEffectCodeList codes;
FCDEffectTechniqueList techniques;
FCDEffectParameterList* parameters;
public:
/** Constructor: do not use directly. Instead, use the FCDEffect::AddProfile function.
@param document The COLLADA document which owns the effect profile.
@param parent The effect which contains this profile.
@param type The type of profile. */
FCDEffectProfileFX(FCDocument* document, FCDEffect* parent, FUDaeProfileType::Type type);
/** Destructor: do not use directly. Instead, use the FCDEffect:RemoveProfile function. */
virtual ~FCDEffectProfileFX();
/** Retrieves the profile type for this effect.
This function is a part of the FCDEffectProfile interface and allows you
to up-cast an effect profile pointer safely to this class.
@return The profile type. This should never be the value: 'COMMON',
but all other profiles currently derive from this class. */
virtual FUDaeProfileType::Type GetType() const { return type; }
/** @deprecated Retrieves the filename of the file that contains the code for this effect profile.
Instead, look through the FCDEffectCode object, using the GetCodeList function and retrieve
the correct object and its filename string.
@return The filename of the file to import. */
const string& GetIncludeFilename() const { return includeFilename; }
/** Retrieves the name of the platform in which to use the effect profile.
This parameter is very optional.
@return The platform name. */
const fstring& GetPlatform() const { return platform; }
/** Sets the name of the platform in which to use the effect profile.
This parameter is very optional.
@param _platform The platform name. */
void SetPlatform(fstring& _platform) { platform = _platform; }
/** Retrieves the list of techniques contained within this effect profile.
You may want to check the FCDEffectMaterialTechniqueHint objects at the FCDMaterial level,
in order to determine which technique(s) to use for your platform.
@return The list of inner techniques. */
FCDEffectTechniqueList& GetTechniqueList() { return techniques; }
const FCDEffectTechniqueList& GetTechniqueList() const { return techniques; } /**< See above. */
/** Retrieves the number of techniques contained within this effect profile.
@return The number of inner techniques. */
size_t GetTechniqueCount() const { return techniques.size(); }
/** Retrieves a technique contained within this effect profile.
You may want to check the FCDEffectMaterialTechniqueHint objects at the FCDMaterial level,
in order to determine which technique(s) to use for your platform.
@param index The index of the technique.
@return The inner technique. This pointer will be NULL if the index is out-of-bounds. */
FCDEffectTechnique* GetTechnique(size_t index) { FUAssert(index < GetTechniqueCount(), return NULL); return techniques.at(index); }
const FCDEffectTechnique* GetTechnique(size_t index) const { FUAssert(index < GetTechniqueCount(), return NULL); return techniques.at(index); } /**< See above. */
/** Adds a new technique to this effect profile.
@return The new technique object. */
FCDEffectTechnique* AddTechnique();
/** Releases a technique contained within this effect profile.
@param technique The technique to release. */
void ReleaseTechnique(FCDEffectTechnique* technique);
/** Retrieves the list of code inclusions.
@return The list of code inclusions. */
FCDEffectCodeList& GetCodeList() { return codes; }
const FCDEffectCodeList& GetCodeList() const { return codes; } /**< See above. */
/** Retrieves the number of code inclusions contained within the effect profile.
@return The number of code inclusions. */
size_t GetCodeCount() const { return codes.size(); }
/** Retrieves a code inclusion contained within the effect profile.
@param index The index of the code inclusion.
@return The code inclusion. This pointer will be NULL if the index is out-of-bounds. */
FCDEffectCode* GetCode(size_t index) { FUAssert(index < GetCodeCount(), return NULL); return codes.at(index); }
const FCDEffectCode* GetCode(size_t index) const { FUAssert(index < GetCodeCount(), return NULL); return codes.at(index); } /**< See above. */
/** Retrieves the code inclusion with the given sub-id.
@param sid A COLLADA sub-id.
@return The code inclusion with the given sub-id. This pointer will be NULL,
if there are no code inclusions that match the given sub-id. */
FCDEffectCode* FindCode(const string& sid);
const FCDEffectCode* FindCode(const string& sid) const; /**< See above. */
/** Adds a new code inclusion to this effect profile.
@return The new code inclusion. */
FCDEffectCode* AddCode();
/** Releases a code inclusion contained within this effect profile.
@param code The code inclusion to release. */
void ReleaseCode(FCDEffectCode* code);
/** Retrieves the list of effect parameters contained within the effect profile.
At this level of abstraction, there should be only effect parameter generators.
@return The list of effect parameters. */
FCDEffectParameterList* GetParameters() { return parameters; }
const FCDEffectParameterList* GetParameters() const { return parameters; } /**< See above. */
/** [INTERNAL] Inserts an existing parameter into the list of effect parameters
at this abstraction level. This function is used during the flattening of a material.
@param parameter The effect parameter to insert. */
void AddParameter(FCDEffectParameter* parameter);
/** Retrieves an effect parameter.
Looks for the effect parameter with the correct reference, in order to bind or override its value.
This function searches through the effect profile and the level of abstractions below.
@param reference The reference to match. In the case of effect parameter generators,
the sub-id is used to match.
@return The first effect parameter that matches the reference.
This pointer will be NULL if no effect parameter matches the given semantic. */
const FCDEffectParameter* FindParameter(const char* reference) const;
/** Retrieves an effect parameter.
Looks for the effect parameter with the correct semantic, in order to bind or override its value.
This function searches through the effect profile and the level of abstractions below.
@param semantic The effect parameter semantic to match.
@return The first effect parameter that matches the semantic.
This pointer will be NULL if no effect parameter matches the given semantic. */
virtual FCDEffectParameter* FindParameterBySemantic(const string& semantic);
/** Retrieves a subset of the effect parameter list.
Look for the effect parameter generators with the correct semantic.
This function searches through the effect profile and the level of abstractions below.
@param semantic The effect parameter semantic to match.
@param parameters The list of parameters to fill in. This list is not cleared. */
virtual void FindParametersBySemantic(const string& semantic, FCDEffectParameterList& parameters);
/** Retrieves a subset of the effect parameter list.
Look for the effect parameter generators with the correct reference.
This function searches through the effect profile and the level of abstractions below.
@param reference The effect parameter reference to match. In the case of effect
parameter generators, the reference is replaced by the sub-id.
@param parameters The list of parameters to fill in. This list is not cleared. */
virtual void FindParametersByReference(const string& reference, FCDEffectParameterList& parameters);
/** [INTERNAL] Clones the full effect profile.
@param newParent The effect that will contain the cloned profile.
@return The cloned profile. This pointer will never be NULL. */
virtual FCDEffectProfile* Clone(FCDEffect* newParent);
/** [INTERNAL] Flattens this effect profile. Pushes all the effect parameter overrides
into the effect parameter generators and moves all the parameters to the
effect technique level of abstraction. To flatten the material, use the
FCDMaterialInstance::FlattenMaterial function. */
virtual void Flatten();
/** [INTERNAL] Reads in the effect profile from a given COLLADA XML tree node.
@param profileNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the effect profile.*/
virtual FUStatus LoadFromXML(xmlNode* profileNode);
/** [INTERNAL] Writes out the effect profile to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the material declaration.
@return The created element XML tree node. */
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif // _FCD_EFFECT_PROFILE_H_

View File

@@ -0,0 +1,572 @@
/*
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/FCDEffect.h"
#include "FCDocument/FCDEffectStandard.h"
#include "FCDocument/FCDMaterial.h"
#include "FCDocument/FCDTexture.h"
#include "FUtils/FUDaeEnum.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
#include "FUtils/FUStringConversion.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDEffectStandard::FCDEffectStandard(FCDocument* document, FCDEffect* _parent) : FCDEffectProfile(document, _parent)
{
emissionColor = translucencyColor = diffuseColor = ambientColor = specularColor = FMVector3::Origin;
reflectivityFactor = translucencyFactor = specularFactor = emissionFactor = 1.0f;
reflectivityColor = translucencyColor = FMVector3(1.0f, 1.0f, 1.0f);
shininess = 20.0f;
type = CONSTANT;
isWireframe = isFaceMap = isDoubleSided = isFaceted = isEmissionFactor = false;
textureBuckets = new FCDTextureList[FUDaeTextureChannel::COUNT];
}
FCDEffectStandard::~FCDEffectStandard()
{
for (uint32 i = 0; i < FUDaeTextureChannel::COUNT; ++i)
{
FCDTextureList& t = textureBuckets[i];
CLEAR_POINTER_VECTOR(t);
}
SAFE_DELETE_ARRAY(textureBuckets);
}
// Retrieve one of the buckets
const FCDTextureList& FCDEffectStandard::GetTextureBucket(uint32 bucket) const
{
if (bucket < FUDaeTextureChannel::COUNT) return textureBuckets[bucket];
else return textureBuckets[FUDaeTextureChannel::FILTER]; // Because I think this one will almost always be empty. ;)
}
// Adds a texture to a specific channel.
FCDTexture* FCDEffectStandard::AddTexture(uint32 bucket)
{
FUAssert(bucket < FUDaeTextureChannel::COUNT, return NULL);
FCDTexture* texture = new FCDTexture(GetDocument());
textureBuckets[bucket].push_back(texture);
return texture;
}
// Releases a texture contained within this effect profile.
void FCDEffectStandard::ReleaseTexture(FCDTexture* texture)
{
for (uint32 i = 0; i < FUDaeTextureChannel::COUNT; ++i)
{
FCDTextureList::iterator it = std::find(textureBuckets[i].begin(), textureBuckets[i].end(), texture);
if (it != textureBuckets[i].end())
{
delete *it;
textureBuckets[i].erase(it);
break;
}
}
}
// Calculate the opacity for this material
float FCDEffectStandard::GetOpacity() const
{
return 1.0f - (translucencyColor.x + translucencyColor.y + translucencyColor.z) / 3.0f * translucencyFactor;
}
// Calculate the overall reflectivity for this material
float FCDEffectStandard::GetReflectivity() const
{
return (reflectivityColor.x + reflectivityColor.y + reflectivityColor.z) / 3.0f * reflectivityFactor;
}
// Look for the effect parameter with the correct semantic, in order to bind/set its value
FCDEffectParameter* FCDEffectStandard::FindParameterBySemantic(const string& semantic)
{
// Check only the texture buckets, for now.
for (uint32 i = 0; i < FUDaeTextureChannel::COUNT; ++i)
{
for (FCDTextureList::iterator itT = textureBuckets[i].begin(); itT != textureBuckets[i].end(); ++itT)
{
FCDEffectParameter* p = (*itT)->FindParameterBySemantic(semantic);
if (p != NULL) return p;
}
}
return NULL;
}
void FCDEffectStandard::FindParametersBySemantic(const string& semantic, FCDEffectParameterList& parameters)
{
// Check only the texture buckets, for now.
for (uint32 i = 0; i < FUDaeTextureChannel::COUNT; ++i)
{
for (FCDTextureList::iterator itT = textureBuckets[i].begin(); itT != textureBuckets[i].end(); ++itT)
{
(*itT)->FindParametersBySemantic(semantic, parameters);
}
}
}
void FCDEffectStandard::FindParametersByReference(const string& reference, FCDEffectParameterList& parameters)
{
// Check only the texture buckets, for now.
for (uint32 i = 0; i < FUDaeTextureChannel::COUNT; ++i)
{
for (FCDTextureList::iterator itT = textureBuckets[i].begin(); itT != textureBuckets[i].end(); ++itT)
{
(*itT)->FindParametersByReference(reference, parameters);
}
}
}
// Clone the standard effect
FCDEffectProfile* FCDEffectStandard::Clone(FCDEffect* newParent)
{
FCDEffectStandard* clone = new FCDEffectStandard(GetDocument(), newParent);
clone->type = type;
for (uint32 i = 0; i < FUDaeTextureChannel::COUNT; ++i)
{
for (FCDTextureList::iterator itT = textureBuckets[i].begin(); itT != textureBuckets[i].end(); ++itT)
{
clone->textureBuckets[i].push_back((*itT)->Clone());
}
}
# define CLONE_ANIMATED_F(flt) clone->flt = flt; FCDAnimatedFloat::Clone(GetDocument(), &flt, &clone->flt);
# define CLONE_ANIMATED_C(flt) clone->flt = flt; FCDAnimatedColor::Clone(GetDocument(), &flt, &clone->flt);
CLONE_ANIMATED_C(emissionColor); CLONE_ANIMATED_F(emissionFactor); clone->isEmissionFactor = isEmissionFactor;
CLONE_ANIMATED_C(translucencyColor); CLONE_ANIMATED_F(translucencyFactor);
CLONE_ANIMATED_C(diffuseColor); CLONE_ANIMATED_C(ambientColor);
CLONE_ANIMATED_C(specularColor); CLONE_ANIMATED_F(specularFactor); CLONE_ANIMATED_F(shininess);
CLONE_ANIMATED_C(reflectivityColor); CLONE_ANIMATED_F(reflectivityFactor);
clone->isFaceted = isFaceted;
clone->isDoubleSided = isDoubleSided;
clone->isWireframe = isWireframe;
clone->isFaceMap = isFaceMap;
# undef CLONE_ANIMATED_F
# undef CLONE_ANIMATED_C
return clone;
}
// Read in a <material> node from the COLLADA document
FUStatus FCDEffectStandard::LoadFromXML(xmlNode* baseNode)
{
FUStatus status;
// <shader> support is for COLLADA 1.3 backward compatibility
bool isCollada1_3 = IsEquivalent(baseNode->name, DAE_SHADER_ELEMENT);
if (!isCollada1_3 && !IsEquivalent(baseNode->name, DAE_FX_PROFILE_COMMON_ELEMENT))
{
return status.Warning(FS("Unknown element as standard material base."), baseNode->line);
}
// For COLLADA 1.3 backward compatibility: find the correct base node for the profile.
// While we're digging, find the node with the Max-specific parameters
xmlNode* maxParameterNode = NULL;
xmlNode* mayaParameterNode = NULL;
if (isCollada1_3)
{
// COLLADA 1.3 backward compatibility: the base node is <shader><technique><pass>
// and the Max-specific parameters are in <shader><technique><pass><program>.
xmlNode* commonTechniqueNode = FindTechnique(baseNode, DAE_COMMON_PROFILE);
xmlNode* maxTechniqueNode = FindTechnique(baseNode, DAEMAX_MAX_PROFILE);
baseNode = FindChildByType(commonTechniqueNode, DAE_PASS_ELEMENT);
xmlNode* maxPassNode = FindChildByType(maxTechniqueNode, DAE_PASS_ELEMENT);
maxParameterNode = FindChildByType(maxPassNode, DAE_PROGRAM_ELEMENT);
}
else
{
// Bump the base node up the first <technique> element
xmlNode* techniqueNode = FindChildByType(baseNode, DAE_TECHNIQUE_ELEMENT);
if (techniqueNode == NULL)
{
return status.Warning(FS("Expecting <technique> within the <profile_COMMON> element for effect: ") + TO_FSTRING(GetDaeId()), baseNode->line);
}
baseNode = techniqueNode;
// Look for an <extra><technique> node for Max-specific parameter
xmlNode* extraNode = FindChildByType(baseNode, DAE_EXTRA_ELEMENT);
maxParameterNode = FindTechnique(extraNode, DAEMAX_MAX_PROFILE);
mayaParameterNode = FindTechnique(extraNode, DAEMAYA_MAYA_PROFILE);
}
if (isCollada1_3)
{
// COLLADA 1.3 backward compatibility: look for <input> elements pointing to textures
xmlNodeList textureInputNodes;
FindChildrenByType(baseNode, DAE_INPUT_ELEMENT, textureInputNodes);
for (xmlNodeList::iterator it = textureInputNodes.begin(); it != textureInputNodes.end(); ++it)
{
string semantic = ReadNodeSemantic(*it);
if (semantic != DAE_TEXTURE_INPUT)
{
status.Warning(FS("Unknown input semantic in material: ") + TO_FSTRING(GetDaeId()), (*it)->line);
continue;
}
// Retrieve the texture and bucket it
string textureId = ReadNodeSource(*it);
FCDTexture* texture = GetDocument()->FindTexture(textureId);
if (texture != NULL)
{
uint32 channel = (uint32) texture->GetTextureChannel();
textureBuckets[(uint32) channel].push_back(texture->Clone());
}
else
{
status.Warning(FS("Unknown input texture '") + TO_FSTRING(textureId) + FS("' in material: ") + TO_FSTRING(GetDaeId()), (*it)->line);
}
}
}
// Parse the material's program node and figure out the correct shader type
xmlNode* commonParameterNode = NULL;
if (isCollada1_3)
{
// COLLADA 1.3 backward compatibility: read in the type attribute of the <program> node
commonParameterNode = FindChildByType(baseNode, DAE_PROGRAM_ELEMENT);
FUUri programUrl = ReadNodeUrl(commonParameterNode);
string materialType = FUStringConversion::ToString(programUrl.prefix);
if (materialType == DAE_CONSTANT_MATERIAL_PROGRAM) type = CONSTANT;
else if (materialType == DAE_LAMBERT_MATERIAL_PROGRAM) type = LAMBERT;
else if (materialType == DAE_PHONG_MATERIAL_PROGRAM) type = PHONG;
else
{
return status.Warning(FS("Unsupported shader program type: '") + programUrl.prefix + FS("' in material: ") + TO_FSTRING(GetDaeId()), commonParameterNode->line);
}
}
else
{
// Either <phong>, <lambert> or <constant> are expected
for (commonParameterNode = baseNode->children; commonParameterNode != NULL; commonParameterNode = commonParameterNode->next)
{
if (commonParameterNode->type != XML_ELEMENT_NODE) continue;
if (IsEquivalent(commonParameterNode->name, DAE_FXSTD_CONSTANT_ELEMENT)) { type = CONSTANT; break; }
else if (IsEquivalent(commonParameterNode->name, DAE_FXSTD_LAMBERT_ELEMENT)) { type = LAMBERT; break; }
else if (IsEquivalent(commonParameterNode->name, DAE_FXSTD_PHONG_ELEMENT)) { type = PHONG; break; }
else if (IsEquivalent(commonParameterNode->name, DAE_FXSTD_BLINN_ELEMENT)) { type = BLINN; break; }
}
}
if (commonParameterNode == NULL)
{
return status.Fail(FS("Unable to find the program node for standard effect: ") + TO_FSTRING(GetDaeId()), baseNode->line);
}
bool hasTranslucency = false, hasReflectivity = false;
FCDTextureList emptyBucket;
// Read in the parameters for the common program types and apply them to the shader
StringList parameterNames;
xmlNodeList parameterNodes;
FindParameters(commonParameterNode, parameterNames, parameterNodes);
FindParameters(maxParameterNode, parameterNames, parameterNodes);
FindParameters(mayaParameterNode, parameterNames, parameterNodes);
size_t parameterCount = parameterNodes.size();
for (size_t i = 0; i < parameterCount; ++i)
{
xmlNode* parameterNode = parameterNodes[i];
const string& parameterName = parameterNames[i];
const char* parameterContent = ReadNodeContentDirect(parameterNode);
if (parameterName == DAE_EMISSION_MATERIAL_PARAMETER || parameterName == DAE_EMISSION_MATERIAL_PARAMETER1_3)
{
status.AppendStatus(ParseColorTextureParameter(parameterNode, emissionColor, textureBuckets[FUDaeTextureChannel::EMISSION]));
}
else if (parameterName == DAE_DIFFUSE_MATERIAL_PARAMETER || parameterName == DAE_DIFFUSE_MATERIAL_PARAMETER1_3)
{
status.AppendStatus(ParseColorTextureParameter(parameterNode, diffuseColor, textureBuckets[FUDaeTextureChannel::DIFFUSE]));
}
else if (parameterName == DAE_AMBIENT_MATERIAL_PARAMETER || parameterName == DAE_AMBIENT_MATERIAL_PARAMETER1_3)
{
status.AppendStatus(ParseColorTextureParameter(parameterNode, ambientColor, textureBuckets[FUDaeTextureChannel::AMBIENT]));
}
else if (parameterName == DAE_TRANSPARENT_MATERIAL_PARAMETER || parameterName == DAE_TRANSPARENT_MATERIAL_PARAMETER1_3)
{
status.AppendStatus(ParseColorTextureParameter(parameterNode, translucencyColor, textureBuckets[FUDaeTextureChannel::TRANSPARENT]));
hasTranslucency = true;
}
else if (parameterName == DAE_TRANSPARENCY_MATERIAL_PARAMETER || parameterName == DAE_TRANSPARENCY_MATERIAL_PARAMETER1_3)
{
status.AppendStatus(ParseFloatTextureParameter(parameterNode, translucencyFactor, textureBuckets[FUDaeTextureChannel::OPACITY]));
hasTranslucency = true;
}
else if (parameterName == DAE_SPECULAR_MATERIAL_PARAMETER || parameterName == DAE_SPECULAR_MATERIAL_PARAMETER1_3)
{
status.AppendStatus(ParseColorTextureParameter(parameterNode, specularColor, textureBuckets[FUDaeTextureChannel::SPECULAR]));
}
else if (parameterName == DAE_SPECULAR_MATERIAL_PARAMETER || parameterName == DAE_SPECULAR_MATERIAL_PARAMETER1_3)
{
status.AppendStatus(ParseColorTextureParameter(parameterNode, specularColor, textureBuckets[FUDaeTextureChannel::SPECULAR]));
}
else if (parameterName == DAE_SHININESS_MATERIAL_PARAMETER || parameterName == DAE_SHININESS_MATERIAL_PARAMETER1_3)
{
status.AppendStatus(ParseFloatTextureParameter(parameterNode, shininess, textureBuckets[FUDaeTextureChannel::SHININESS]));
}
else if (parameterName == DAE_REFLECTIVE_MATERIAL_PARAMETER || parameterName == DAE_REFLECTIVE_MATERIAL_PARAMETER1_3)
{
status.AppendStatus(ParseColorTextureParameter(parameterNode, reflectivityColor, textureBuckets[FUDaeTextureChannel::REFLECTION]));
hasReflectivity = true;
}
else if (parameterName == DAE_REFLECTIVITY_MATERIAL_PARAMETER || parameterName == DAE_REFLECTIVITY_MATERIAL_PARAMETER1_3)
{
status.AppendStatus(ParseFloatTextureParameter(parameterNode, reflectivityFactor, emptyBucket));
hasReflectivity = true;
}
else if (parameterName == DAE_BUMP_MATERIAL_PARAMETER)
{
status.AppendStatus(ParseSimpleTextureParameter(parameterNode, textureBuckets[FUDaeTextureChannel::BUMP]));
}
else if (parameterName == DAEMAX_SPECLEVEL_MATERIAL_PARAMETER || parameterName == DAEMAX_SPECLEVEL_MATERIAL_PARAMETER1_3)
{
status.AppendStatus(ParseFloatTextureParameter(parameterNode, specularFactor, textureBuckets[FUDaeTextureChannel::SPECULAR_LEVEL]));
}
else if (parameterName == DAEMAX_EMISSIONLEVEL_MATERIAL_PARAMETER || parameterName == DAEMAX_EMISSIONLEVEL_MATERIAL_PARAMETER1_3)
{
status.AppendStatus(ParseFloatTextureParameter(parameterNode, emissionFactor, textureBuckets[FUDaeTextureChannel::EMISSION]));
isEmissionFactor = true;
}
else if (parameterName == DAEMAX_FACETED_MATERIAL_PARAMETER || parameterName == DAEMAX_FACETED_MATERIAL_PARAMETER1_3)
{
isFaceted = FUStringConversion::ToBoolean(parameterContent);
}
else if (parameterName == DAESHD_DOUBLESIDED_PARAMETER)
{
isDoubleSided = FUStringConversion::ToBoolean(parameterContent);
}
else if (parameterName == DAEMAX_WIREFRAME_MATERIAL_PARAMETER)
{
isWireframe = FUStringConversion::ToBoolean(parameterContent);
}
else if (parameterName == DAEMAX_FACEMAP_MATERIAL_PARAMETER)
{
isFaceMap = FUStringConversion::ToBoolean(parameterContent);
}
else if (parameterName == DAEMAX_INDEXOFREFRACTION_MATERIAL_PARAMETER)
{
status.AppendStatus(ParseSimpleTextureParameter(parameterNode, textureBuckets[FUDaeTextureChannel::REFRACTION]));
}
else if (parameterName == DAEMAX_DISPLACEMENT_MATERIAL_PARAMETER)
{
status.AppendStatus(ParseSimpleTextureParameter(parameterNode, textureBuckets[FUDaeTextureChannel::DISPLACEMENT]));
}
else if (parameterName == DAEMAX_FILTERCOLOR_MATERIAL_PARAMETER)
{
status.AppendStatus(ParseSimpleTextureParameter(parameterNode, textureBuckets[FUDaeTextureChannel::FILTER]));
}
else
{
status.Warning(FS("Unknown parameter name for material ") + TO_FSTRING(GetDaeId()), parameterNode->line);
}
}
bool isEmptyBucketEmpty = emptyBucket.empty();
CLEAR_POINTER_VECTOR(emptyBucket);
if (!isEmptyBucketEmpty)
{
return status.Fail(FS("Unexpected texture sampler on some parameters for material ") + TO_FSTRING(GetDaeId()), baseNode->line);
}
// Although the default COLLADA materials gives, wrongly, a transparent material,
// when neither the TRANSPARENT or TRANSPARENCY parameters are set, assume an opaque material.
// Similarly for reflectivity
if (!hasTranslucency)
{
translucencyColor = FMVector3::Origin;
translucencyFactor = 0.0f;
}
if (!hasReflectivity)
{
reflectivityColor = FMVector3::Origin;
reflectivityFactor = 0.0f;
}
// Convert some of the values that may appear in different formats
if (!isEmissionFactor)
{
emissionFactor = (emissionColor.x + emissionColor.y + emissionColor.z) / 3.0f;
}
return status;
}
xmlNode* FCDEffectStandard::WriteToXML(xmlNode* parentNode) const
{
xmlNode* profileCommonNode = AddChild(parentNode, DAE_FX_PROFILE_COMMON_ELEMENT);
xmlNode* techniqueCommonNode = AddChild(profileCommonNode, DAE_TECHNIQUE_ELEMENT);
AddNodeSid(techniqueCommonNode, "common");
const char* materialName;
switch (type)
{
case CONSTANT: materialName = DAE_FXSTD_CONSTANT_ELEMENT; break;
case LAMBERT: materialName = DAE_FXSTD_LAMBERT_ELEMENT; break;
case PHONG: materialName = DAE_FXSTD_PHONG_ELEMENT; break;
case BLINN: materialName = DAE_FXSTD_BLINN_ELEMENT; break;
case UNKNOWN:
default: materialName = DAEERR_UNKNOWN_ELEMENT; break;
}
xmlNode* materialNode = AddChild(techniqueCommonNode, materialName);
xmlNode* techniqueNode = AddExtraTechniqueChild(techniqueCommonNode, DAEMAYA_MAYA_PROFILE);
// Export the color/float parameters
FCDTextureList emptyBucket; float emptyValue = 0.0f; FMVector3 emptyColor;
WriteColorTextureParameterToXML(materialNode, DAE_EMISSION_MATERIAL_PARAMETER, emissionColor, textureBuckets[FUDaeTextureChannel::EMISSION]);
if (type != CONSTANT)
{
WriteColorTextureParameterToXML(materialNode, DAE_AMBIENT_MATERIAL_PARAMETER, emissionColor, textureBuckets[FUDaeTextureChannel::AMBIENT]);
WriteColorTextureParameterToXML(materialNode, DAE_DIFFUSE_MATERIAL_PARAMETER, diffuseColor, textureBuckets[FUDaeTextureChannel::DIFFUSE]);
if (type != LAMBERT)
{
WriteColorTextureParameterToXML(materialNode, DAE_SPECULAR_MATERIAL_PARAMETER, specularColor, textureBuckets[FUDaeTextureChannel::SPECULAR]);
WriteFloatTextureParameterToXML(materialNode, DAE_SHININESS_MATERIAL_PARAMETER, shininess, emptyBucket);
if (!textureBuckets[FUDaeTextureChannel::SHININESS].empty())
{
WriteFloatTextureParameterToXML(techniqueNode, DAE_SHININESS_MATERIAL_PARAMETER, shininess, textureBuckets[FUDaeTextureChannel::SHININESS]);
WriteFloatTextureParameterToXML(techniqueNode, DAEMAX_SPECLEVEL_MATERIAL_PARAMETER, specularFactor, textureBuckets[FUDaeTextureChannel::SPECULAR_LEVEL]);
}
}
}
WriteColorTextureParameterToXML(materialNode, DAE_REFLECTIVE_MATERIAL_PARAMETER, reflectivityColor, textureBuckets[FUDaeTextureChannel::REFLECTION]);
WriteFloatTextureParameterToXML(materialNode, DAE_REFLECTIVITY_MATERIAL_PARAMETER, reflectivityFactor, emptyBucket);
// Translucency includes both transparent and opacity textures
FCDTextureList translucencyBucket = textureBuckets[FUDaeTextureChannel::TRANSPARENT];
translucencyBucket.insert(translucencyBucket.end(), textureBuckets[FUDaeTextureChannel::OPACITY].begin(), textureBuckets[FUDaeTextureChannel::OPACITY].end());
WriteColorTextureParameterToXML(materialNode, DAE_TRANSPARENT_MATERIAL_PARAMETER, translucencyColor, translucencyBucket);
WriteFloatTextureParameterToXML(materialNode, DAE_TRANSPARENCY_MATERIAL_PARAMETER, translucencyFactor, emptyBucket);
WriteFloatTextureParameterToXML(materialNode, DAEMAX_INDEXOFREFRACTION_MATERIAL_PARAMETER, emptyValue, textureBuckets[FUDaeTextureChannel::REFRACTION]);
// Non-COLLADA parameters
if (!textureBuckets[FUDaeTextureChannel::BUMP].empty())
{
WriteFloatTextureParameterToXML(techniqueNode, DAE_BUMP_MATERIAL_PARAMETER, emptyValue, textureBuckets[FUDaeTextureChannel::BUMP]);
}
if (!textureBuckets[FUDaeTextureChannel::DISPLACEMENT].empty())
{
WriteFloatTextureParameterToXML(techniqueNode, DAEMAX_DISPLACEMENT_MATERIAL_PARAMETER, emptyValue, textureBuckets[FUDaeTextureChannel::DISPLACEMENT]);
}
if (!textureBuckets[FUDaeTextureChannel::FILTER].empty())
{
WriteColorTextureParameterToXML(techniqueNode, DAEMAX_FILTERCOLOR_MATERIAL_PARAMETER, emptyColor, textureBuckets[FUDaeTextureChannel::FILTER]);
}
return profileCommonNode;
}
xmlNode* FCDEffectStandard::WriteColorTextureParameterToXML(xmlNode* parentNode, const char* parameterNodeName, const FMVector3& value, const FCDTextureList& textureBucket) const
{
xmlNode* parameterNode = AddChild(parentNode, parameterNodeName);
if (WriteTextureParameterToXML(parameterNode, textureBucket) == NULL)
{
// The color value expected by the profile_COMMON <color> element has four floating-point values.
string colorValue = FUStringConversion::ToString(value) + " 1.0";
xmlNode* valueNode = AddChild(parameterNode, DAE_FXSTD_COLOR_ELEMENT, colorValue);
GetDocument()->WriteAnimatedValueToXML(&value.x, valueNode, parameterNodeName);
}
return parameterNode;
}
xmlNode* FCDEffectStandard::WriteFloatTextureParameterToXML(xmlNode* parentNode, const char* parameterNodeName, const float& value, const FCDTextureList& textureBucket) const
{
xmlNode* parameterNode = AddChild(parentNode, parameterNodeName);
if (WriteTextureParameterToXML(parameterNode, textureBucket) == NULL)
{
xmlNode* valueNode = AddChild(parameterNode, DAE_FXSTD_FLOAT_ELEMENT, value);
GetDocument()->WriteAnimatedValueToXML(&value, valueNode, parameterNodeName);
}
return parameterNode;
}
xmlNode* FCDEffectStandard::WriteTextureParameterToXML(xmlNode* parentNode, const FCDTextureList& textureBucket) const
{
xmlNode* textureNode = NULL;
for (FCDTextureList::const_iterator itT = textureBucket.begin(); itT != textureBucket.end(); ++itT)
{
xmlNode* newTextureNode = (*itT)->WriteToXML(parentNode);
if (newTextureNode != NULL && textureNode == NULL) textureNode = newTextureNode;
}
return textureNode;
}
// Parse in the different standard effect parameters, bucketing the textures
FUStatus FCDEffectStandard::ParseColorTextureParameter(xmlNode* parameterNode, FMVector3& value, FCDTextureList& textureBucket)
{
FUStatus status;
// Look for <texture> elements, they pre-empt everything else
size_t originalSize = textureBucket.size();
ParseSimpleTextureParameter(parameterNode, textureBucket);
if (originalSize < textureBucket.size()) { value = FMVector3(1.0f, 1.0f, 1.0f); return status; }
// Next, look for a <color> element
// COLLADA 1.3 backward compatibility: also look for the color value directly inside the parameter node.
xmlNode* colorNode = FindChildByType(parameterNode, DAE_FXSTD_COLOR_ELEMENT);
const char* content = ReadNodeContentDirect(colorNode);
if (content == NULL || *content == 0) content = ReadNodeContentDirect(parameterNode);
// Parse the color value and allow for an animation of it
value = FUStringConversion::ToPoint(content);
if (HasNodeProperty(colorNode, DAE_ID_ATTRIBUTE) || HasNodeProperty(colorNode, DAE_SID_ATTRIBUTE))
FCDAnimatedColor::Create(GetDocument(), colorNode, &value);
else
FCDAnimatedColor::Create(GetDocument(), parameterNode, &value);
return status;
}
FUStatus FCDEffectStandard::ParseFloatTextureParameter(xmlNode* parameterNode, float& value, FCDTextureList& textureBucket)
{
FUStatus status;
// Look for <texture> elements, they pre-empt everything else
size_t originalSize = textureBucket.size();
ParseSimpleTextureParameter(parameterNode, textureBucket);
if (originalSize < textureBucket.size()) { value = 1.0f; return status; }
// Next, look for a <float> element
// COLLADA 1.3 backward compatibility: also look for the value directly inside the parameter node.
xmlNode* floatNode = FindChildByType(parameterNode, DAE_FXSTD_FLOAT_ELEMENT);
const char* content = ReadNodeContentDirect(floatNode);
if (content == NULL || *content == 0) content = ReadNodeContentDirect(parameterNode);
// Parse the value and register it for an animation.
value = FUStringConversion::ToFloat(content);
if (HasNodeProperty(floatNode, DAE_ID_ATTRIBUTE) || HasNodeProperty(floatNode, DAE_SID_ATTRIBUTE))
FCDAnimatedFloat::Create(GetDocument(), floatNode, &value);
else
FCDAnimatedFloat::Create(GetDocument(), parameterNode, &value);
return status;
}
FUStatus FCDEffectStandard::ParseSimpleTextureParameter(xmlNode* parameterNode, FCDTextureList& textureBucket)
{
FUStatus status;
// Parse in all the <texture> elements as standard effect samplers
xmlNodeList samplerNodes;
FindChildrenByType(parameterNode, DAE_FXSTD_SAMPLER_ELEMENT, samplerNodes);
if (!samplerNodes.empty())
{
for (xmlNodeList::iterator itS = samplerNodes.begin(); itS != samplerNodes.end(); ++itS)
{
// Parse in the texture element and bucket them
FCDTexture* texture = new FCDTexture(GetDocument());
status.AppendStatus(texture->LoadFromTextureXML(*itS));
if (status) textureBucket.push_back(texture);
else { SAFE_DELETE(texture); }
}
}
return status;
}

View File

@@ -0,0 +1,415 @@
/*
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
*/
/**
@file FCDEffectStandard.h
This file contains the FCDEffectStandard class.
*/
#ifndef _FCD_MATERIAL_STANDARD_H_
#define _FCD_MATERIAL_STANDARD_H_
#include "FUtils/FUDaeEnum.h"
#include "FCDocument/FCDEffectProfile.h"
class FCDocument;
class FCDEffect;
class FCDEffectParameter;
class FCDTexture;
class FCDEffectParameterList;
/** A dynamically-sized array of texture objects. */
typedef vector<FCDTexture*> FCDTextureList;
/**
A COMMON profile effect description.
The COMMON effect profile holds the information necessary
to render your polygon sets using the well-defined lighting models.
COLLADA supports four lighting models: constant, Lambert, Phong and Blinn.
@ingroup FCDEffect
*/
class FCOLLADA_EXPORT FCDEffectStandard : public FCDEffectProfile
{
public:
/** The list of the lighting models supported by the COMMON profile of COLLADA. */
enum LightingType
{
/** The constant lighting model.
This lighting model uses the emissive color everywhere, without
any complex lighting calculations. It also uses the translucency
factor and the translucency color, by multiplying them together
and applying them to your standard alpha channel according to the
final lighting color.*/
CONSTANT,
/** The Lambert lighting model.
This lighting model improves on the constant lighting model by
using the dot-product between the normalized light vectors and the
polygon normals to determine how much light should affect each polygon.
This value is multiplied to the diffuse color and (1 + the ambient color). */
LAMBERT,
/** The Phong lighting model.
This lighting model improves on the Lambert lighting model by
calculating how much light is reflected by the polygons into the viewer's eye.
For this calculation, the shininess, the specular color and the reflectivity is used. */
PHONG,
/** The Blinn lighting model.
This lighting model improves on the Lambert lighting model by
calculating how much light is reflected by the polygons into the viewer's eye.
For this calculation, the shininess, the specular color and the reflectivity is used. */
BLINN,
/** Not a valid lighting model. */
UNKNOWN
};
private:
LightingType type;
FCDTextureList* textureBuckets;
// Common material parameter: Emission
FMVector3 emissionColor;
float emissionFactor; // Max-specific
// Common material parameter: Translucency
FMVector3 translucencyColor;
float translucencyFactor;
// Lambert material parameters
FMVector3 diffuseColor;
FMVector3 ambientColor;
// Phong material parameters: Specular
FMVector3 specularColor;
float specularFactor; // Max-specific
float shininess;
// Phong material parameter: Reflectivity
FMVector3 reflectivityColor; // Maya-specific
float reflectivityFactor; // Maya-specific
// Geometry modifier
bool isFaceted; // Max-specific
bool isDoubleSided; // Max-specific for now
bool isWireframe; // Max-specific
bool isFaceMap; // Max-specific
bool isEmissionFactor; // Max-specific
public:
/** Constructor: do not use directly. Instead, use the FCDEffect::AddProfile function
with the FUDaeProfileType::COMMON parameter.
@param document The COLLADA document that owns this effect profile.
@param parent The effect that contains this profile. */
FCDEffectStandard(FCDocument* document, FCDEffect* parent);
/** Destructor: do not use directly.
Instead, use the FCDEffect::ReleaseProfile function. */
virtual ~FCDEffectStandard();
/** Retrieves the lighting model to be used for this profile.
@return The lighting model. */
inline LightingType GetLightingType() const { return type; }
/** Sets the lighting model to be used for this profile.
Note that which parameters are exported depends on the lighting model.
@param _type The lighting model. */
inline void SetLightingType(LightingType _type) { type = _type; }
/** Retrieves the profile type for this effect.
This function is a part of the FCDEffectProfile interface and allows you
to up-cast an effect profile pointer safely to this class.
@return The profile type: COMMON. */
virtual FUDaeProfileType::Type GetType() const { return FUDaeProfileType::COMMON; }
/** Retrieves the list of textures belonging to a specific channel.
@param bucket A texture channel index. This index should match one
of the values in the FUDaeTextureChannel enum.
@return The list of textures for this channel. */
const FCDTextureList& GetTextureBucket(uint32 bucket) const;
/** Retrieves the number of textures belonging to a specific channel.
@param bucket A texture channel index. This index should match one
of the values in the FUDaeTextureChannel enum.
@return The number of textures in that channel. */
size_t GetTextureCount(uint32 bucket) const { FUAssert(bucket < FUDaeTextureChannel::COUNT, return 0); return textureBuckets[bucket].size(); }
/** Retrieves a texture
@param bucket A texture channel index. This index should match one
of the values in the FUDaeTextureChannel enum.
@param index The index of a texture within this channel.
@return The texture. This pointer will be NULL if either the bucket or the index is out-of-bounds. */
inline FCDTexture* GetTexture(uint32 bucket, size_t index) { FUAssert(index < GetTextureCount(bucket), return NULL); return textureBuckets[bucket].at(index); }
inline const FCDTexture* GetTexture(uint32 bucket, size_t index) const { FUAssert(index < GetTextureCount(bucket), return NULL); return textureBuckets[bucket].at(index); } /**< See above. */
/** Adds a texture to a specific channel.
@param bucket A texture channel index. This index should match one
of the values in the FUDaeTextureChannel enum.
@return The new texture. This pointer will be NULL if the bucket is out-of-bounds. */
FCDTexture* AddTexture(uint32 bucket);
/** Releases a texture contained within this effect profile.
@param texture The texture to release. */
void ReleaseTexture(FCDTexture* texture);
/** Retrieves the base translucency color.
This value must be multiplied with the translucency factor
to get the real translucency color.
This value is used in all lighting models.
@return The base translucency color. */
inline const FMVector3& GetTranslucencyColor() const { return translucencyColor; }
/** Sets the base translucency color.
@param color The base translucency color. */
inline void SetTranslucencyColor(const FMVector3& color) { translucencyColor = color; }
/** Retrieves the translucency factor.
This value must be multiplied with the translucency color
to get the real translucency color.
This value is used in all lighting models.
@return The translucency factor. */
inline const float& GetTranslucencyFactor() const { return translucencyFactor; }
/** Sets the translucency factor.
@param factor The translucency factor. */
inline void SetTranslucencyFactor(float factor) { translucencyFactor = factor; }
/** Retrieves the flat opacity.
This is a calculated value and will not take into consideration any animations
that affect either the base translucency color or the translucency factor.
This value can be used in all lighting models.
@return The flat opacity. */
float GetOpacity() const;
/** Retrieves the base emission/self-illumination color.
This value must be multiplied with the emission factor to get the real emission color.
This value is used in all lighting models.
@return The base emission color. */
inline const FMVector3& GetEmissionColor() const { return emissionColor; }
/** Sets the base emission/self-illumination color.
@param color The base emission color. */
inline void SetEmissionColor(const FMVector3& color) { emissionColor = color; }
/** Retrieves the emission/self-illumination factor.
This value must be multiplied with the base emission color to get the real emission color.
@return The emission factor. */
inline const float& GetEmissionFactor() const { return emissionFactor; }
/** Sets the emission/self-illumination factor.
@param factor The emission factor. */
inline void SetEmissionFactor(float factor) { emissionFactor = factor; }
/** Retrieves whether the emission factor was used, rather than the emission color.
This value is used in conjunction with 3dsMax, in which the self-illumination color
and the self-illumination factor are mutually exclusive.
@return Whether the emission factor is to be used. */
inline bool IsEmissionFactor() const { return isEmissionFactor; }
/** Sets whether the emission factor is to be used, rather than the emission color.
This value is used in conjunction with 3dsMax, in which the self-illumination color
and the self-illumination factor are mutually exclusive.
@param useFactor Whether the emission factor should be used. */
inline void SetIsEmissionFactor(bool useFactor) { isEmissionFactor = useFactor; }
/** Retrieves the diffuse color.
This value is used in the Lambert lighting model.
@return The diffuse color. */
inline const FMVector3& GetDiffuseColor() const { return diffuseColor; }
/** Sets the diffuse color.
@param color The diffuse color. */
inline void SetDiffuseColor(const FMVector3& color) { diffuseColor = color; }
/** Retrieves the ambient color.
This value is used in the Lambert lighting model.
@return The ambient color. */
inline const FMVector3& GetAmbientColor() const { return ambientColor; }
/** Sets the ambient color.
@param color The ambient color. */
inline void SetAmbientColor(const FMVector3& color) { ambientColor = color; }
/** Retrieves the base specular color.
This value must be multiplied with the specular factor
to get the real specular color.
This value is used in the Phong and Blinn lighting models.
@return The specular color. */
inline const FMVector3& GetSpecularColor() const { return specularColor; }
/** Sets the specular color.
@param color The specular color. */
inline void SetSpecularColor(const FMVector3& color) { specularColor = color; }
/** Retrieves the specular factor.
This value must be multiplied with the base specular color
to get the real specular color.
This value is used in the Phong and Blinn lighting models.
@return The specular factor. */
inline const float& GetSpecularFactor() const { return specularFactor; }
/** Sets the specular factor.
@param factor The specular factor. */
inline void SetSpecularFactor(float factor) { specularFactor = factor; }
/** Retrieves the specular shininess.
This value represents the exponent to which you must raise
the dot-product between the view vector and reflected light vectors:
as such, it is usually a number greater than 1.
This value is used in the Phong and Blinn lighting models.
@return The specular shininess. */
inline const float& GetShininess() const { return shininess; }
/** Sets the specular shininess.
This value represents the exponent to which you must raise
the dot-product between the view vector and reflected light vectors:
as such, it is usually a number greater than 1.
@param _shininess The specular shininess. */
inline void SetShininess(float _shininess) { shininess = _shininess; }
/** Retrieves the base reflectivity color.
This value must be multiplied to the reflectivity factor to
get the real reflectivity color.
This value is used in the Phong and Blinn lighting models.
@return The base reflectivity color. */
inline const FMVector3& GetReflectivityColor() const { return reflectivityColor; }
/** Sets the base reflectivity color.
@param color The base reflectivity color. */
inline void SetReflectivityColor(const FMVector3& color) { reflectivityColor = color; }
/** Retrieves the reflectivity factor.
This value must be multiplied to the base reflectivity color
to get the real reflectivity color.
This value is used in the Phong and Blinn lighting models.
@return The reflectivity factor. */
inline const float& GetReflectivityFactor() const { return reflectivityFactor; }
/** Sets the reflectivity factor.
@param factor The reflectivity factor. */
inline void SetReflectivityFactor(float factor) { reflectivityFactor = factor; }
/** Retrieves the flat reflectivity.
This is a calculated value and will not take into consideration any animations
that affect either the base reflectivity color or the reflectivity factor.
This value can be used in the Phong and Blinn lighting models.
@return The flat reflectivity. */
float GetReflectivity() const;
/** Retrieves the 'faceted' flag.
This flag is used in conjunction with 3dsMax. It represents whether all the edges
of the polygon sets using this effect profile should be hard. The final result
of using this flag is a mesh where all the faces stand out.
@return The status of the 'faceted' flag. */
inline bool GetFacetedFlag() const { return isFaceted; }
/** Sets the 'faceted' flag.
This flag is used in conjunction with 3dsMax. It represents whether all the edges
of the polygon sets using this effect profile should be hard. The final result
of using this flag is a mesh where all the faces stand out.
@param flag The status of the 'faceted' flag. */
inline void SetFacetedFlag(bool flag) { isFaceted = flag; }
/** Retrieves the 'double-sided' flag.
This flag is used in conjunction with 3dsMax. It represents whether all the faces
of the polygon sets should be treated as two-sided and have normals in both directions.
@return The status of the 'double-sided' flag. */
inline bool GetDoubleSidedFlag() const { return isDoubleSided; }
/** Sets the 'double-sided' flag.
This flag is used in conjunction with 3dsMax. It represents whether all the faces
of the polygon sets should be treated as two-sided and have normals in both directions.
@param flag The status of the 'double-sided' flag. */
inline bool SetDoubleSidedFlag(bool flag) { isDoubleSided = flag; }
/** Retrieves the 'wireframe' flag.
This flag is used in conjunction with 3dsMax. It represents whether all the edges
of the polygon sets should be rendered, rather than the faces.
@return The status of the 'wireframe' flag. */
inline bool GetWireframeFlag() const { return isWireframe; }
/** Sets the 'wireframe' flag.
This flag is used in conjunction with 3dsMax. It represents whether all the edges
of the polygon sets should be rendered, rather than the faces.
@param flag The status of the 'wireframe' flag. */
inline bool SetWireframeFlag(bool flag) { isWireframe = flag; }
/** Retrieves the 'face-map' flag.
This is a pure 3dsMax flag and I have no idea what it does.
@return The status of the 'face-map' flag. */
inline bool GetFaceMapFlag() const { return isFaceMap; }
/** Sets the 'face-map' flag.
This is a pure 3dsMax flag and I have no idea what it does.
@param flag The status of the 'face-map' flag. */
inline void SetFaceMapFlag(bool flag) { isFaceMap = flag; }
/** Retrieves an effect parameter.
Looks for the effect parameter with the correct semantic, in order to bind or override its value.
This function searches through the effect profile and the level of abstractions below.
@param semantic The effect parameter semantic to match.
@return The effect parameter that matches the semantic. This pointer may be
NULL if no effect parameter matches the given semantic. */
virtual FCDEffectParameter* FindParameterBySemantic(const string& semantic);
/** Retrieves a subset of the effect parameter list.
Look for effect parameters with the correct semantic.
This function searches through the effect profile and the level of abstractions below.
@param semantic The effect parameter semantic to match.
@param parameters The list of parameters to fill in. This list is not cleared. */
virtual void FindParametersBySemantic(const string& semantic, FCDEffectParameterList& parameters);
/** Retrieves a subset of the effect parameter list.
Look for effect parameters with the correct reference.
This function searches through the effect profile and the level of abstractions below.
@param reference The effect parameter reference to match. In the case of effect
parameter, the reference is replaced by the sub-id.
@param parameters The list of parameters to fill in. This list is not cleared. */
virtual void FindParametersByReference(const string& reference, FCDEffectParameterList& parameters);
/** [INTERNAL] Clones the COMMON profile effect.
You will need release the cloned effect directly, by deleting the pointer.
@param newParent The effect that contains the cloned effect profile.
@return The cloned effect profile. You will must delete this pointer. */
virtual FCDEffectProfile* Clone(FCDEffect* newParent);
/** [INTERNAL] Flattens the profile.
Does nothing on the common profile. */
virtual void Flatten() {}
/** [INTERNAL] Reads in the \<profile_COMMON\> element from a given COLLADA XML tree node.
For COLLADA 1.3 backward-compatibility, this function can also read in \<material\> elements.
@param baseNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the effect profile.*/
virtual FUStatus LoadFromXML(xmlNode* baseNode);
/** [INTERNAL] Writes out the \<profile_COMMON\> element to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the effect profile.
@return The created element XML tree node. */
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
private:
xmlNode* WriteColorTextureParameterToXML(xmlNode* parentNode, const char* parameterNodeName, const FMVector3& value, const FCDTextureList& textureBucket) const;
xmlNode* WriteFloatTextureParameterToXML(xmlNode* parentNode, const char* parameterNodeName, const float& value, const FCDTextureList& textureBucket) const;
xmlNode* WriteTextureParameterToXML(xmlNode* parentNode, const FCDTextureList& textureBucket) const;
FUStatus ParseColorTextureParameter(xmlNode* parameterNode, FMVector3& value, FCDTextureList& textureBucket);
FUStatus ParseFloatTextureParameter(xmlNode* parameterNode, float& value, FCDTextureList& textureBucket);
FUStatus ParseSimpleTextureParameter(xmlNode* parameterNode, FCDTextureList& textureBucket);
};
#endif //_FCD_MATERIAL_STANDARD_H_

View File

@@ -0,0 +1,254 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDocument.h"
#include "FCDocument/FCDEffectCode.h"
#include "FCDocument/FCDEffectPass.h"
#include "FCDocument/FCDEffectProfileFX.h"
#include "FCDocument/FCDEffectParameter.h"
#include "FCDocument/FCDEffectParameterFactory.h"
#include "FCDocument/FCDEffectParameterList.h"
#include "FCDocument/FCDEffectTechnique.h"
#include "FCDocument/FCDLibrary.h"
#include "FCDocument/FCDImage.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDEffectTechnique::FCDEffectTechnique(FCDocument* document, FCDEffectProfileFX *_parent) : FCDObject(document, "FCDEffectTechnique")
{
parent = _parent;
parameters = new FCDEffectParameterList(GetDocument(), true);;
}
FCDEffectTechnique::~FCDEffectTechnique()
{
CLEAR_POINTER_VECTOR(codes);
CLEAR_POINTER_VECTOR(passes);
SAFE_DELETE(parameters);
parent = NULL;
}
// Adds a new pass to this effect technique.
FCDEffectPass* FCDEffectTechnique::AddPass()
{
FCDEffectPass* pass = new FCDEffectPass(GetDocument(), this);
passes.push_back(pass);
return pass;
}
// Releases a pass contaied within this effect technique.
void FCDEffectTechnique::ReleasePass(FCDEffectPass* pass)
{
FCDEffectPassList::iterator it = std::find(passes.begin(), passes.end(), pass);
if (it != passes.end())
{
delete *it;
passes.erase(it);
}
}
// Adds a new code inclusion to this effect profile.
FCDEffectCode* FCDEffectTechnique::AddCode()
{
FCDEffectCode* code = new FCDEffectCode(GetDocument());
codes.push_back(code);
return code;
}
// Releases a code inclusion contained within this effect profile.
void FCDEffectTechnique::ReleaseCode(FCDEffectCode* code)
{
FCDEffectCodeList::iterator itC = std::find(codes.begin(), codes.end(), code);
if (itC != codes.end())
{
delete *itC;
codes.erase(itC);
}
}
FCDEffectTechnique* FCDEffectTechnique::Clone(FCDEffectProfileFX* newParent)
{
FCDEffectTechnique* clone = new FCDEffectTechnique(GetDocument(), newParent);
clone->name = name;
SAFE_DELETE(clone->parameters);
clone->parameters = parameters->Clone();
// Clone the codes: need to happen before the passes are cloned
clone->codes.reserve(codes.size());
for (FCDEffectCodeList::const_iterator itC = codes.begin(); itC != codes.end(); ++itC)
{
clone->codes.push_back((*itC)->Clone());
}
// Clone the passes
for (FCDEffectPassList::iterator itP = passes.begin(); itP != passes.end(); ++itP)
{
clone->passes.push_back((*itP)->Clone(clone));
}
return clone;
}
const string& FCDEffectTechnique::GetDaeId() const
{
return parent->GetDaeId();
}
void FCDEffectTechnique::AddParameter(FCDEffectParameter* parameter)
{
parameters->push_back(parameter);
}
// Flatten this effect technique: merge the parameter modifiers and generators
void FCDEffectTechnique::Flatten()
{
for (FCDEffectParameterList::iterator itP = parameters->begin(); itP != parameters->end();)
{
FCDEffectParameterList generators(GetDocument());
if ((*itP)->IsModifier())
{
// Overwrite the generators
FindParametersByReference((*itP)->GetReference(), generators);
for (FCDEffectParameterList::iterator itQ = generators.begin(); itQ != generators.end(); ++itQ)
{
if ((*itQ)->IsGenerator())
{
(*itP)->Overwrite(*itQ);
}
}
SAFE_DELETE(*itP);
parameters->erase(itP);
}
else
{
++itP;
}
}
}
FUStatus FCDEffectTechnique::LoadFromXML(xmlNode* techniqueNode, xmlNode* profileNode)
{
FUStatus status;
if (!IsEquivalent(techniqueNode->name, DAE_TECHNIQUE_ELEMENT))
{
return status.Warning(FS("Technique contains unknown element."), techniqueNode->line);
}
string techniqueName = ReadNodeProperty(techniqueNode, DAE_SID_ATTRIBUTE);
name = TO_FSTRING(techniqueName);
// Look for the pass and parameter elements
SAFE_DELETE(parameters);
parameters = new FCDEffectParameterList(GetDocument(), true);
for (xmlNode* child = techniqueNode->children; child != NULL; child = child->next)
{
if (child->type != XML_ELEMENT_NODE) continue;
if (IsEquivalent(child->name, DAE_PASS_ELEMENT))
{
FCDEffectPass* pass = AddPass();
status.AppendStatus(pass->LoadFromXML(child, techniqueNode, profileNode));
}
else if (IsEquivalent(child->name, DAE_FXCMN_NEWPARAM_ELEMENT) || IsEquivalent(child->name, DAE_FXCMN_SETPARAM_ELEMENT))
{
AddParameter(FCDEffectParameterFactory::LoadFromXML(GetDocument(), child, &status));
}
else if (IsEquivalent(child->name, DAE_FXCMN_CODE_ELEMENT) || IsEquivalent(child->name, DAE_FXCMN_INCLUDE_ELEMENT))
{
FCDEffectCode* code = new FCDEffectCode(GetDocument());
codes.push_back(code);
status.AppendStatus(code->LoadFromXML(child));
}
else if (IsEquivalent(child->name, DAE_IMAGE_ELEMENT))
{
FCDImage* image = GetDocument()->GetImageLibrary()->AddEntity();
status.AppendStatus(image->LoadFromXML(child));
}
}
return status;
}
// Write out the effect techniques to the COLLADA xml node tree
xmlNode* FCDEffectTechnique::WriteToXML(xmlNode* parentNode) const
{
xmlNode* techniqueNode = AddChild(parentNode, DAE_TECHNIQUE_ELEMENT);
const_cast<FCDEffectTechnique*>(this)->name = TO_FSTRING(AddNodeSid(techniqueNode, !name.empty() ? TO_STRING(name).c_str() : "common"));
// Write out the code/includes
for (FCDEffectCodeList::const_iterator itC = codes.begin(); itC != codes.end(); ++itC)
{
(*itC)->WriteToXML(techniqueNode);
}
// Write out the effect parameters at this level
for (FCDEffectParameterList::const_iterator itP = parameters->begin(); itP != parameters->end(); ++itP)
{
(*itP)->WriteToXML(techniqueNode);
}
// Write out the passes.
// In COLLADA 1.4: there should always be at least one pass.
if (!passes.empty())
{
for (FCDEffectPassList::const_iterator itP = passes.begin(); itP != passes.end(); ++itP)
{
(*itP)->WriteToXML(techniqueNode);
}
}
else
{
UNUSED(xmlNode* dummyPassNode =) AddChild(techniqueNode, DAE_PASS_ELEMENT);
}
return techniqueNode;
}
// Look for the parameter with the given reference.
const FCDEffectParameter* FCDEffectTechnique::FindParameter(const char* ref) const
{
return parameters->FindReference(ref);
}
// Look for the effect parameter with the correct semantic, in order to bind/set its value
FCDEffectParameter* FCDEffectTechnique::FindParameterBySemantic(const string& semantic)
{
return parameters->FindSemantic(semantic);
}
void FCDEffectTechnique::FindParametersBySemantic(const string& semantic, FCDEffectParameterList& _parameters)
{
for (FCDEffectParameterList::iterator it = parameters->begin(); it != parameters->end(); ++it)
{
if ((*it)->GetSemantic() == semantic) _parameters.push_back(*it);
}
}
void FCDEffectTechnique::FindParametersByReference(const string& reference, FCDEffectParameterList& _parameters)
{
for (FCDEffectParameterList::iterator it = parameters->begin(); it != parameters->end(); ++it)
{
if ((*it)->GetReference() == reference) _parameters.push_back(*it);
}
}
FCDEffectCode* FCDEffectTechnique::FindCode(const string& sid)
{
for (FCDEffectCodeList::iterator itC = codes.begin(); itC != codes.end(); ++itC)
{
if ((*itC)->GetSid() == sid) return (*itC);
}
return NULL;
}
const FCDEffectCode* FCDEffectTechnique::FindCode(const string& sid) const
{
for (FCDEffectCodeList::const_iterator itC = codes.begin(); itC != codes.end(); ++itC)
{
if ((*itC)->GetSid() == sid) return (*itC);
}
return NULL;
}

View File

@@ -0,0 +1,195 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
/**
@file FCDEffectTechnique.h
This file declares the FCDEffectTechnique class.
*/
#ifndef _FCD_EFFECT_TECHNIQUE_H_
#define _FCD_EFFECT_TECHNIQUE_H_
#include "FCDocument/FCDObject.h"
class FCDEffectCode;
class FCDEffectPass;
class FCDEffectParameter;
class FCDEffectParameterList;
class FCDEffectProfileFX;
typedef vector<FCDEffectPass*> FCDEffectPassList; /**< A dynamically-sized array of effect passes. */
typedef vector<FCDEffectCode*> FCDEffectCodeList; /**< A dynamically-sized array of effect code inclusions. */
/**
A COLLADA effect technique.
The COLLADA effect technique contains the passes to be used in the rendering of
polygon sets.
It also contains a list of effect parameters: both generators and overrides
and it is the lowest level of abstraction in which you can access effect parameters. For
flattened materials, this means that all the effect parameters will be accessible at this level.
It also contains a list of effect code inclusions.
@ingroup FCDEffect
*/
class FCOLLADA_EXPORT FCDEffectTechnique : public FCDObject
{
private:
FCDEffectProfileFX* parent;
fstring name;
FCDEffectCodeList codes;
FCDEffectPassList passes;
FCDEffectParameterList* parameters;
public:
/** Constructor: do not use directly.
Instead, use the FCDEffectProfileFX::AddTechnique function.
@param document The COLLADA document which owns this technique.
@param _parent The effect profile which contains the technique. */
FCDEffectTechnique(FCDocument* document, FCDEffectProfileFX *_parent);
/** Destructor: do not use directly.
Instead, use the FCDEffectProfileFX::ReleaseTechnique function. */
virtual ~FCDEffectTechnique();
/** Retrieves the effect profile that contains this technique.
@return The parent effect profile. */
FCDEffectProfileFX* GetParent() { return parent; }
const FCDEffectProfileFX* GetParent() const { return parent; } /**< See above. */
/** Retrieves the COLLADA id of the parent effect.
This function is mostly useful as a shortcut for debugging and reporting.
@return The COLLADA id of the parent effect. */
const string& GetDaeId() const;
/** Retrieves the sub-id of the technique.
@return The sub-id of the technique. */
const fstring& GetName() const { return name; }
/** Sets the sub-id of the technique.
The effect technique must have a valid sub-id that is unique
within its scope. Otherwise, one will be provided on XML export.
@param _name A valid sub-id. */
void SetName(const fstring& _name) { name = _name; }
/** Retrieves the list of passes.
@return The list of passes. */
FCDEffectPassList& GetPassList() { return passes; }
const FCDEffectPassList& GetPassList() const { return passes; } /**< See above. */
/** Retrieves the number of passes contained within this effect technique.
@return The number of passes. */
size_t GetPassCount() const { return passes.size(); }
/** Retrieves a specific pass contained within this effect technique.
@param index The index of the pass.
@return The pass. This pointer will be NULL if the index is out-of-bounds. */
FCDEffectPass* GetPass(size_t index) { FUAssert(index < GetPassCount(), return NULL); return passes.at(index); }
const FCDEffectPass* GetPass(size_t index) const { FUAssert(index < GetPassCount(), return NULL); return passes.at(index); } /**< See above. */
/** Adds a new pass to this effect technique.
@return The new pass. */
FCDEffectPass* AddPass();
/** Releases a pass contaied within this effect technique.
@param pass The pass to release. */
void ReleasePass(FCDEffectPass* pass);
/** Retrieves the list of code inclusions.
@return The list of code inclusions. */
FCDEffectCodeList& GetCodeList() { return codes; }
const FCDEffectCodeList& GetCodeList() const { return codes; } /**< See above. */
/** Retrieves the number of code inclusions contained within the effect profile.
@return The number of code inclusions. */
size_t GetCodeCount() const { return codes.size(); }
/** Retrieves a code inclusion contained within the effect profile.
@param index The index of the code inclusion.
@return The code inclusion. This pointer will be NULL if the index is out-of-bounds. */
FCDEffectCode* GetCode(size_t index) { FUAssert(index < GetCodeCount(), return NULL); return codes.at(index); }
const FCDEffectCode* GetCode(size_t index) const { FUAssert(index < GetCodeCount(), return NULL); return codes.at(index); } /**< See above. */
/** Retrieves the code inclusion with the given sub-id.
@param sid A COLLADA sub-id.
@return The code inclusion with the given sub-id. This pointer will be NULL,
if there are no code inclusions that match the given sub-id. */
FCDEffectCode* FindCode(const string& sid);
const FCDEffectCode* FindCode(const string& sid) const; /**< See above. */
/** Adds a new code inclusion to this effect profile.
@return The new code inclusion. */
FCDEffectCode* AddCode();
/** Releases a code inclusion contained within this effect profile.
@param code The code inclusion to release. */
void ReleaseCode(FCDEffectCode* code);
/** Retrieves the list of effect parameters contained within the effect profile.
This is the lowest level of abstraction and may contain either effect parameter
generators or effect parameter overrides.
@return The list of effect parameters. */
FCDEffectParameterList* GetParameterList() { return parameters; }
const FCDEffectParameterList* GetParameterList() const { return parameters; } /**< See above. */
/** [INTERNAL] Inserts an existing parameter into the list of effect parameters
at this abstraction level. This function is used during the flattening of a material.
@param parameter The effect parameter to insert. */
void AddParameter(FCDEffectParameter* parameter);
/** Retrieves an effect parameter.
Looks for the effect parameter with the correct reference, in order to bind or override its value.
@param reference The reference to match. In the case of effect parameter generators,
the sub-id is used to match.
@return The first effect parameter that matches the reference.
This pointer will be NULL if no effect parameter matches the given semantic. */
const FCDEffectParameter* FindParameter(const char* reference) const;
/** Retrieves an effect parameter.
Looks for the effect parameter with the correct semantic, in order to bind or override its value.
@param semantic The effect parameter semantic to match.
@return The first effect parameter that matches the semantic.
This pointer will be NULL if no effect parameter matches the given semantic. */
virtual FCDEffectParameter* FindParameterBySemantic(const string& semantic);
/** Retrieves a subset of the effect parameter list.
Look for the effect parameter generators with the correct semantic.
@param semantic The effect parameter semantic to match.
@param parameters The list of parameters to fill in. This list is not cleared. */
virtual void FindParametersBySemantic(const string& semantic, FCDEffectParameterList& parameters);
/** Retrieves a subset of the effect parameter list.
Look for the effect parameter generators with the correct reference.
@param reference The effect parameter reference to match. In the case of effect
parameter generators, the reference is replaced by the sub-id.
@param parameters The list of parameters to fill in. This list is not cleared. */
virtual void FindParametersByReference(const string& reference, FCDEffectParameterList& parameters);
/** [INTERNAL] Clones the full effect technique.
@param newParent The effect profile that will contain the cloned technique.
@return The cloned technique. This pointer will never be NULL. */
FCDEffectTechnique* Clone(FCDEffectProfileFX* newParent);
/** [INTERNAL] Flattens this effect technique.
Merges the parameter overrides into the parameter generators. */
void Flatten();
/** [INTERNAL] Reads in the effect technique from a given COLLADA XML tree node.
@param techniqueNode The COLLADA XML tree node.
@param profileNode X @deprecated bad interface : this dependency must be taken out.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the effect technique.*/
FUStatus LoadFromXML(xmlNode* techniqueNode, xmlNode* profileNode);
/** [INTERNAL] Writes out the effect technique to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the effect technique.
@return The created element XML tree node. */
xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif

View File

@@ -0,0 +1,127 @@
/*
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/FCDEntity.h"
#include "FCDocument/FCDExtra.h"
#include "FCDocument/FCDSceneNode.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
#include "FUtils/FUUniqueStringMap.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDEntity::FCDEntity(FCDocument* document, const char* baseId) : FCDObjectWithId(document, baseId)
{
extra = new FCDExtra(document);
}
FCDEntity::~FCDEntity()
{
SAFE_DELETE(extra);
}
// Structure cloning
void FCDEntity::Clone(FCDEntity* clone)
{
FCDObjectWithId::Clone(clone);
clone->name = name;
clone->note = note;
}
void FCDEntity::SetName(const fstring& _name)
{
name = CleanName(_name);
}
// Parse this entity information from the COLLADA XML document
FUStatus FCDEntity::LoadFromXML(xmlNode* entityNode)
{
FUStatus status;
string fileId = FUDaeParser::ReadNodeId(entityNode);
if (!fileId.empty()) SetDaeId(fileId);
else RemoveDaeId();
name = TO_FSTRING(FUDaeParser::ReadNodeName(entityNode));
if (name.empty()) name = TO_FSTRING(fileId);
xmlNode* extraNode = FindChildByType(entityNode, DAE_EXTRA_ELEMENT);
if (extraNode != NULL)
{
extra->LoadFromXML(extraNode);
// Look for an extra node at this level and a Max/Maya-specific technique
FCDETechnique* mayaTechnique = extra->FindTechnique(DAEMAYA_MAYA_PROFILE);
FCDETechnique* maxTechnique = extra->FindTechnique(DAEMAX_MAX_PROFILE);
// Read in all the extra parameters
StringList parameterNames;
FCDENodeList parameterNodes;
if (mayaTechnique != NULL) mayaTechnique->FindParameters(parameterNodes, parameterNames);
if (maxTechnique != NULL) maxTechnique->FindParameters(parameterNodes, parameterNames);
// Look for the note and user-properties, which is the only parameter currently supported at this level
size_t parameterCount = parameterNodes.size();
for (size_t i = 0; i < parameterCount; ++i)
{
FCDENode* parameterNode = parameterNodes[i];
const string& parameterName = parameterNames[i];
if (parameterName == DAEMAX_USERPROPERTIES_NODE_PARAMETER || parameterName == DAEMAYA_NOTE_PARAMETER
|| parameterName == DAEMAX_USERPROPERTIES_NODE_PARAMETER1_3 || parameterName == DAEMAYA_MAYA_NOTE_PARAMETER1_3)
{
note = parameterNode->GetContent();
parameterNode->Release();
}
}
}
return status;
}
// Look for a children with the given COLLADA Id.
FCDEntity* FCDEntity::FindDaeId(const string& _daeId)
{
if (GetDaeId() == _daeId) return this;
return NULL;
}
xmlNode* FCDEntity::WriteToXML(xmlNode* parentNode) const
{
return WriteToEntityXML(parentNode, DAEERR_UNKNOWN_ELEMENT);
}
xmlNode* FCDEntity::WriteToEntityXML(xmlNode* parentNode, const char* nodeName) const
{
// Create the entity node and write out the id and name attributes
xmlNode* entityNode = AddChild(parentNode, nodeName);
AddAttribute(entityNode, DAE_ID_ATTRIBUTE, GetDaeId());
if (!name.empty())
{
AddAttribute(entityNode, DAE_NAME_ATTRIBUTE, name);
}
return entityNode;
}
void FCDEntity::WriteToExtraXML(xmlNode* entityNode) const
{
// Write out the note
if (HasNote())
{
xmlNode* techniqueNode = AddExtraTechniqueChild(entityNode, DAEMAX_MAX_PROFILE);
AddChild(techniqueNode, DAEMAX_USERPROPERTIES_NODE_PARAMETER, note);
}
// Write out the user-defined extra information.
extra->WriteToXML(entityNode);
}

View File

@@ -0,0 +1,189 @@
/*
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
*/
/**
@file FCDEntity.h
This file contains the FCDEntity class.
*/
#ifndef _FCD_ENTITY_H_
#define _FCD_ENTITY_H_
#include "FCDocument/FCDObject.h"
class FCDocument;
class FCDExtra;
/**
A COLLADA entity.
A COLLADA entity is an object contained within a COLLADA library.
As such, it is based on the FCDObjectWithId class so that it
can be accessed by other entities, such as the scene graph.
The entity adds to the FCDObjectWithId class: a name,
an extra tree and an optional note, as well as a way
to identity the type of the entity, in order to up-cast it
to its correct class.
@ingroup FCDocument
*/
class FCOLLADA_EXPORT FCDEntity : public FCDObjectWithId
{
public:
/** The types of entity classes.
Each type corresponds directly to one class that contains the
FCDEntity class as a parent, so you can up-cast FCDEntity pointers. */
enum Type
{
ENTITY, /**< A generic entity (FCDEntity). Should never be used. */
ANIMATION, /**< An animation (FCDAnimation). */
ANIMATION_CLIP, /**< An animation clip (FCDAnimationClip). */
CAMERA, /**< A camera (FCDCamera). */
LIGHT, /**< A light (FCDLight). */
IMAGE, /**< An image (FCDImage). */
TEXTURE, /**< A texture (FCDTexture). Used for COLLADA 1.3 backward compatibility only! */
MATERIAL, /**< A visual material definition (FCDMaterial). */
EFFECT, /**< An effect definition (FCDEffect). */
GEOMETRY, /**< A geometric object (FCDGeometry). Includes splines and meshes. */
CONTROLLER, /**< A geometric controller (FCDController). Includes skins and morphers. */
SCENE_NODE, /**< A visual scene node (FCDSceneNode). */
PHYSICS_RIGID_CONSTRAINT, /**< A physics rigid constraint (FCDPhysicsRigidConstraint). */
PHYSICS_MATERIAL, /**< A physics material definiton (FCDPhysicsMaterial). */
PHYSICS_RIGID_BODY, /**< A physics rigid body (FCDPhysicsRigidBody). */
PHYSICS_SHAPE, /**< A physics shape (FCDPhysicsShape). */
PHYSICS_ANALYTICAL_GEOMETRY, /**< A physics analytical geometric object (FCDPhysicsAnalyticalGeometry). */
PHYSICS_MODEL, /**< A physics model (FCDPhysicsModel). */
PHYSICS_SCENE_NODE /**< A physics scene node (FCDPhysicsSceneNode). */
};
private:
fstring name;
// Extra information for the entity.
FCDExtra* extra;
// Maya and Max both support custom strings for objects.
fstring note;
// Deprecated ColladaMaya post-processing information.
StringList postCmds;
public:
/** Constructor: do not use directly.
Instead, create objects of the up-classes.
@param document The COLLADA document that owns the entity.
@param baseId The prefix COLLADA id to be used if no COLLADA id is provided. */
FCDEntity(FCDocument* document, const char* baseId = "GenericEntity");
/** Destructor: do not use directly.
Instead, release objects through their libraries or their parent entities. */
virtual ~FCDEntity();
/** Retrieves the entity class type for an entity.
You can use the entity class type of up-cast an entity pointer
to the correct up-class.
This function should be overwritten by all up-classes.
@return The entity class type. */
virtual Type GetType() const { return ENTITY; }
/** Retrieves the name of the entity.
This value has no direct use in COLLADA but is useful
to track the user-friendly name of an entity.
@return The name. */
const fstring& GetName() const { return name; }
/** Sets the name of the entity.
This value has no direct use in COLLADA but is useful
to track the user-friendly name of an entity.
@param _name The name. */
void SetName(const fstring& _name);
/** Retrieves the extra information tree for this entity.
The prefered way to save extra information in FCollada is at
the entity level. Use this extra information tree to store
any information you want exported and imported back.
@return The extra information tree. */
FCDExtra* GetExtra() { return extra; }
const FCDExtra* GetExtra() const { return extra; } /**< See above. */
/** Retrieves whether the entity has a user-defined note.
This value is a simpler way, than the extra tree, to store
user-defined information that does not belong in COLLADA.
@return Whether the entity has an user-defined note. */
bool HasNote() const { return !note.empty(); }
/** Retrieves the user-defined note for this entity.
This value is a simpler way, than the extra tree, to store
user-defined information that does not belong in COLLADA.
@return The user-defined note. */
const fstring& GetNote() const { return note; }
/** Sets the user-defined note for this entity.
This value is a simpler way, than the extra tree, to store
user-defined information that does not belong in COLLADA.
@param _note The user-defined note. */
void SetNote(const fstring& _note) { note = _note; }
/** Retrieves the child entity that has the given COLLADA id.
This function is only useful for entities that are hierarchical:
visual/physics scene nodes and animations.
@param daeId A COLLADA id.
@return The child entity with the given id. This pointer will be NULL
if no child entity matches the given id. */
virtual FCDEntity* FindDaeId(const string& daeId);
/** [INTERNAL] Reads in the entity from a given COLLADA XML tree node.
This function should be overwritten by all up-classes.
@param entityNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the entity.*/
virtual FUStatus LoadFromXML(xmlNode* entityNode);
/** [INTERNAL] Writes out the entity to the given COLLADA XML tree node.
This function should be overwritten by all up-classes.
@param parentNode The COLLADA XML parent node in which to insert the entity.
@return The created element XML tree node. */
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
/** @deprecated Retrieves the like of post-processing commands.
Used only in ColladaMaya and should be taken out.
@return The list of post-processing commands. */
StringList& GetPostProcessCmds() { return postCmds; }
protected:
/** [INTERNAL] Writes out the top entity XML node for the entity.
This function should be used by all up-classes within the
WriteToXML overwritting function to create the top XML node,
as it will write out the name and COLLADA id of the entity.
@param parentNode The COLLADA XML parent node in which to insert the entity.
@param nodeName The COLLADA XML node name for the top entity XML node.
@return The created element XML tree node. */
xmlNode* WriteToEntityXML(xmlNode* parentNode, const char* nodeName) const;
/** [INTERNAL] Writes out the extra information for the entity.
This function should be used by all up-classes within the
WriteToXML overwritting function, at the very end, to write
the user-defined note and the extra tree to the COLLADA document.
@param entityNode The created element XML tree node returned
by the WriteToEntityXML function. */
void WriteToExtraXML(xmlNode* entityNode) const;
/** [INTERNAL] Copies the entity information into a cloned entity.
This function should be used by all up-classes when cloning an entity
to copy the COLLADA id and the other entity-level information into a clone.
@param clone The cloned entity. */
void Clone(FCDEntity* clone);
};
#endif // _FCD_ENTITY_H_

View File

@@ -0,0 +1,44 @@
/*
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
*/
#ifndef _FCD_ENTITY_INSTANCE_H_
#define _FCD_ENTITY_INSTANCE_H_
class FCDocument;
class FCDEntity;
#include "FCDocument/FCDObject.h"
class FCOLLADA_EXPORT FCDEntityInstance : public FCDObject
{
public:
enum Type { SIMPLE, EXTERNAL_REFERENCE, GEOMETRY, MATERIAL, PHYSICS_MODEL, PHYSICS_RIGID_BODY, PHYSICS_RIGID_CONSTRAINT };
protected:
FCDEntity* entity;
public:
FCDEntityInstance(FCDocument* document, FCDEntity* _entity = NULL) : FCDObject(document, "FCDEntityInstance") { entity = _entity; }
virtual ~FCDEntityInstance() { entity = NULL; }
// Accessors
FCDEntity* GetEntity() { return entity; }
const FCDEntity* GetEntity() const { return entity; }
virtual Type GetType() const { return SIMPLE; }
// Load the per-instance information from the xml node tree
virtual FUStatus LoadFromXML(xmlNode* UNUSED(instanceNode)) { return FUStatus(true); }
// Write out the instantiation information to the xml node tree
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif // _FCD_ENTITY_INSTANCE_H_

View File

@@ -0,0 +1,37 @@
/*
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
*/
#ifndef _FCD_XREF_ENTITY_H_
#define _FCD_XREF_ENTITY_H_
#include "FCDocument/FCDEntityInstance.h"
#include "FUtils/FUStringConversion.h"
#include "FUtils/FUUri.h"
class FCOLLADA_EXPORT FCDExternalReference : public FCDEntityInstance
{
private:
FUUri uri;
public:
FCDExternalReference(FCDocument* document, const FUUri& _uri) : FCDEntityInstance(document) { uri = _uri; }
virtual ~FCDExternalReference() {}
// FCDEntity override for RTTI-like
virtual Type GetType() const { return EXTERNAL_REFERENCE; }
// Accessors
const FUUri& GetUri() const { return uri; }
const fstring& GetFilename() const { return uri.prefix; }
fstring GetObjectName() const { return TO_FSTRING(uri.suffix); }
};
#endif // _FCD_XREF_ENTITY_H_

View File

@@ -0,0 +1,366 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDocument.h"
#include "FCDocument/FCDAnimated.h"
#include "FCDocument/FCDExtra.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDExtra::FCDExtra(FCDocument* document) : FCDObject(document, "FCDExtra")
{
}
FCDExtra::~FCDExtra()
{
CLEAR_POINTER_VECTOR(techniques);
}
// Adds a technique of the given profile (or return the existing technique with this profile).
FCDETechnique* FCDExtra::AddTechnique(const char* profile)
{
FCDETechnique* technique = FindTechnique(profile);
if (technique == NULL)
{
technique = new FCDETechnique(GetDocument(), profile);
techniques.push_back(technique);
}
return technique;
}
// Releases a technique contained within the extra tree.
void FCDExtra::ReleaseTechnique(FCDETechnique* technique)
{
FCDETechniqueList::iterator it = std::find(techniques.begin(), techniques.end(), technique);
if (it != techniques.end())
{
delete (*it);
techniques.erase(it);
}
}
// Search for a profile-specific technique
FCDETechnique* FCDExtra::FindTechnique(const char* profile)
{
for (FCDETechniqueList::iterator itT = techniques.begin(); itT != techniques.end(); ++itT)
{
if (IsEquivalent((*itT)->GetProfile(), profile)) return *itT;
}
return NULL;
}
const FCDETechnique* FCDExtra::FindTechnique(const char* profile) const
{
for (FCDETechniqueList::const_iterator itT = techniques.begin(); itT != techniques.end(); ++itT)
{
if (IsEquivalent((*itT)->GetProfile(), profile)) return *itT;
}
return NULL;
}
// Search for a root node with a specific element name
FCDENode* FCDExtra::FindRootNode(const char* name)
{
FCDENode* rootNode = NULL;
for (FCDETechniqueList::iterator itT = techniques.begin(); itT != techniques.end(); ++itT)
{
rootNode = (*itT)->FindChildNode(name);
if (rootNode != NULL) break;
}
return rootNode;
}
const FCDENode* FCDExtra::FindRootNode(const char* name) const
{
FCDENode* rootNode = NULL;
for (FCDETechniqueList::const_iterator itT = techniques.begin(); itT != techniques.end(); ++itT)
{
rootNode = (*itT)->FindChildNode(name);
if (rootNode != NULL) break;
}
return rootNode;
}
// Read in/Write to a COLLADA xml document
FUStatus FCDExtra::LoadFromXML(xmlNode* extraNode)
{
FUStatus status;
// Read in the techniques
xmlNodeList techniqueNodes;
FindChildrenByType(extraNode, DAE_TECHNIQUE_ELEMENT, techniqueNodes);
for (xmlNodeList::iterator itN = techniqueNodes.begin(); itN != techniqueNodes.end(); ++itN)
{
xmlNode* techniqueNode = (*itN);
FCDETechnique* technique = AddTechnique(ReadNodeProperty(techniqueNode, DAE_PROFILE_ATTRIBUTE));
status.AppendStatus(technique->LoadFromXML(techniqueNode));
}
return status;
}
xmlNode* FCDExtra::WriteToXML(xmlNode* parentNode) const
{
if (techniques.empty()) return NULL;
// Add the <extra> element and its techniques
xmlNode* extraNode = AddChildOnce(parentNode, DAE_EXTRA_ELEMENT);
for (FCDETechniqueList::const_iterator itT = techniques.begin(); itT != techniques.end(); ++itT)
{
(*itT)->WriteToXML(extraNode);
}
return extraNode;
}
FCDENode::FCDENode(FCDocument* document, FCDENode* _parent) : FCDObject(document, "FCDENode")
{
parent = _parent;
animated = NULL;
}
FCDENode::~FCDENode()
{
GetDocument()->UnregisterAnimatedValue(animated);
SAFE_DELETE(animated);
parent = NULL;
CLEAR_POINTER_VECTOR(children);
CLEAR_POINTER_VECTOR(attributes);
}
void FCDENode::Release()
{
if (parent != NULL)
{
parent->ReleaseChildNode(this);
}
// Otherwise, we have a technique so don't release
}
void FCDENode::SetContent(const fchar* _content)
{
// As COLLADA doesn't allow for mixed content, release all the children.
while (!children.empty())
{
children.back()->Release();
}
content = _content;
}
// Search for a children with a specific name
FCDENode* FCDENode::FindChildNode(const char* name)
{
for (FCDENodeList::iterator itN = children.begin(); itN != children.end(); ++itN)
{
if (IsEquivalent((*itN)->GetName(), name)) return (*itN);
}
return NULL;
}
const FCDENode* FCDENode::FindChildNode(const char* name) const
{
for (FCDENodeList::const_iterator itN = children.begin(); itN != children.end(); ++itN)
{
if (IsEquivalent((*itN)->GetName(), name)) return (*itN);
}
return NULL;
}
// Adds a new child node
FCDENode* FCDENode::AddChildNode()
{
FCDENode* node = new FCDENode(GetDocument(), this);
children.push_back(node);
return node;
}
// Releases a child node
void FCDENode::ReleaseChildNode(FCDENode* childNode)
{
FCDENodeList::iterator itN = std::find(children.begin(), children.end(), childNode);
if (itN != children.end())
{
delete (*itN);
children.erase(itN);
}
}
FCDENode* FCDENode::FindParameter(const char* name)
{
for (FCDENodeList::iterator itN = children.begin(); itN != children.end(); ++itN)
{
FCDENode* node = (*itN);
if (IsEquivalent(node->GetName(), name)) return node;
else if (IsEquivalent(node->GetName(), DAE_PARAMETER_ELEMENT))
{
FCDEAttribute* nameAttribute = node->FindAttribute(DAE_NAME_ATTRIBUTE);
if (nameAttribute != NULL && nameAttribute->value == TO_FSTRING(name)) return node;
}
}
return NULL;
}
void FCDENode::FindParameters(FCDENodeList& nodes, StringList& names)
{
for (FCDENodeList::iterator itN = children.begin(); itN != children.end(); ++itN)
{
FCDENode* node = (*itN);
if (node->GetChildNodeCount() > 1) continue;
if (IsEquivalent(node->GetName(), DAE_PARAMETER_ELEMENT))
{
FCDEAttribute* nameAttribute = node->FindAttribute(DAE_NAME_ATTRIBUTE);
if (nameAttribute != NULL)
{
nodes.push_back(node);
names.push_back(FUStringConversion::ToString(nameAttribute->value));
}
}
else
{
nodes.push_back(node);
names.push_back(node->GetName());
}
}
}
// Adds a new attribute to this extra tree node.
FCDEAttribute* FCDENode::AddAttribute(const char* _name, const fchar* _value)
{
FCDEAttribute* attribute = FindAttribute(_name);
if (attribute == NULL)
{
attribute = new FCDEAttribute();
attribute->name = _name;
attributes.push_back(attribute);
}
attribute->value = _value;
return attribute;
}
// Releases an attribute
void FCDENode::ReleaseAttribute(FCDEAttribute* attribute)
{
FCDEAttributeList::iterator it = std::find(attributes.begin(), attributes.end(), attribute);
if (it != attributes.end())
{
delete *it;
attributes.erase(it);
}
}
// Search for an attribute with a specific name
FCDEAttribute* FCDENode::FindAttribute(const char* name)
{
for (FCDEAttributeList::iterator itA = attributes.begin(); itA != attributes.end(); ++itA)
{
if ((*itA)->name == name) return (*itA);
}
return NULL;
}
const FCDEAttribute* FCDENode::FindAttribute(const char* name) const
{
for (FCDEAttributeList::const_iterator itA = attributes.begin(); itA != attributes.end(); ++itA)
{
if ((*itA)->name == name) return (*itA);
}
return NULL;
}
// Read in this extra node from a COLLADA xml document
FUStatus FCDENode::LoadFromXML(xmlNode* customNode)
{
FUStatus status;
// Read in the node's name and children
name = (const char*) customNode->name;
ReadChildrenFromXML(customNode);
// If there are no child nodes, we have a tree leaf: parse in the content and its animation
content = (children.empty()) ? TO_FSTRING(ReadNodeContentDirect(customNode)) : FS("");
animated = FCDAnimatedCustom::Create(GetDocument(), customNode);
// Read in the node's attributes
for (xmlAttr* a = customNode->properties; a != NULL; a = a->next)
{
AddAttribute((const char*) a->name, (a->children != NULL) ? TO_FSTRING((const char*) (a->children->content)) : FS(""));
}
return status;
}
// Write out this extra to a COLLADA xml document
xmlNode* FCDENode::WriteToXML(xmlNode* parentNode) const
{
xmlNode* customNode = AddChild(parentNode, name.c_str(), content);
// Write out the attributes
for (FCDEAttributeList::const_iterator itA = attributes.begin(); itA != attributes.end(); ++itA)
{
const FCDEAttribute* attribute = (*itA);
FUXmlWriter::AddAttribute(customNode, attribute->name.c_str(), attribute->value);
}
// Write out the children
WriteChildrenToXML(customNode);
return customNode;
}
// Read in the child nodes from the xml tree node
FUStatus FCDENode::ReadChildrenFromXML(xmlNode* customNode)
{
FUStatus status;
// Read in the node's children
for (xmlNode* k = customNode->children; k != NULL; k = k->next)
{
if (k->type != XML_ELEMENT_NODE) continue;
FCDENode* node = AddChildNode();
status.AppendStatus(node->LoadFromXML(k));
}
return status;
}
// Write out the child nodes to the xml tree node
void FCDENode::WriteChildrenToXML(xmlNode* customNode) const
{
for (FCDENodeList::const_iterator itN = children.begin(); itN != children.end(); ++itN)
{
(*itN)->WriteToXML(customNode);
}
}
FCDETechnique::FCDETechnique(FCDocument* document, const char* _profile) : FCDENode(document, NULL)
{
profile = _profile;
}
FCDETechnique::~FCDETechnique() {}
// Read in/Write to a COLLADA xml document
FUStatus FCDETechnique::LoadFromXML(xmlNode* techniqueNode)
{
FUStatus status;
// Read in only the child elements: none of the attributes
status.AppendStatus(ReadChildrenFromXML(techniqueNode));
return status;
}
xmlNode* FCDETechnique::WriteToXML(xmlNode* parentNode) const
{
// Create the technique for this profile and write out the children
xmlNode* customNode = AddTechniqueChild(parentNode, profile.c_str());
WriteChildrenToXML(customNode);
return customNode;
}

View File

@@ -0,0 +1,357 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
/**
@file FCDExtra.h
This file contains the FCDExtra class and its sub-classes:
FCDENode, FCDETechnique and FCDEAttribute.
*/
#ifndef _FCD_EXTRA_H_
#define _FCD_EXTRA_H_
#include "FCDocument/FCDObject.h"
class FCDAnimated;
class FCDAnimatedCustom;
class FCDETechnique;
class FCDENode;
/**
An extra tree attribute.
Contains a name and a value string.
*/
struct FCDEAttribute
{
string name; /**< The attribute name. Must be provided. */
fstring value; /**< The attribute value. Is optional. */
};
typedef vector<FCDETechnique*> FCDETechniqueList; /**< A dynamically-sized array of extra tree techniques. */
typedef vector<FCDENode*> FCDENodeList; /**< A dynamically-sized array of extra tree nodes. */
typedef vector<FCDEAttribute*> FCDEAttributeList; /**< A dynamically-sized array of extra tree attributes. */
/**
A COLLADA extra tree.
An extra tree contains the user-defined COLLADA information
contained within \<extra\> elements. For this, the extra tree
root simply contains a list of techniques. Each technique
belongs to a different application-specific profile.
*/
class FCOLLADA_EXPORT FCDExtra : public FCDObject
{
private:
FCDETechniqueList techniques;
public:
/** Constructor: do not use directly.
The structures that contain extra trees will create them.
@param document The COLLADA document that owns the extra tree. */
FCDExtra(FCDocument* document);
/** Destructor: do not use directly.
The structures that contain extra trees will release them. */
virtual ~FCDExtra();
/** Retrieves the list of techniques contained by this extra tree.
@return The list of techniques. */
FCDETechniqueList& GetTechniques() { return techniques; }
const FCDETechniqueList& GetTechniques() const { return techniques; } /**< See above. */
/** Retrieves the number of techniques contained by this extra tree.
@return The number of techniques. */
size_t GetTechniqueCount() const { return techniques.size(); }
/** Retrieves a specific technique contained by this extra tree.
@param index The index of the technique.
@return The technique. This pointer will be NULL if the
index is out-of-bounds. */
FCDETechnique* GetTechnique(size_t index) { FUAssert(index < techniques.size(), return NULL); return techniques.at(index); }
const FCDETechnique* GetTechnique(size_t index) const { FUAssert(index < techniques.size(), return NULL); return techniques.at(index); } /**< See above. */
/** Adds a new application-specific profile technique to the extra tree.
If the given application-specific profile already exists
within the extra tree, the old technique will be returned.
@param profile The application-specific profile name.
@return A technique for this application-specific profile. */
FCDETechnique* AddTechnique(const char* profile);
inline FCDETechnique* AddTechnique(const string& profile) { return AddTechnique(profile.c_str()); } /**< See above. */
/** Releases a technique contained within the extra tree.
@param technique The technique to release. */
void ReleaseTechnique(FCDETechnique* technique);
/** Retrieves a specific technique contained by this extra tree.
@param profile The application-specific profile name of the technique.
@return The technique that matches the profile name. This pointer may
be NULL if no technique matches the profile name. */
FCDETechnique* FindTechnique(const char* profile);
const FCDETechnique* FindTechnique(const char* profile) const; /**< See above. */
inline FCDETechnique* FindTechnique(const string& profile) { return FindTechnique(profile.c_str()); } /**< See above. */
inline const FCDETechnique* FindTechnique(const string& profile) const { return FindTechnique(profile.c_str()); } /**< See above. */
/** Retrieves the extra tree node that has a given element name.
This function searches for the extra tree node within all the
techniques.
@param name An element name.
@return The extra tree node that matches the element name. This pointer
will be NULL if no extra tree node matches the element name. */
FCDENode* FindRootNode(const char* name);
const FCDENode* FindRootNode(const char* name) const; /**< See above. */
inline FCDENode* FindRootNode(const string& name) { return FindRootNode(name.c_str()); } /**< See above. */
inline const FCDENode* FindRootNode(const string& name) const { return FindRootNode(name.c_str()); } /**< See above. */
/** [INTERNAL] Reads in the extra tree from a given COLLADA XML tree node.
@param extraNode The COLLADA \<extra\> element XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the entity.*/
FUStatus LoadFromXML(xmlNode* extraNode);
/** [INTERNAL] Writes out the extra tree to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the \<extra\> element.
@return The created element XML tree node. */
xmlNode* WriteToXML(xmlNode* parentNode) const;
};
/**
A COLLADA extra tree node.
The extra tree node is a hierarchical structure that contains child
extra tree nodes as well as attributes. If the extra tree node is a leaf
of the tree, it may contain textual content.
The extra tree node leaf may be animated, if it has the 'sid' attribute.
*/
class FCOLLADA_EXPORT FCDENode : public FCDObject
{
private:
string name;
fstring content;
FCDENode* parent;
FCDENodeList children;
FCDEAttributeList attributes;
FCDAnimatedCustom* animated;
public:
/** Constructor: do not use directly.
Instead, call the FCDENode::AddChild function of the parent within the hierarchy.
@param document The COLLADA document that owns the extra tree node.
@param parent The extra tree node that contains this extra tree node. */
FCDENode(FCDocument* document, FCDENode* parent);
/** Destructor: do not use directly.
Instead, for hierarchical nodes: call the Release function
or the parent's ReleaseChildNode function and for techniques:
call the FCDExtra::ReleaseTechnique function. */
virtual ~FCDENode();
/** Releases this extra tree node.
This function is a shortcut to the parent's FCDENode::ReleaseChildNode function. */
void Release();
/** Retrieves the name of the extra tree node.
The name of the extra tree node is the name of the equivalent XML tree node.
@return The name of the extra tree node. */
inline const char* GetName() const { return name.c_str(); }
/** Sets the name of the extra tree node.
The name of the extra tree node is the name of the equivalent XML tree node.
@param _name The name of the extra tree node. */
inline void SetName(const char* _name) { name = _name; }
inline void SetName(const string& _name) { name = _name; } /**< See above. */
/** Retrieves the textual content of the extra tree node.
This value is only valid for extra tree node that have no children,
as COLLADA doesn't allow for mixed-content.
@return The textual content of the extra tree node. */
const fchar* GetContent() const { return content.c_str(); }
/** Sets the textual content of the extra tree node.
This function will release all the child node of this extra tree node,
as COLLADA doesn't allow for mixed-content.
@param _content The textual content. */
void SetContent(const fchar* _content);
inline void SetContent(const fstring& _content) { return SetContent(_content.c_str()); } /**< See above. */
/** Retrieves the animated values associated with this extra tree node.
Extra tree node leaves may be animated. If this extra tree node leaf
is animated, this animated value will contain the animation curves.
@return The animated value. */
FCDAnimatedCustom* GetAnimated() { return animated; }
const FCDAnimatedCustom* GetAnimated() const { return animated; } /**< See above. */
/** Retrieves the parent of an extra tree node.
The hierarchy cannot be changed dynamically. If you to move an extra tree node,
you will need to clone it manually and release the old extra tree node.
@return The parent extra tree node within the hierarchy. This pointer
will be NULL if the extra tree node is a extra tree technique. */
FCDENode* GetParent() { return parent; }
const FCDENode* GetParent() const { return parent; } /**< See above. */
/** Retrieves the children of an extra tree node.
@return The list of child extra tree nodes. */
FCDENodeList& GetChildNodes() { return children; }
const FCDENodeList& GetChildNodes() const { return children; } /**< See above. */
/** Retrieves the number of children of an extra tree node.
@return The number of children. */
size_t GetChildNodeCount() const { return children.size(); }
/** Retrieves a specific child extra tree node.
@param index The index of the child extra tree node.
@return The child extra tree node. This pointer will be NULL if the index
is out-of-bounds. */
FCDENode* GetChildNode(size_t index) { FUAssert(index < children.size(), return NULL); return children.at(index); }
const FCDENode* GetChildNode(size_t index) const { FUAssert(index < children.size(), return NULL); return children.at(index); } /**< See above. */
/** Adds a new child extra tree to this extra tree node.
@return The new child extra tree node. */
FCDENode* AddChildNode();
/** Releases a child extra tree node of this extra tree node.
@param childNode The child to release. */
void ReleaseChildNode(FCDENode* childNode);
/** Retrieves the child extra tree node with the given name.
@param name A name.
@return The child extra tree node that matches the given name.
This pointer will be NULL if no child extra tree node matches
the given name. */
FCDENode* FindChildNode(const char* name);
const FCDENode* FindChildNode(const char* name) const; /**< See above. */
inline FCDENode* FindChildNode(const string& name) { return FindChildNode(name.c_str()); } /**< See above. */
inline const FCDENode* FindChildNode(const string& name) const { return FindChildNode(name.c_str()); } /**< See above. */
/** Retrieves the child extra tree node with the given name.
This function is used for COLLADA 1.3 backward compatibility,
where all parameters were described as \<param name='X'>value\</param\>.
So, if the child extra tree node with the name 'X' as searched for:
both the above COLLADA 1.3 parameter and the COLLADA 1.4+
\<X\>value\</X\> parameters will be returned.
@param name The parameter name.
@return The first child extra tree node holding the wanted parameter within the hierarchy.
This pointer will be NULL to indicate that no parameter matches the given name. */
FCDENode* FindParameter(const char* name);
/** Retrieves a list of all the parameters contained within the hierarchy.
This function is used for COLLADA 1.3 backward compatibility,
where all parameters were described as \<param name='X'>value\</param\>.
In COLLADA 1.4+, the same parameter should be described as: \<X\>value\</X\>.
Using this function, both parameters would be returned with the name 'X'.
@param nodes The list of parameters to fill in. This list is not emptied by the function.
@param names The list of names of the parameters. This list is not emptied by the function. */
void FindParameters(FCDENodeList& nodes, StringList& names);
/** Retrieves the list of attributes for this extra tree node.
@return The list of attributes. */
FCDEAttributeList& GetAttributes() { return attributes; }
const FCDEAttributeList& GetAttributes() const { return attributes; } /**< See above. */
/** Retrieves the number of attributes for this extra tree node.
@return The number of attributes. */
size_t GetAttributeCount() const { return attributes.size(); }
/** Retrieves a specific attribute of this extra tree node.
@param index The index.
@return The attribute at this index. This pointer will be NULL
if the index is out-of-bounds. */
FCDEAttribute* GetAttribute(size_t index) { FUAssert(index < attributes.size(), return NULL); return attributes.at(index); }
const FCDEAttribute* GetAttribute(size_t index) const { FUAssert(index < attributes.size(), return NULL); return attributes.at(index); } /**< See above. */
/** Adds a new attribute to this extra tree node.
If an attribute with the same name already exists, this function simply
assigns the new value to the existing attribute and returns the existing attribute.
@param _name The name of the attribute.
@param _value The value of the attribute.
@return The new attribute. */
FCDEAttribute* AddAttribute(const char* _name, const fchar* _value);
inline FCDEAttribute* AddAttribute(const string& _name, const fchar* _value) { return AddAttribute(_name.c_str(), _value); } /**< See above. */
inline FCDEAttribute* AddAttribute(const char* _name, const fstring& _value) { return AddAttribute(_name, _value.c_str()); } /**< See above. */
inline FCDEAttribute* AddAttribute(const string& _name, const fstring& _value) { return AddAttribute(_name.c_str(), _value.c_str()); } /**< See above. */
template <typename T> inline FCDEAttribute* AddAttribute(const char* _name, const T& _value) { return AddAttribute(_name, TO_FSTRING(_value)); } /**< See above. */
template <typename T> inline FCDEAttribute* AddAttribute(const string& _name, const T& _value) { return AddAttribute(_name.c_str(), TO_FSTRING(_value)); } /**< See above. */
/** Releases an attribute of this extra tree node.
@param attribute The attribute to release. */
void ReleaseAttribute(FCDEAttribute* attribute);
/** Retrieve the attribute of this extra tree node with the given name.
Attribute names are unique within an extra tree node.
@param name The attribute name.
@return The attribute that matches the name. This pointer will be NULL if
there is no attribute with the given name. */
FCDEAttribute* FindAttribute(const char* name);
const FCDEAttribute* FindAttribute(const char* name) const; /**< See above. */
/** [INTERNAL] Reads in the extra tree node from a given COLLADA XML tree node.
@param customNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the extra tree node.*/
virtual FUStatus LoadFromXML(xmlNode* customNode);
/** [INTERNAL] Writes out the extra tree node to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the extra tree node.
@return The created element XML tree node. */
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
protected:
/** [INTERNAL] Reads in the children nodes of the extra tree node.
Used by the FCDETechnique class exclusively.
@param customNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the extra tree node.*/
FUStatus ReadChildrenFromXML(xmlNode* customNode);
/** [INTERNAL] Writes out the children nodes of extra tree node.
Used by the FCDETechnique class exclusively.
@param customNode The COLLADA XML node for the extra tree node. */
void WriteChildrenToXML(xmlNode* customNode) const;
};
/**
A COLLADA extra tree technique.
For convenience, this extra tree technique is based on top of the FCDENode class.
An extra tree technique is the root of the extra tree specific to
the profile of an application.
@ingroup FCDocument
*/
class FCOLLADA_EXPORT FCDETechnique : public FCDENode
{
private:
string profile;
public:
/** Constructor: do not use directly.
Instead, use the FCDExtra::AddTechnique function.
@param document The COLLADA document that owns the technique.
@param profile The application-specific profile name. */
FCDETechnique(FCDocument* document, const char* profile);
/** Destructor: do not use directly.
Instead, release a technique using the FCDExtra::ReleaseTechnique function. */
virtual ~FCDETechnique();
/** Retrieves the name of the application-specific profile of the technique.
@return The name of the application-specific profile. */
const char* GetProfile() const { return profile.c_str(); }
/** [INTERNAL] Reads in the extra tree technique from a given COLLADA XML tree node.
@param techniqueNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the extra tree technique.*/
virtual FUStatus LoadFromXML(xmlNode* techniqueNode);
/** [INTERNAL] Writes out the extra tree technique to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the extra tree technique.
@return The created element XML tree node. */
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif // _FCD_EXTRA_H_

View File

@@ -0,0 +1,117 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDocument.h"
#include "FCDocument/FCDAnimated.h"
#include "FCDocument/FCDGeometry.h"
#include "FCDocument/FCDGeometryMesh.h"
#include "FCDocument/FCDGeometrySpline.h"
#include "FUtils/FUStringConversion.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDGeometry::FCDGeometry(FCDocument* document) : FCDEntity(document, "Geometry")
{
spline = NULL;
mesh = NULL;
}
FCDGeometry::~FCDGeometry()
{
SAFE_DELETE(spline);
SAFE_DELETE(mesh);
}
// Sets the type of this geometry to mesh and creates an empty mesh structure.
FCDGeometryMesh* FCDGeometry::CreateMesh()
{
SAFE_DELETE(spline);
SAFE_DELETE(mesh);
mesh = new FCDGeometryMesh(GetDocument(), this);
return mesh;
}
// Sets the type of this geometry to spline and creates an empty spline structure.
FCDGeometrySpline* FCDGeometry::CreateSpline()
{
SAFE_DELETE(spline);
SAFE_DELETE(mesh);
spline = new FCDGeometrySpline(GetDocument(), this);
return spline;
}
// Create a copy of this geometry, with the vertices overwritten
FCDGeometry* FCDGeometry::Clone(FloatList& newPositions, uint32 newPositionsStride, FloatList& newNormals, uint32 newNormalsStride)
{
// Clone only mesh geometries. This function is necessary for COLLADA 1.3 backward compatibility and should not be used
// in some other way (yet)
if (!IsMesh()) return NULL;
FCDGeometry* clone = new FCDGeometry(GetDocument());
clone->mesh = mesh->Clone(newPositions, newPositionsStride, newNormals, newNormalsStride);
return clone;
}
// Load from a XML node the given geometry
FUStatus FCDGeometry::LoadFromXML(xmlNode* geometryNode)
{
SAFE_DELETE(mesh);
SAFE_DELETE(spline);
FUStatus status = FCDEntity::LoadFromXML(geometryNode);
if (!status) return status;
if (!IsEquivalent(geometryNode->name, DAE_GEOMETRY_ELEMENT))
{
return status.Warning(FS("Geometry library contains unknown element."), geometryNode->line);
}
// Read in the first valid child element found
for (xmlNode* child = geometryNode->children; child != NULL; child = child->next)
{
if (child->type != XML_ELEMENT_NODE) continue;
if (IsEquivalent(child->name, DAE_MESH_ELEMENT))
{
// Create a new mesh
FCDGeometryMesh* m = CreateMesh();
status.AppendStatus(m->LoadFromXML(child));
break;
}
else if (IsEquivalent(child->name, DAE_SPLINE_ELEMENT))
{
// Create a new spline
FCDGeometrySpline* s = CreateSpline();
status.AppendStatus(s->LoadFromXML(child));
break;
}
else
{
return status.Fail(FS("Unknown child in <geometry> with id: ") + TO_FSTRING(GetDaeId()), child->line);
}
}
if (mesh == NULL && spline == NULL)
{
status.Warning(FS("No mesh or spline found within geometry: ") + TO_FSTRING(GetDaeId()), geometryNode->line);
}
return status;
}
// Write out the <geometry> node
xmlNode* FCDGeometry::WriteToXML(xmlNode* parentNode) const
{
xmlNode* geometryNode = WriteToEntityXML(parentNode, DAE_GEOMETRY_ELEMENT);
if (mesh != NULL) mesh->WriteToXML(geometryNode);
else if (spline != NULL) spline->WriteToXML(geometryNode);
FCDEntity::WriteToExtraXML(geometryNode);
return geometryNode;
}

View File

@@ -0,0 +1,120 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
/**
@file FCDGeometry.h
This file contains the FCDGeometry class.
The FCDGeometry class holds the information for one mesh or spline
entity, within the COLLADA geometry library.
*/
#ifndef _FCD_GEOMETRY_H_
#define _FCD_GEOMETRY_H_
#include "FCDocument/FCDEntity.h"
#include "FUtils/FUDaeEnum.h"
class FCDocument;
class FCDGeometryMesh;
class FCDGeometrySpline;
/**
@defgroup FCDGeometry COLLADA Document Geometry Entity
@addtogroup FCDocument
*/
/**
A COLLADA geometry entity.
There are two types of COLLADA geometry entities: meshes and splines.
Meshes are collections of polygons where the vertices always have a position,
usually have a normal to define smooth or hard edges and may be colored or textured.
Splines are a sequence of control points used to generate a smooth curve.
@ingroup FCDGeometry
*/
class FCOLLADA_EXPORT FCDGeometry : public FCDEntity
{
private:
// Contains only one of the following, in order of importance.
FCDGeometryMesh* mesh;
FCDGeometrySpline* spline;
public:
/** Contructor: do not use directly. Create new geometries using the FCDocument::AddGeometry function,
or the FCDLibrary::AddEntity function.
@param document The COLLADA document which owns the new geometry entity. */
FCDGeometry(FCDocument* document);
/** Destructor: only release cloned geometries directly.
Release original geometries using the FCDLibrary::ReleaseEntity function.
All original geometries are released with the document that they belong to. */
virtual ~FCDGeometry();
/** Retrieves the entity class type.
This function is a part of the FCDEntity interface.
@return The entity class type: GEOMETRY. */
virtual Type GetType() const { return GEOMETRY; }
/** Retrieves whether the type of this geometry is a mesh.
@return Whether this geometry is a mesh. */
bool IsMesh() const { return mesh != NULL; }
/** Retrieves the mesh information structure for this geometry.
Verify that this geometry is a mesh using the IsMesh function prior to calling this function.
@return The mesh information structure. This pointer will be NULL when the geometry is a spline or is undefined. */
FCDGeometryMesh* GetMesh() { return mesh; }
const FCDGeometryMesh* GetMesh() const { return mesh; } /**< See above. */
/** Sets the type of this geometry to mesh and creates an empty mesh structure.
This function will release any mesh or spline structure that the geometry may already contain
@return The mesh information structure. This pointer will always be valid. */
FCDGeometryMesh* CreateMesh();
/** Retrieves whether the type of this geometry is a spline.
@return Whether this geometry is a spline. */
bool IsSpline() const { return spline != NULL; }
/** Retrieves the spline information structure for this geometry.
Verify that this geometry is a spline using the IsSpline function prior to calling this function.
@return The spline information structure. This pointer will be NULL when the geometry is a mesh or is undefined. */
FCDGeometrySpline* GetSpline() { return spline; }
const FCDGeometrySpline* GetSpline() const { return spline; } /**< See above. */
/** Sets the type of this geometry to spline and creates an empty spline structure.
This function will release any mesh or spline structure that the geometry may already contain.
@return The spline information structure. This pointer will always be valid. */
FCDGeometrySpline* CreateSpline();
/** @deprecated [INTERNAL] Clones the geometry entity.
Works only on mesh geometry. Creates a full copy of the geometry, with the vertices overwritten
by the given data: this is used when importing COLLADA 1.3 skin controllers.
You will need to release the cloned entity.
@param newPositions The list of vertex position that will
overwrite the current mesh vertex positions. This list may be empty.
@param newPositionsStride The stride, in bytes, of the newPositions list.
For an empty newPositions list, this value is discarded.
@param newNormals The list of vertex normals that will overwrite
the current mesh vertex normals. This list may be empty.
@param newNormalsStride The stride, in bytes, of the newNormals list.
For an empty newNormals list, this value is discarded.
@return The cloned geometry entity. This pointer will be NULL,
if the geometry is not a mesh. You will need to release this pointer. */
FCDGeometry* Clone(FloatList& newPositions, uint32 newPositionsStride, FloatList& newNormals, uint32 newNormalsStride);
/** [INTERNAL] Reads in the \<geometry\> element from a given COLLADA XML tree node.
@param node The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the geometry.*/
virtual FUStatus LoadFromXML(xmlNode* node);
/** [INTERNAL] Writes out the \<geometry\> element to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the geometry information.
@return The created \<geometry\> element XML tree node. */
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif // _FCD_GEOMETRY_H_

View File

@@ -0,0 +1,168 @@
/*
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/FCDController.h"
#include "FCDocument/FCDEntity.h"
#include "FCDocument/FCDGeometry.h"
#include "FCDocument/FCDGeometryInstance.h"
#include "FCDocument/FCDGeometryMesh.h"
#include "FCDocument/FCDGeometryPolygons.h"
#include "FCDocument/FCDMaterialInstance.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
// Parasitic: Write out the instantiation information to the xml node tree
xmlNode* FCDEntityInstance::WriteToXML(xmlNode* parentNode) const
{
xmlNode* instanceNode = NULL;
if (entity != NULL)
{
const char* instanceEntityName;
switch (entity->GetType())
{
case FCDEntity::ANIMATION: instanceEntityName = DAE_INSTANCE_ANIMATION_ELEMENT; break;
case FCDEntity::CAMERA: instanceEntityName = DAE_INSTANCE_CAMERA_ELEMENT; break;
case FCDEntity::CONTROLLER: instanceEntityName = DAE_INSTANCE_CONTROLLER_ELEMENT; break;
case FCDEntity::EFFECT: instanceEntityName = DAE_INSTANCE_EFFECT_ELEMENT; break;
case FCDEntity::GEOMETRY: instanceEntityName = DAE_INSTANCE_GEOMETRY_ELEMENT; break;
case FCDEntity::LIGHT: instanceEntityName = DAE_INSTANCE_LIGHT_ELEMENT; break;
case FCDEntity::MATERIAL: instanceEntityName = DAE_INSTANCE_MATERIAL_ELEMENT; break;
case FCDEntity::PHYSICS_MODEL: instanceEntityName = DAE_INSTANCE_PHYSICS_MODEL_ELEMENT; break;
case FCDEntity::PHYSICS_RIGID_BODY: instanceEntityName = DAE_INSTANCE_RIGID_BODY_ELEMENT; break;
case FCDEntity::PHYSICS_RIGID_CONSTRAINT: instanceEntityName = DAE_INSTANCE_RIGID_CONSTRAINT_ELEMENT; break;
case FCDEntity::SCENE_NODE: instanceEntityName = DAE_INSTANCE_NODE_ELEMENT; break;
case FCDEntity::ANIMATION_CLIP:
case FCDEntity::ENTITY:
case FCDEntity::IMAGE:
case FCDEntity::TEXTURE:
default: instanceEntityName = DAEERR_UNKNOWN_ELEMENT;
}
instanceNode = AddChild(parentNode, instanceEntityName);
AddAttribute(instanceNode, DAE_URL_ATTRIBUTE, string("#") + entity->GetDaeId());
}
return instanceNode;
}
FCDGeometryInstance::FCDGeometryInstance(FCDocument* document, FCDEntity* entity) : FCDEntityInstance(document, entity)
{
}
FCDGeometryInstance::~FCDGeometryInstance()
{
CLEAR_POINTER_VECTOR(materials);
}
// Access Bound Materials
FCDMaterialInstance* FCDGeometryInstance::FindMaterialInstance(const fstring& semantic)
{
for (FCDMaterialInstanceList::iterator itB = materials.begin(); itB != materials.end(); ++itB)
{
if ((*itB)->GetSemantic() == semantic) return (*itB);
}
return NULL;
}
const FCDMaterialInstance* FCDGeometryInstance::FindMaterialInstance(const fstring& semantic) const
{
for (FCDMaterialInstanceList::const_iterator itB = materials.begin(); itB != materials.end(); ++itB)
{
if ((*itB)->GetSemantic() == semantic) return (*itB);
}
return NULL;
}
// Load the geometry instance from the COLLADA document
FUStatus FCDGeometryInstance::LoadFromXML(xmlNode* instanceNode)
{
FUStatus status = FCDEntityInstance::LoadFromXML(instanceNode);
if (!status) return status;
if (entity == NULL)
{
return status.Fail(FS("Trying to instantiate non-valid geometric entity."), instanceNode->line);
}
// Check for the expected instantiation node type
if (!IsEquivalent(instanceNode->name, DAE_INSTANCE_GEOMETRY_ELEMENT) && !IsEquivalent(instanceNode->name, DAE_INSTANCE_CONTROLLER_ELEMENT)
&& !IsEquivalent(instanceNode->name, DAE_INSTANCE_ELEMENT))
{
return status.Fail(FS("Unknown element for instantiation of entity: ") + TO_FSTRING(entity->GetDaeId()), instanceNode->line);
}
// Look for the <bind_material> element. The others are discarded for now.
xmlNode* bindMaterialNode = FindChildByType(instanceNode, DAE_BINDMATERIAL_ELEMENT);
if (bindMaterialNode != NULL)
{
// Retrieve the list of the <technique_common><instance_material> elements.
xmlNode* techniqueNode = FindChildByType(bindMaterialNode, DAE_TECHNIQUE_COMMON_ELEMENT);
xmlNodeList materialNodes;
FindChildrenByType(techniqueNode, DAE_INSTANCE_MATERIAL_ELEMENT, materialNodes);
for (xmlNodeList::iterator itM = materialNodes.begin(); itM != materialNodes.end(); ++itM)
{
FCDMaterialInstance* material = new FCDMaterialInstance(GetDocument(), this);
status.AppendStatus(material->LoadFromXML(*itM));
materials.push_back(material);
}
}
if (materials.empty())
{
// COLLADA 1.3 backward compatibility: Create blank material instances for all the geometry's
// polygons that have a valid material semantic
FCDEntity* itE = entity;
while (itE != NULL && itE->GetType() == FCDEntity::CONTROLLER) itE = ((FCDController*) itE)->GetBaseTarget();
if (itE != NULL)
{
FCDGeometry* geometry = (FCDGeometry*) itE;
if (geometry->IsMesh())
{
FCDGeometryMesh* mesh = geometry->GetMesh();
size_t polygonsCount = mesh->GetPolygonsCount();
for (size_t i = 0; i < polygonsCount; ++i)
{
FCDGeometryPolygons* polygons = mesh->GetPolygons(i);
const fstring& materialSemantic = polygons->GetMaterialSemantic();
if (!materialSemantic.empty())
{
FCDMaterialInstance* material = new FCDMaterialInstance(GetDocument(), this);
status.AppendStatus(material->LoadFromId(FUStringConversion::ToString(materialSemantic)));
materials.push_back(material);
}
}
}
}
}
return status;
}
// Write out the instantiation information to the xml node tree
xmlNode* FCDGeometryInstance::WriteToXML(xmlNode* parentNode) const
{
xmlNode* instanceNode = FCDEntityInstance::WriteToXML(parentNode);
if (!materials.empty())
{
xmlNode* bindMaterialNode = AddChild(instanceNode, DAE_BINDMATERIAL_ELEMENT);
xmlNode* techniqueCommonNode = AddChild(bindMaterialNode, DAE_TECHNIQUE_COMMON_ELEMENT);
for (FCDMaterialInstanceList::const_iterator itM = materials.begin(); itM != materials.end(); ++itM)
{
(*itM)->WriteToXML(techniqueCommonNode);
}
}
return instanceNode;
}

View File

@@ -0,0 +1,46 @@
/*
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
*/
#ifndef _FCD_GEOMETRY_ENTITY_H_
#define _FCD_GEOMETRY_ENTITY_H_
#include "FCDocument/FCDEntityInstance.h"
class FCDocument;
class FCDMaterialInstance;
typedef vector<FCDMaterialInstance*> FCDMaterialInstanceList;
class FCOLLADA_EXPORT FCDGeometryInstance : public FCDEntityInstance
{
private:
FCDMaterialInstanceList materials;
public:
FCDGeometryInstance(FCDocument* document, FCDEntity* entity);
virtual ~FCDGeometryInstance();
// FCDEntity override for RTTI-like
virtual Type GetType() const { return GEOMETRY; }
// Access Bound Materials
FCDMaterialInstance* FindMaterialInstance(const fstring& semantic);
const FCDMaterialInstance* FindMaterialInstance(const fstring& semantic) const;
const FCDMaterialInstanceList& GetMaterialInstanceList() const { return materials; }
// Load the geometry instance from the COLLADA document
virtual FUStatus LoadFromXML(xmlNode* instanceNode);
// Write out the instantiation information to the xml node tree
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif // _FCD_GEOMETRY_ENTITY_H_

View File

@@ -0,0 +1,357 @@
/*
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/FCDGeometry.h"
#include "FCDocument/FCDGeometryMesh.h"
#include "FCDocument/FCDGeometryPolygons.h"
#include "FCDocument/FCDGeometrySource.h"
#include "FUtils/FUStringConversion.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDGeometryMesh::FCDGeometryMesh(FCDocument* document, FCDGeometry* _parent) : FCDObject(document, "FCDGeometryMesh")
{
parent = _parent;
faceVertexCount = faceCount = holeCount = 0;
isDoubleSided = true;
}
FCDGeometryMesh::~FCDGeometryMesh()
{
CLEAR_POINTER_VECTOR(sources);
CLEAR_POINTER_VECTOR(polygons);
faceVertexCount = faceCount = 0;
parent = NULL;
}
// Retrieve the parent's id
const string& FCDGeometryMesh::GetDaeId() const
{
return parent->GetDaeId();
}
// Search for a data source in the geometry node
FCDGeometrySource* FCDGeometryMesh::FindSourceById(const string& id)
{
const char* localId = id.c_str();
if (localId[0] == '#') ++localId;
for (FCDGeometrySourceList::iterator it = sources.begin(); it != sources.end(); ++it)
{
if ((*it)->GetSourceId() == localId) return (*it);
}
return NULL;
}
// Search for a data source in the geometry node
const FCDGeometrySource* FCDGeometryMesh::FindSourceById(const string& id) const
{
const char* localId = id.c_str();
if (localId[0] == '#') ++localId;
for (FCDGeometrySourceList::const_iterator it = sources.begin(); it != sources.end(); ++it)
{
if ((*it)->GetSourceId() == localId) return (*it);
}
return NULL;
}
// Retrieve the source for the vertex position
FCDGeometrySource* FCDGeometryMesh::GetPositionSource()
{
string vertexSourceId;
for (FCDGeometrySourceList::iterator itS = vertexSources.begin(); itS != vertexSources.end(); ++itS)
{
if ((*itS)->GetSourceType() == FUDaeGeometryInput::POSITION) return (*itS);
}
return NULL;
}
// Retrieve the source of the vertex position
const FCDGeometrySource* FCDGeometryMesh::GetPositionSource() const
{
string vertexSourceId;
for (FCDGeometrySourceList::const_iterator itS = vertexSources.begin(); itS != vertexSources.end(); ++itS)
{
if ((*itS)->GetSourceType() == FUDaeGeometryInput::POSITION) return (*itS);
}
return NULL;
}
// Creates a new polygon group.
FCDGeometryPolygons* FCDGeometryMesh::AddPolygons()
{
FCDGeometryPolygons* polys = new FCDGeometryPolygons(GetDocument(), this);
polygons.push_back(polys);
// Add to this new polygons all the per-vertex sources.
for (FCDGeometrySourceList::iterator itS = vertexSources.begin(); itS != vertexSources.end(); ++itS)
{
polys->AddInput(*itS, 0);
}
return polys;
}
// Creates a new per-vertex data source
FCDGeometrySource* FCDGeometryMesh::AddVertexSource()
{
FCDGeometrySource* vertexSource = AddSource();
vertexSources.push_back(vertexSource);
// Add this new per-vertex data source to all the existing polygon groups, at offset 0.
for (FCDGeometryPolygonsList::iterator itP = polygons.begin(); itP != polygons.end(); ++itP)
{
(*itP)->AddInput(vertexSource, 0);
}
return vertexSource;
}
// Creates a new data source
FCDGeometrySource* FCDGeometryMesh::AddSource()
{
FCDGeometrySource* source = new FCDGeometrySource(GetDocument());
sources.push_back(source);
return source;
}
// Forces the triangulation of the mesh polygons
void FCDGeometryMesh::Triangulate()
{
for (FCDGeometryPolygonsList::iterator itP = polygons.begin(); itP != polygons.end(); ++itP)
{
(*itP)->Triangulate();
}
// Recalculate the mesh/polygons statistics
Recalculate();
}
// Recalculates all the hole/vertex/face-vertex counts and offsets within the mesh and its polygons
void FCDGeometryMesh::Recalculate()
{
faceCount = holeCount = faceVertexCount = 0;
for (FCDGeometryPolygonsList::iterator itP = polygons.begin(); itP != polygons.end(); ++itP)
{
FCDGeometryPolygons* polygons = *itP;
polygons->Recalculate();
polygons->SetFaceOffset(faceCount);
polygons->SetHoleOffset(holeCount);
polygons->SetFaceVertexOffset(faceVertexCount);
faceCount += polygons->GetFaceCount();
holeCount += polygons->GetHoleCount();
faceVertexCount += polygons->GetFaceVertexCount();
}
}
// Create a copy of this geometry, with the vertices overwritten
FCDGeometryMesh* FCDGeometryMesh::Clone(FloatList& newPositions, uint32 newPositionsStride, FloatList& newNormals, uint32 newNormalsStride)
{
// Create the clone and fill it with the known information
FCDGeometryMesh* clone = new FCDGeometryMesh(GetDocument(), NULL);
clone->faceCount = faceCount;
// Clone the source data
size_t sourceCount = sources.size();
clone->sources.reserve(sourceCount);
for (FCDGeometrySourceList::const_iterator itS = sources.begin(); itS != sources.end(); ++itS)
{
clone->sources.push_back((*itS)->Clone());
if (std::find(vertexSources.begin(), vertexSources.end(), (*itS)) != vertexSources.end())
{
clone->vertexSources.push_back(clone->sources.back());
}
}
// Clone the polygons data
// Gather up the position and normal data sources
FCDGeometrySourceList positionSources, normalSources;
size_t polygonsCount = polygons.size();
clone->polygons.resize(polygonsCount);
for (size_t i = 0; i < polygonsCount; ++i)
{
clone->polygons[i] = polygons[i]->Clone(clone);
// Retrieve the position data source
FCDGeometryPolygonsInput* positionInput = clone->polygons[i]->FindInput(FUDaeGeometryInput::POSITION);
if (positionInput != NULL)
{
FCDGeometrySource* dataSource = positionInput->source;
FUAssert(dataSource != NULL, continue);
if (std::find(positionSources.begin(), positionSources.end(), dataSource) == positionSources.end())
{
positionSources.push_back(dataSource);
}
}
// Retrieve the normal data source
FCDGeometryPolygonsInput* normalInput = clone->polygons[i]->FindInput(FUDaeGeometryInput::NORMAL);
if (normalInput != NULL)
{
FCDGeometrySource* dataSource = normalInput->source;
FUAssert(dataSource != NULL, continue);
if (std::find(normalSources.begin(), normalSources.end(), dataSource) == normalSources.end())
{
normalSources.push_back(dataSource);
}
}
}
// Override the position and normal data sources with the given data (from the controller's bind shape)
# define OVERWRITE_SOURCES(cloneSources, newSourceData, newSourceStride) { \
size_t dataSourceCount = min(cloneSources.size(), newSourceData.size()), offset = 0; \
for (size_t i = 0; i < dataSourceCount; ++i) { \
FCDGeometrySource* dataSource = cloneSources[i]; \
size_t dataCount = dataSource->GetSourceData().size() / dataSource->GetSourceStride(); \
if (offset + dataCount > newSourceData.size() / newSourceStride) dataCount = newSourceData.size() / newSourceStride - offset; \
if (dataCount == 0) break; \
/* Insert the relevant data in this source */ \
dataSource->SetSourceData(newSourceData, newSourceStride, offset * newSourceStride, (offset + dataCount) * newSourceStride); \
offset += dataCount; \
} }
OVERWRITE_SOURCES(positionSources, newPositions, newPositionsStride);
OVERWRITE_SOURCES(normalSources, newNormals, newNormalsStride);
# undef OVERWRITE_SOURCES
return clone;
}
// Read in the <mesh> node of the COLLADA document
FUStatus FCDGeometryMesh::LoadFromXML(xmlNode* meshNode)
{
FUStatus status;
// Read in the data sources
xmlNodeList sourceDataNodes;
FindChildrenByType(meshNode, DAE_SOURCE_ELEMENT, sourceDataNodes);
for (xmlNodeList::iterator it = sourceDataNodes.begin(); it != sourceDataNodes.end(); ++it)
{
FCDGeometrySource* source = AddSource();
status.AppendStatus(source->LoadFromXML(*it));
if (source->GetSourceStride() < 3) continue;
// COLLADA 1.3 backward compatibility
// Maya-specific: Look for the double-sided flag in the normals source
StringList parameterNames; xmlNodeList parameterNodes;
xmlNode* mayaTechniqueNode = FindTechnique((*it), DAEMAYA_MAYA_PROFILE);
FindParameters(mayaTechniqueNode, parameterNames, parameterNodes);
size_t parameterCount = parameterNodes.size();
for (size_t i = 0; i < parameterCount; ++i)
{
const char* content = ReadNodeContentDirect(parameterNodes[i]);
if (parameterNames[i] == DAEMAYA_DOUBLE_SIDED_PARAMETER) isDoubleSided = FUStringConversion::ToBoolean(content);
}
}
// Retrieve the <vertices> node
xmlNode* verticesNode = FindChildByType(meshNode, DAE_VERTICES_ELEMENT);
if (verticesNode == NULL)
{
return status.Warning(FS("No <vertices> element in mesh: ") + TO_FSTRING(parent->GetDaeId()), meshNode->line);
}
// Read in the per-vertex inputs
bool hasPositions = false;
xmlNodeList vertexInputNodes;
FindChildrenByType(verticesNode, DAE_INPUT_ELEMENT, vertexInputNodes);
for (xmlNodeList::iterator it = vertexInputNodes.begin(); it < vertexInputNodes.end(); ++it)
{
xmlNode* vertexInputNode = *it;
string inputSemantic = ReadNodeSemantic(vertexInputNode);
FUDaeGeometryInput::Semantic semantic = FUDaeGeometryInput::FromString(inputSemantic);
if (semantic == FUDaeGeometryInput::POSITION || semantic == FUDaeGeometryInput::NORMAL
|| semantic == FUDaeGeometryInput::COLOR || semantic == FUDaeGeometryInput::TEXCOORD)
{
string sourceId = ReadNodeSource(vertexInputNode);
FCDGeometrySource* source = FindSourceById(sourceId);
if (source == NULL)
{
return status.Fail(FS("Mesh has source with an unknown id: ") + TO_FSTRING(parent->GetDaeId()), vertexInputNode->line);
}
source->SetSourceType(semantic);
if (semantic == FUDaeGeometryInput::POSITION) hasPositions = true;
vertexSources.push_back(source);
}
}
if (!hasPositions)
{
return status.Warning(FS("No vertex position input node in mesh: ") + TO_FSTRING(parent->GetDaeId()), verticesNode->line);
}
// Create our rendering object and read in the tessellation
xmlNodeList polygonsNodes;
FindChildrenByType(meshNode, DAE_POLYGONS_ELEMENT, polygonsNodes);
FindChildrenByType(meshNode, DAE_TRIANGLES_ELEMENT, polygonsNodes);
FindChildrenByType(meshNode, DAE_POLYLIST_ELEMENT, polygonsNodes);
if (polygonsNodes.empty())
{
return status.Warning(FS("No tessellation found for mesh: ") + TO_FSTRING(parent->GetDaeId()), meshNode->line);
}
for (xmlNodeList::iterator it = polygonsNodes.begin(); it != polygonsNodes.end(); ++it)
{
// Create the geometry polygons object
xmlNode* polygonsNode = *it;
FCDGeometryPolygons* polygon = new FCDGeometryPolygons(GetDocument(), this);
polygons.push_back(polygon);
status = polygon->LoadFromXML(polygonsNode);
if (!status) return status;
}
// Calculate the important statistics/offsets/counts
Recalculate();
// Apply the length factor on the vertex positions
float lengthFactor = GetDocument()->GetLengthUnitConversion();
FCDGeometrySource* positionSource = GetPositionSource();
if (positionSource == NULL)
{
return status.Fail(FS("Cannot process the vertex POSITION source for mesh: ") + TO_FSTRING(parent->GetDaeId()), meshNode->line);
}
FloatList& positionData = positionSource->GetSourceData();
for (FloatList::iterator it = positionData.begin(); it != positionData.end(); ++it) (*it) *= lengthFactor;
return status;
}
// Write out the <mesh> node to the COLLADA xml tree
xmlNode* FCDGeometryMesh::WriteToXML(xmlNode* parentNode) const
{
xmlNode* meshNode = AddChild(parentNode, DAE_MESH_ELEMENT);
// Write out the sources
for (FCDGeometrySourceList::const_iterator itS = sources.begin(); itS != sources.end(); ++itS)
{
(*itS)->WriteToXML(meshNode);
}
// Write out the <vertices> element
xmlNode* verticesNode = AddChild(meshNode, DAE_VERTICES_ELEMENT);
for (FCDGeometrySourceList::const_iterator itS = vertexSources.begin(); itS != vertexSources.end(); ++itS)
{
const char* semantic = FUDaeGeometryInput::ToString((*itS)->GetSourceType());
AddInput(verticesNode, (*itS)->GetSourceId(), semantic);
}
FUSStringBuilder verticesNodeId(GetDaeId()); verticesNodeId.append("-vertices");
AddAttribute(verticesNode, DAE_ID_ATTRIBUTE, verticesNodeId);
// Write out the polygons
for (FCDGeometryPolygonsList::const_iterator itP = polygons.begin(); itP != polygons.end(); ++itP)
{
(*itP)->WriteToXML(meshNode);
}
return meshNode;
}

View File

@@ -0,0 +1,209 @@
/*
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
*/
/**
@file FCDGeometryMesh.h
This file contains the FCDGeometryMesh class.
*/
#ifndef _FCD_GEOMETRY_MESH_H_
#define _FCD_GEOMETRY_MESH_H_
#include "FCDocument/FCDObject.h"
#include "FUtils/FUDaeEnum.h"
class FCDocument;
class FCDGeometry;
class FCDGeometryPolygons;
class FCDGeometrySource;
/** A dynamically-sized array of FCDGeometrySource objects. */
typedef vector<FCDGeometrySource*> FCDGeometrySourceList;
/** A dynamically-sized array of FCDGeometryPolygons objects. */
typedef vector<FCDGeometryPolygons*> FCDGeometryPolygonsList;
/**
A COLLADA geometric mesh.
A COLLADA geometric mesh is a list of vertices tied together in polygons.
A set of per-vertex data is used to determine the vertices of the mesh.
This data usually includes a single list: of vertex positions, but it may also
contain per-vertex colors, per-vertex normals or per-vertex texture coordinates.
The other data sources declare per-vertex-face data.
The faces of a mesh may be split across different groups, as they may have
different materials assigned to them. The FCDGeometryPolygons objects contains one such group
of faces.
@ingroup FCDGeometry
*/
class FCOLLADA_EXPORT FCDGeometryMesh : public FCDObject
{
private:
FCDGeometry* parent;
FCDGeometrySourceList sources;
FCDGeometryPolygonsList polygons;
FCDGeometrySourceList vertexSources;
size_t faceCount, holeCount;
size_t faceVertexCount;
bool isDoubleSided; // Maya-specific, defaults to true
public:
/** Contructor: do not use directly. Use FCDGeometry::AddMesh instead.
@param document The COLLADA document which owns this mesh.
@param parent The geometry entity which contains this mesh. */
FCDGeometryMesh(FCDocument* document, FCDGeometry* parent);
/** Destructor: do not use directly. All geometric meshes are released with the geometry that they belong to. */
virtual ~FCDGeometryMesh();
/** Retrieves the number of faces within the geometric mesh.
@return The number of faces within the geometric mesh. */
inline size_t GetFaceCount() const { return faceCount; }
/** Retrieves the number of holes within the faces of the geometric mesh.
As one face may contain multiple holes, this value may be larger than the number of faces.
@return The number of holes within the faces of the geometric mesh. */
inline size_t GetHoleCount() const { return holeCount; }
/** Retrieves the total number of per-face vertices in the mesh.
This function makes no assumption about the uniqueness of the per-face vertices.
@return The total number of per-face vertices in the mesh. */
inline size_t GetFaceVertexCount() const { return faceVertexCount; }
/** Retrieves whether the mesh should be treated as double-sided.
This flag does not belong to COLLADA but is exported at the geometric-level by ColladaMaya.
@return Whether the mesh is double-sided. */
inline bool IsDoubleSided() const { return isDoubleSided; }
/** Retrieves the COLLADA id of the mesh.
This is a shortcut to the parent geometry's COLLADA id.
@return The COLLADA id of the mesh. */
const string& GetDaeId() const;
/** Retrieves the number of independent polygon groups.
Each polygon group is represented within a FCDGeometryPolygons object.
An independent polygon group is usually created to assign a different material to different parts of the mesh
or to assign partial texture coordinates and texture tangents to different parts of the mesh.
@return The number of independent polygon groups. */
inline size_t GetPolygonsCount() const { return polygons.size(); }
/** Retrieves a specific polygon group.
Each polygon group is represented within a FCDGeometryPolygons object.
An independent polygon group is usually created to assign a different material to different parts of the mesh
or to assign partial texture coordinates and texture tangents to different parts of the mesh.
@param index The index of the polygon group. This index should be less than the number
of independent polygon groups returned by the GetPolygonsCount function.
@return The polygon group. This pointer will be NULL if the index is out-of-bounds. */
inline FCDGeometryPolygons* GetPolygons(size_t index) { FUAssert(index < GetPolygonsCount(), return NULL); return polygons.at(index); }
inline const FCDGeometryPolygons* GetPolygons(size_t index) const { FUAssert(index < GetPolygonsCount(), return NULL); return polygons.at(index); } /**< See above. */
/** Creates a new polygon group.
Each polygon group is represented within a FCDGeometryPolygons object.
The new polygon group will be assigned all the existing per-vertex data sources.
No material will be assigned to the new polygon group.
@return The new polygon group. This pointer should never be NULL. */
FCDGeometryPolygons* AddPolygons();
/** [INTERNAL] Retrieves the list of per-vertex data sources.
There should usually be one per-vertex data source that contains positions.
All the sources within this list are also present within the data source list.
@return The list of per-vertex data sources. */
inline FCDGeometrySourceList& GetVertexSources() { return vertexSources; }
inline const FCDGeometrySourceList& GetVertexSources() const { return vertexSources; } /**< See above. */
/** Retrieves the number of per-vertex data sources.
This number should always be lesser or equal to the number of data sources, as each per-vertex
data source is also included within the list of data sources.
@return The number of per-vertex data sources. */
inline size_t GetVertexSourceCount() const { return vertexSources.size(); }
/** Retrieves a specific per-vertex data source.
All the per-vertex data sources are also included in the list of data sources.
@param index The index of the per-vertex data source. This index should be less than the number of
per-vertex data sources returns by the GetVertexSourceCount function.
@return The per-vertex data source. This pointer will be NULL if the index is out-of-bounds. */
inline FCDGeometrySource* GetVertexSource(size_t index) { FUAssert(index < GetVertexSourceCount(), return NULL); return vertexSources.at(index); }
inline const FCDGeometrySource* GetVertexSource(size_t index) const { FUAssert(index < GetVertexSourceCount(), return NULL); return vertexSources.at(index); } /**< See above. */
/** Creates a new per-vertex data source for this geometric mesh.
The per-vertex data source will be added to both the per-vertex data source list and the data source list.
The new per-vertex data source will automatically be added to all the existing polygon groups.
@return The new per-vertex data source. This pointer should never be NULL. */
FCDGeometrySource* AddVertexSource();
/** [INTERNAL] Retrieves the data source that matches the given COLLADA id.
@param id A valid COLLADA id.
@return The data source. This pointer will be NULL if no matching data source was found. */
FCDGeometrySource* FindSourceById(const string& id);
const FCDGeometrySource* FindSourceById(const string& id) const; /**< See above. */
/** Retrieves the per-vertex data that specifically contains the vertex positions.
If there are more than one per-vertex data source that contains vertex positions, the first one is returned.
@return A per-vertex data source that contains vertex positions. This pointer will be NULL
in the unlikely possibility that there are no per-vertex data source that contains vertex positions. */
FCDGeometrySource* GetPositionSource();
const FCDGeometrySource* GetPositionSource() const; /**< See above. */
/** Retrieves the number of data sources contained within this geometric mesh.
@return The number of data sources within the mesh. */
inline size_t GetSourceCount() const { return sources.size(); }
/** Retrieves a specific data source.
@param index The index of the data source. This index should be less than the number of
data sources returns by the GetSourceCount function.
@return The data source. This pointer will be NULL if the index is out-of-bounds. */
inline FCDGeometrySource* GetSource(size_t index) { FUAssert(index < GetSourceCount(), return NULL); return sources.at(index); }
inline const FCDGeometrySource* GetSource(size_t index) const { FUAssert(index < GetSourceCount(), return NULL); return sources.at(index); } /**< See above. */
/** Creates a new data source for this geometric mesh.
The new data source will not be added to any of the existing polygon groups.
@return The new per-vertex data source. This pointer should never be NULL. */
FCDGeometrySource* AddSource();
/** Triangulates the mesh.
A simple fanning techique is currently used: holes will not be triangulated correctly. */
void Triangulate();
/** [INTERNAL] Forces the recalculation of the hole count, vertex count, face-vertex counts and their offsets.
Since the counts and offsets are buffered at the geometric mesh object level, this function allows the polygon
groups to force the recalculation of the buffered values, when they are modified. */
void Recalculate();
/** [INTERNAL] Creates a copy of this mesh. You may use the FCDGeometry::Clone function instead of this function.
Creates a full copy of the geometry, with the vertices overwritten
by the given data: this is used when importing COLLADA 1.3 skin controllers.
You will need to release the cloned entity.
@see FCDGeometry::Clone.
@param newPositions The list of vertex position that will
overwrite the current mesh vertex positions. This list may be empty.
@param newPositionsStride The stride, in bytes, of the newPositions list.
For an empty newPositions list, this value is discarded.
@param newNormals The list of vertex normals that will overwrite
the current mesh vertex normals. This list may be empty.
@param newNormalsStride The stride, in bytes, of the newNormals list.
For an empty newNormals list, this value is discarded.
@return The cloned geometry entity. You will need to release this pointer. */
FCDGeometryMesh* Clone(FloatList& newPositions, uint32 newPositionsStride, FloatList& newNormals, uint32 newNormalsStride);
/** [INTERNAL] Reads in the \<mesh\> element from a given COLLADA XML tree node.
@param meshNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the geometric mesh.*/
FUStatus LoadFromXML(xmlNode* meshNode);
/** [INTERNAL] Writes out the \<mesh\> element to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the geometric mesh.
@return The created \<mesh\> element XML tree node. */
xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif // _FCD_GEOMETRY_MESH_H_

View File

@@ -0,0 +1,811 @@
/*
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/FCDGeometryMesh.h"
#include "FCDocument/FCDGeometryPolygons.h"
#include "FCDocument/FCDGeometrySource.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
#include "FUtils/FUStringConversion.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
typedef vector<UInt32List> UniqueVerticesTable;
FCDGeometryPolygons::FCDGeometryPolygons(FCDocument* document, FCDGeometryMesh* _parent) : FCDObject(document, "FCDGeometryPolygons")
{
parent = _parent;
faceVertexCount = 0;
faceOffset = faceVertexOffset = 0;
}
FCDGeometryPolygons::~FCDGeometryPolygons()
{
CLEAR_POINTER_VECTOR(inputs);
idxOwners.clear();
holeFaces.clear();
parent = NULL;
}
// Creates a new face.
void FCDGeometryPolygons::AddFace(uint32 degree)
{
faceVertexCounts.push_back(degree);
// Inserts empty indices
for (FCDGeometryPolygonsInputList::iterator it = idxOwners.begin(); it != idxOwners.end(); ++it)
{
FCDGeometryPolygonsInput* input = (*it);
input->indices.resize(input->indices.size() + degree, 0);
}
parent->Recalculate();
}
// Removes a face
void FCDGeometryPolygons::RemoveFace(size_t index)
{
FUAssert(index < GetFaceCount(), return);
// Remove the associated indices, if they exist.
size_t offset = GetFaceVertexOffset(index);
size_t indexCount = GetFaceVertexCount(index);
for (FCDGeometryPolygonsInputList::iterator it = idxOwners.begin(); it != idxOwners.end(); ++it)
{
FCDGeometryPolygonsInput* input = (*it);
size_t inputIndexCount = input->indices.size();
if (offset < inputIndexCount)
{
UInt32List::iterator end, begin = input->indices.begin() + offset;
if (offset + indexCount < inputIndexCount) end = begin + indexCount;
else end = input->indices.end();
input->indices.erase(begin, end);
}
}
// Remove the face and its holes
size_t holeBefore = GetHoleCountBefore(index);
UInt32List::iterator itFV = faceVertexCounts.begin() + index + holeBefore;
size_t holeCount = GetHoleCount(index);
faceVertexCounts.erase(itFV, itFV + holeCount + 1); // +1 in order to remove the polygon as well as the holes.
parent->Recalculate();
}
// Calculates the offset of face-vertex pairs before the given face index within the polygon set.
size_t FCDGeometryPolygons::GetFaceVertexOffset(size_t index) const
{
size_t offset = 0;
// We'll need to skip over the holes
size_t holeCount = GetHoleCountBefore(index);
if (index + holeCount < faceVertexCounts.size())
{
// Sum up the wanted offset
UInt32List::const_iterator end = faceVertexCounts.begin() + index + holeCount;
for (UInt32List::const_iterator it = faceVertexCounts.begin(); it != end; ++it)
{
offset += (*it);
}
}
return offset;
}
// Calculates the number of holes within the polygon set that appear before the given face index.
size_t FCDGeometryPolygons::GetHoleCountBefore(size_t index) const
{
size_t holeCount = 0;
for (UInt32List::const_iterator it = holeFaces.begin(); it != holeFaces.end(); ++it)
{
if ((*it) < index) ++holeCount;
}
return holeCount;
}
// Retrieves the number of holes within a given face.
size_t FCDGeometryPolygons::GetHoleCount(size_t index) const
{
size_t holeCount = 0;
for (size_t i = GetFaceVertexOffset(index) + 1; i < faceVertexCounts.size(); ++i)
{
bool isHoled = std::find(holeFaces.begin(), holeFaces.end(), i) != holeFaces.end();
if (!isHoled) break;
else ++holeCount;
}
return holeCount;
}
// The number of face-vertex pairs for a given face.
size_t FCDGeometryPolygons::GetFaceVertexCount(size_t index) const
{
size_t count = 0;
if (index < GetFaceCount())
{
size_t holeCount = GetHoleCount(index);
UInt32List::const_iterator it = faceVertexCounts.begin() + index + GetHoleCountBefore(index);
UInt32List::const_iterator end = it + holeCount + 1; // +1 in order to sum the face-vertex pairs of the polygon as its holes.
for (; it != end; ++it) count += (*it);
}
return count;
}
FCDGeometryPolygonsInput* FCDGeometryPolygons::AddInput(FCDGeometrySource* source, uint32 offset)
{
FCDGeometryPolygonsInput* input = new FCDGeometryPolygonsInput();
input->source = source;
input->idx = offset;
input->semantic = source->GetSourceType();
// Check if the offset is new
input->ownsIdx = true;
for (FCDGeometryPolygonsInputList::iterator it = inputs.begin(); it != inputs.end(); ++it)
{
if ((*it)->idx == input->idx)
{
input->ownsIdx = false;
break;
}
}
inputs.push_back(input);
if (input->ownsIdx) idxOwners.push_back(input);
return input;
}
void FCDGeometryPolygons::ReleaseInput(FCDGeometryPolygonsInput* input)
{
FCDGeometryPolygonsInputList::iterator itP = std::find(inputs.begin(), inputs.end(), input);
if (itP != inputs.end())
{
// Before releasing the polygon set input, verify that shared indices are not lost
if (input->ownsIdx)
{
for (FCDGeometryPolygonsInputList::iterator it = inputs.begin(); it != inputs.end(); ++it)
{
if ((*it)->idx == input->idx && !(*it)->ownsIdx)
{
(*it)->indices = input->indices;
(*it)->ownsIdx = true;
idxOwners.push_back(*it);
break;
}
}
FCDGeometryPolygonsInputList::iterator itO = std::find(idxOwners.begin(), idxOwners.end(), input);
if (itO != idxOwners.end()) idxOwners.erase(itO);
input->indices.clear();
input->ownsIdx = false;
}
// Release the polygon set input
SAFE_DELETE(input);
inputs.erase(itP);
}
}
FCDGeometryPolygonsInput* FCDGeometryPolygons::FindInput(FUDaeGeometryInput::Semantic semantic)
{
for (FCDGeometryPolygonsInputList::iterator it = inputs.begin(); it != inputs.end(); ++it)
{
if ((*it)->semantic == semantic) return (*it);
}
return NULL;
}
const FCDGeometryPolygonsInput* FCDGeometryPolygons::FindInput(FUDaeGeometryInput::Semantic semantic) const
{
for (FCDGeometryPolygonsInputList::const_iterator it = inputs.begin(); it != inputs.end(); ++it)
{
if ((*it)->semantic == semantic) return (*it);
}
return NULL;
}
FCDGeometryPolygonsInput* FCDGeometryPolygons::FindInput(FCDGeometrySource* source)
{
for (FCDGeometryPolygonsInputList::iterator it = inputs.begin(); it != inputs.end(); ++it)
{
if ((*it)->source == source) return (*it);
}
return NULL;
}
const FCDGeometryPolygonsInput* FCDGeometryPolygons::FindInput(const FCDGeometrySource* source) const
{
for (FCDGeometryPolygonsInputList::const_iterator it = inputs.begin(); it != inputs.end(); ++it)
{
if ((*it)->source == source) return (*it);
}
return NULL;
}
FCDGeometryPolygonsInput* FCDGeometryPolygons::FindInput(const string& sourceId)
{
const char* s = sourceId.c_str();
if (*s == '#') ++s;
for (FCDGeometryPolygonsInputList::iterator it = inputs.begin(); it != inputs.end(); ++it)
{
if ((*it)->source->GetDaeId() == s) return (*it);
}
return NULL;
}
void FCDGeometryPolygons::FindInputs(FUDaeGeometryInput::Semantic semantic, FCDGeometryPolygonsInputList& _inputs)
{
for (FCDGeometryPolygonsInputList::iterator it = inputs.begin(); it != inputs.end(); ++it)
{
if ((*it)->semantic == semantic) _inputs.push_back(*it);
}
}
UInt32List* FCDGeometryPolygons::FindIndicesForIdx(uint32 idx)
{
for (FCDGeometryPolygonsInputList::iterator it = idxOwners.begin(); it != idxOwners.end(); ++it)
{
if ((*it)->idx == idx) return &(*it)->indices;
}
return NULL;
}
const UInt32List* FCDGeometryPolygons::FindIndicesForIdx(uint32 idx) const
{
for (FCDGeometryPolygonsInputList::const_iterator cit = idxOwners.begin(); cit != idxOwners.end(); ++cit)
{
if ((*cit)->idx == idx) return &(*cit)->indices;
}
return NULL;
}
UInt32List* FCDGeometryPolygons::FindIndices(FCDGeometrySource* source)
{
FCDGeometryPolygonsInput* input = FindInput(source);
return (input != NULL) ? FindIndices(input) : NULL;
}
const UInt32List* FCDGeometryPolygons::FindIndices(const FCDGeometrySource* source) const
{
const FCDGeometryPolygonsInput* input = FindInput(source);
return (input != NULL) ? FindIndices(input) : NULL;
}
UInt32List* FCDGeometryPolygons::FindIndices(FCDGeometryPolygonsInput* input)
{
FCDGeometryPolygonsInputList::iterator itP = std::find(inputs.begin(), inputs.end(), input);
return itP != inputs.end() ? FindIndicesForIdx(input->idx) : NULL;
}
const UInt32List* FCDGeometryPolygons::FindIndices(const FCDGeometryPolygonsInput* input) const
{
FCDGeometryPolygonsInputList::const_iterator itP = std::find(inputs.begin(), inputs.end(), input);
return itP != inputs.end() ? FindIndicesForIdx(input->idx) : NULL;
}
// Forces the triangulation of the polygons
void FCDGeometryPolygons::Triangulate()
{
// Pre-allocate and ready the end index/count buffers
UInt32List oldFaceVertexCounts = faceVertexCounts;
faceVertexCounts.clear();
vector<UInt32List*> dataIndices;
vector<UInt32List> oldDataIndices;
for (FCDGeometryPolygonsInputList::iterator itI = idxOwners.begin(); itI != idxOwners.end(); ++itI)
{
UInt32List* indices = &(*itI)->indices;
oldDataIndices.push_back(*indices);
dataIndices.push_back(indices);
indices->clear();
}
size_t dataIndicesCount = oldDataIndices.size();
// Rebuild the index/count buffers through simple fan-triangulation.
// Drop holes and polygons with less than two vertices.
size_t oldOffset = 0, oldFaceCount = oldFaceVertexCounts.size();
for (size_t oldFaceIndex = 0; oldFaceIndex < oldFaceCount; ++oldFaceIndex)
{
size_t oldFaceVertexCount = oldFaceVertexCounts[oldFaceIndex];
bool isHole = std::find(holeFaces.begin(), holeFaces.end(), oldFaceIndex) != holeFaces.end();
if (!isHole && oldFaceVertexCount >= 3)
{
// Fan-triangulation: works well on convex polygons.
size_t triangleCount = oldFaceVertexCount - 2;
for (size_t triangleIndex = 0; triangleIndex < triangleCount; ++triangleIndex)
{
for (size_t j = 0; j < dataIndicesCount; ++j)
{
UInt32List& oldData = oldDataIndices[j];
UInt32List* newData = dataIndices[j];
newData->push_back(oldData[oldOffset]);
newData->push_back(oldData[oldOffset + triangleIndex + 1]);
newData->push_back(oldData[oldOffset + triangleIndex + 2]);
}
faceVertexCounts.push_back(3);
}
}
oldOffset += oldFaceVertexCount;
}
holeFaces.clear();
}
// Recalculates the face-vertex count within the polygons
void FCDGeometryPolygons::Recalculate()
{
faceVertexCount = 0;
for (UInt32List::iterator itC = faceVertexCounts.begin(); itC != faceVertexCounts.end(); ++itC) faceVertexCount += (*itC);
}
FUStatus FCDGeometryPolygons::LoadFromXML(xmlNode* baseNode)
{
FUStatus status;
// Retrieve the expected face count from the base node's 'count' attribute
size_t expectedFaceCount = ReadNodeCount(baseNode);
// Check the node's name to know whether to expect a <vcount> element
size_t expectedVertexCount; bool isPolygons = false, isTriangles = false, isPolylist = false;
if (IsEquivalent(baseNode->name, DAE_POLYGONS_ELEMENT)) { expectedVertexCount = 4; isPolygons = true; }
else if (IsEquivalent(baseNode->name, DAE_TRIANGLES_ELEMENT)) { expectedVertexCount = 3 * expectedFaceCount; isTriangles = true; }
else if (IsEquivalent(baseNode->name, DAE_POLYLIST_ELEMENT)) { expectedVertexCount = 0; isPolylist = true; }
else
{
return status.Fail(FS("Unknown polygons element in geometry: ") + TO_FSTRING(parent->GetDaeId()), baseNode->line);
}
// Retrieve the material symbol used by these polygons
materialSemantic = TO_FSTRING(ReadNodeProperty(baseNode, DAE_MATERIAL_ATTRIBUTE));
if (materialSemantic.empty())
{
status.Warning(FS("Unknown or missing polygonal material symbol in geometry: ") + TO_FSTRING(parent->GetDaeId()), baseNode->line);
}
// Read in the per-face, per-vertex inputs
uint32 idxCount = 1, tableIdx = 0;
xmlNode* itNode = NULL;
for (itNode = baseNode->children; itNode != NULL; itNode = itNode->next)
{
if (itNode->type != XML_ELEMENT_NODE) continue;
if (IsEquivalent(itNode->name, DAE_INPUT_ELEMENT))
{
FCDGeometryPolygonsInput* input = new FCDGeometryPolygonsInput();
string sourceId = ReadNodeSource(itNode);
if (sourceId[0] == '#') sourceId.erase(0, 1);
// Parse input idx
string idx = ReadNodeProperty(itNode, DAE_OFFSET_ATTRIBUTE);
if (idx.empty()) idx = ReadNodeProperty(itNode, DAE_IDX_ATTRIBUTE); // COLLADA 1.3 Backward-compatibility
input->idx = (!idx.empty()) ? FUStringConversion::ToUInt32(idx) : idxCount;
idxCount = max(input->idx + 1, idxCount);
// Parse input set
string setString = ReadNodeProperty(itNode, DAE_SET_ATTRIBUTE);
input->set = setString.empty() ? -1 : FUStringConversion::ToInt32(setString);
// Parse input semantic
string semanticString = ReadNodeSemantic(itNode);
input->semantic = FUDaeGeometryInput::FromString(semanticString);
if (input->semantic == FUDaeGeometryInput::UNKNOWN)
{
// Unknown input type
SAFE_DELETE(input);
continue;
}
else if (input->semantic == FUDaeGeometryInput::VERTEX)
{
tableIdx = input->idx;
}
else
{
// Retrieve the source for this input
input->source = parent->FindSourceById(sourceId);
if (input->source == NULL)
{
status.Warning(FS("Unknown polygons set input with id: '") + TO_FSTRING(sourceId) + FS("' in geometry: ") + TO_FSTRING(parent->GetDaeId()), itNode->line);
SAFE_DELETE(input);
continue;
}
}
// Check uniqueness of idx
input->ownsIdx = true;
for (FCDGeometryPolygonsInputList::iterator it = inputs.begin(); it != inputs.end(); ++it)
{
if ((*it)->idx == input->idx)
{
input->ownsIdx = false;
break;
}
}
// Add to our lists
if (input->ownsIdx) idxOwners.push_back(input);
inputs.push_back(input);
}
else if (IsEquivalent(itNode->name, DAE_POLYGON_ELEMENT)
|| IsEquivalent(itNode->name, DAE_VERTEXCOUNT_ELEMENT)
|| IsEquivalent(itNode->name, DAE_POLYGONHOLED_ELEMENT))
{
break;
}
// COLLADA 1.3 backward compatibility: <param> is a valid node, but unused
else if (IsEquivalent(itNode->name, DAE_PARAMETER_ELEMENT)) {}
else
{
status.Warning(FS("Unknown polygon child element in geometry: ") + TO_FSTRING(parent->GetDaeId()), itNode->line);
}
}
if (itNode == NULL)
{
return status.Fail(FS("No polygon <p>/<vcount> element found in geometry: ") + TO_FSTRING(parent->GetDaeId()), baseNode->line);
}
// Look for the <vcount> element and parse it in
xmlNode* vCountNode = FindChildByType(baseNode, DAE_VERTEXCOUNT_ELEMENT);
const char* vCountDataString = ReadNodeContentDirect(vCountNode);
if (vCountDataString != NULL) FUStringConversion::ToUInt32List(vCountDataString, faceVertexCounts);
bool hasVertexCounts = !faceVertexCounts.empty();
if (isPolylist && !hasVertexCounts)
{
return status.Fail(FS("No or empty <vcount> element found in geometry: ") + TO_FSTRING(parent->GetDaeId()), baseNode->line);
}
else if (!isPolylist && hasVertexCounts)
{
return status.Fail(FS("<vcount> is only expected with the <polylist> element in geometry: ") + TO_FSTRING(parent->GetDaeId()), baseNode->line);
}
else if (isPolylist)
{
// Count the total number of face-vertices expected, to pre-buffer the index lists
expectedVertexCount = 0;
for (UInt32List::iterator itC = faceVertexCounts.begin(); itC != faceVertexCounts.end(); ++itC)
{
expectedVertexCount += *itC;
}
}
string holeBuffer;
UInt32List allIndices;
// First pass, allocation for tessellation
xmlNode* savedNode = itNode; // two pass process for performance
uint32 indicesSize = 0;
faceVertexCount = 0;
allIndices.clear();
allIndices.reserve(expectedVertexCount * idxCount);
for (; itNode != NULL; itNode = itNode->next)
{
uint32 localFaceVertexCount;
const char* content = NULL;
xmlNode* holeNode = NULL;
bool failed = false;
if (!InitTessellation(itNode, &localFaceVertexCount, allIndices, content, holeNode, idxCount, &failed)) continue;
if (failed)
{
return status.Fail(FS("Unknown element found in <ph> element for geometry: ") + TO_FSTRING(parent->GetDaeId()), itNode->line);
}
indicesSize += localFaceVertexCount;
}
for (FCDGeometryPolygonsInputList::iterator it = idxOwners.begin(); it != idxOwners.end(); ++it)
{
size_t currentIndexCount = (*it)->indices.size();
(*it)->indices.reserve(currentIndexCount + indicesSize);
}
// Second pass, saving the tessellation
faceVertexCount = 0;
allIndices.clear();
allIndices.reserve(expectedVertexCount * idxCount);
itNode = savedNode;
for (; itNode != NULL; itNode = itNode->next)
{
uint32 localFaceVertexCount;
const char* content = NULL;
xmlNode* holeNode = NULL;
bool failed = false;
if (!InitTessellation(itNode, &localFaceVertexCount, allIndices, content, holeNode, idxCount, &failed)) continue;
if (failed)
{
return status.Fail(FS("Unknown element found in <ph> element for geometry: ") + TO_FSTRING(parent->GetDaeId()), itNode->line);
}
if (isTriangles) for (uint32 i = 0; i < localFaceVertexCount / 3; ++i) faceVertexCounts.push_back(3);
else if (isPolygons) faceVertexCounts.push_back(localFaceVertexCount);
faceVertexCount += localFaceVertexCount;
// Append any hole indices found
for (; holeNode != NULL; holeNode = holeNode->next)
{
if (holeNode->type != XML_ELEMENT_NODE) continue;
// Read in the hole indices and push them on top of the other indices
UInt32List holeIndices; holeIndices.reserve(expectedVertexCount * idxCount);
content = ReadNodeContentDirect(holeNode);
FUStringConversion::ToUInt32List(content, holeIndices);
allIndices.insert(allIndices.end(), holeIndices.begin(), holeIndices.end());
// Create the hole face and record its index
size_t holeVertexCount = holeIndices.size() / idxCount;
holeFaces.push_back((uint32) faceVertexCounts.size());
faceVertexCounts.push_back((uint32) holeVertexCount);
faceVertexCount += holeVertexCount;
}
// Create a new entry for the vertex buffer
for (size_t offset = 0; offset < allIndices.size(); offset += idxCount)
{
for (FCDGeometryPolygonsInputList::iterator it = idxOwners.begin(); it != idxOwners.end(); ++it)
{
(*it)->indices.push_back(allIndices[offset + (*it)->idx]);
}
}
}
// Check the actual face count
if (expectedFaceCount != faceVertexCounts.size() - holeFaces.size())
{
return status.Fail(FS("Face count for polygons node doesn't match actual number of faces found in <p> element(s) in geometry: ") + TO_FSTRING(parent->GetDaeId()), baseNode->line);
}
// Merge the vertex input with the vertices node information
FCDGeometryPolygonsInputList::iterator itVertex;
for (itVertex = inputs.begin(); itVertex != inputs.end(); ++itVertex)
{
if ((*itVertex)->semantic == FUDaeGeometryInput::VERTEX) break;
}
if (itVertex == inputs.end())
{
return status.Fail(FS("Cannot find VERTEX polygons' input within geometry: ") + TO_FSTRING(parent->GetDaeId()), baseNode->line);
}
FCDGeometrySourceList& vertexSources = parent->GetVertexSources();
size_t vertexMergeCount = vertexSources.size();
if (vertexMergeCount == 0)
{
return status.Fail(FS("Empty <vertices> element in geometry: ") + TO_FSTRING(parent->GetDaeId()), baseNode->line);
}
(*itVertex)->semantic = vertexSources.front()->GetSourceType();
(*itVertex)->source = vertexSources.front();
uint32 vertexIdx = (*itVertex)->idx;
uint32 vertexPosition = (uint32) (itVertex - inputs.begin());
for (uint32 i = 1; i < vertexMergeCount; ++i)
{
FCDGeometryPolygonsInput* perVertexInput = new FCDGeometryPolygonsInput();
perVertexInput->source = vertexSources[i];
perVertexInput->semantic = vertexSources[i]->GetSourceType();
perVertexInput->ownsIdx = false;
perVertexInput->idx = vertexIdx;
perVertexInput->set = 0;
inputs.insert(inputs.begin() + vertexPosition, perVertexInput);
}
// Read in the polygons source animations
for (FCDGeometryPolygonsInputList::iterator it = inputs.begin(); it != inputs.end(); ++it)
{
(*it)->source->SetSourceType((*it)->semantic);
}
return status;
}
bool FCDGeometryPolygons::InitTessellation(xmlNode* itNode,
uint32* localFaceVertexCount, UInt32List& allIndices,
const char* content, xmlNode*& holeNode, uint32 idxCount,
bool* failed)
{
if (itNode->type != XML_ELEMENT_NODE) return false;
if (!IsEquivalent(itNode->name, DAE_POLYGON_ELEMENT)
&& !IsEquivalent(itNode->name, DAE_POLYGONHOLED_ELEMENT)) return false;
// Retrieve the indices
content = NULL;
holeNode = NULL;
if (!IsEquivalent(itNode->name, DAE_POLYGONHOLED_ELEMENT))
{
content = ReadNodeContentDirect(itNode);
}
else
{
// Holed face found
for (xmlNode* child = itNode->children; child != NULL; child = child->next)
{
if (child->type != XML_ELEMENT_NODE) continue;
if (IsEquivalent(child->name, DAE_POLYGON_ELEMENT))
{
content = ReadNodeContentDirect(child);
}
else if (IsEquivalent(child->name, DAE_HOLE_ELEMENT))
{
holeNode = child; break;
}
else
{
*failed = true;
return true;
}
}
}
// Parse the indices
allIndices.clear();
FUStringConversion::ToUInt32List(content, allIndices);
*localFaceVertexCount = (uint32) allIndices.size() / idxCount;
return true;
}
// Write out the polygons structure to the COLLADA xml tree
xmlNode* FCDGeometryPolygons::WriteToXML(xmlNode* parentNode) const
{
// Are there holes? Then, export a <polygons> element.
// Are there only non-triangles within the list? Then, export a <polylist> element.
// Otherwise, you only have triangles: export a <triangles> element.
bool hasHoles = !holeFaces.empty(), hasNPolys = true;
if (!hasHoles)
{
UInt32List::const_iterator itC;
for (itC = faceVertexCounts.begin(); itC != faceVertexCounts.end() && (*itC) == 3; ++itC) {}
hasNPolys = (itC != faceVertexCounts.end());
}
// Create the base node for these polygons
const char* polygonNodeType;
if (hasHoles) polygonNodeType = DAE_POLYGONS_ELEMENT;
else if (hasNPolys) polygonNodeType = DAE_POLYLIST_ELEMENT;
else polygonNodeType = DAE_TRIANGLES_ELEMENT;
xmlNode* polygonsNode = AddChild(parentNode, polygonNodeType);
// Add the inputs
// Find which input owner belongs to the <vertices> element. Replace the semantic and the source id accordingly.
// Make sure to add that 'vertex' input only once.
FUSStringBuilder verticesNodeId(parent->GetDaeId()); verticesNodeId.append("-vertices");
const FCDGeometrySourceList& vertexSources = parent->GetVertexSources();
bool isVertexInputFound = false;
for (FCDGeometryPolygonsInputList::const_iterator itI = inputs.begin(); itI != inputs.end(); ++itI)
{
FCDGeometryPolygonsInput* input = *itI;
if (std::find(vertexSources.begin(), vertexSources.end(), input->source) == vertexSources.end())
{
const char* semantic = FUDaeGeometryInput::ToString(input->semantic);
FUDaeWriter::AddInput(polygonsNode, input->source->GetDaeId(), semantic, input->idx, input->set);
}
else if (!isVertexInputFound)
{
FUDaeWriter::AddInput(polygonsNode, verticesNodeId.ToCharPtr(), DAE_VERTEX_INPUT, input->idx);
isVertexInputFound = true;
}
}
FUSStringBuilder builder;
builder.reserve(1024);
// For the poly-list case, export the list of vertex counts
if (!hasHoles && hasNPolys)
{
FUStringConversion::ToString(builder, faceVertexCounts);
AddChild(polygonsNode, DAE_VERTEXCOUNT_ELEMENT, builder.ToCharPtr());
builder.clear();
}
// For the non-holes cases, open only one <p> element for all the data indices
xmlNode* pNode = NULL,* phNode = NULL;
if (!hasHoles) pNode = AddChild(polygonsNode, DAE_POLYGON_ELEMENT);
// Export the data indices (tessellation information)
size_t faceCount = faceVertexCounts.size();
uint32 faceVertexOffset = 0;
for (size_t faceIndex = 0; faceIndex < faceCount; ++faceIndex)
{
// For the holes cases, verify whether this face or the next one(s) are holes. We may need to open a new <ph>/<p> element
bool isHole = false, isHoleNext = false;
if (hasHoles)
{
for (UInt32List::const_iterator itH = holeFaces.begin(); itH != holeFaces.end(); ++itH)
{
isHole |= (*itH) == (uint32) faceIndex;
isHoleNext |= (*itH) + 1 == (uint32) faceIndex;
}
if (!isHole)
{
// Just open a <p> element: this is the most common case
if (!isHoleNext) pNode = AddChild(polygonsNode, DAE_POLYGONHOLED_ELEMENT);
else
{
// Open up a new <ph> element and its <p> element
phNode = AddChild(polygonsNode, DAE_POLYGONHOLED_ELEMENT);
pNode = AddChild(phNode, DAE_POLYGON_ELEMENT);
}
}
else
{
// Open up a <h> element
pNode = AddChild(phNode, DAE_HOLE_ELEMENT);
}
}
// Write out the tessellation information for all the vertices of this face
uint32 faceVertexCount = faceVertexCounts[faceIndex];
for (uint32 faceVertexIndex = faceVertexOffset; faceVertexIndex < faceVertexOffset + faceVertexCount; ++faceVertexIndex)
{
for (FCDGeometryPolygonsInputList::const_iterator itI = idxOwners.begin(); itI != idxOwners.end(); ++itI)
{
UInt32List& indices = (*itI)->indices;
builder.append(indices[faceVertexIndex]);
builder.append(' ');
}
}
// For the holes cases: write out the indices for every polygon element
if (hasHoles)
{
if (!builder.empty()) builder.pop_back(); // take out the last space
AddContent(pNode, builder);
}
faceVertexOffset += faceVertexCount;
}
// For the non-holes cases: write out the indices at the very end, for the single <p> element
if (!hasHoles)
{
if (!builder.empty()) builder.pop_back(); // take out the last space
AddContent(pNode, builder);
}
// Write out the material semantic and the number of polygons
if (!materialSemantic.empty())
{
AddAttribute(polygonsNode, DAE_MATERIAL_ATTRIBUTE, materialSemantic);
}
AddAttribute(polygonsNode, DAE_COUNT_ATTRIBUTE, GetFaceCount() - GetHoleCount());
return polygonsNode;
}
// Clone this list of polygons
FCDGeometryPolygons* FCDGeometryPolygons::Clone(FCDGeometryMesh* cloneParent)
{
FCDGeometryPolygons* clone = new FCDGeometryPolygons(GetDocument(), cloneParent);
clone->materialSemantic = materialSemantic;
clone->faceVertexCounts = faceVertexCounts;
clone->faceOffset = faceOffset;
clone->faceVertexCount = faceVertexCount;
clone->faceVertexOffset = faceVertexOffset;
// Clone the geometry inputs
uint32 inputCount = (uint32) inputs.size();
clone->inputs.resize(inputCount);
for (uint32 i = 0; i < inputCount; ++i)
{
clone->inputs[i] = new FCDGeometryPolygonsInput();
clone->inputs[i]->source = cloneParent->FindSourceById(inputs[i]->source->GetDaeId());
clone->inputs[i]->idx = inputs[i]->idx;
clone->inputs[i]->indices = inputs[i]->indices;
clone->inputs[i]->ownsIdx = inputs[i]->ownsIdx;
clone->inputs[i]->semantic = inputs[i]->semantic;
clone->inputs[i]->set = inputs[i]->set;
// Regenerate the idxOwners list with the new inputs
if (clone->inputs[i]->ownsIdx) clone->idxOwners.push_back(clone->inputs[i]);
}
return clone;
}
FCDGeometryPolygonsInput::FCDGeometryPolygonsInput()
{
idx = 0;
ownsIdx = false;
semantic = FUDaeGeometryInput::UNKNOWN;
set = -1;
source = NULL;
}

View File

@@ -0,0 +1,340 @@
/*
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
*/
/**
@file FCDGeometryPolygons.h
This file defines the FCDGeometryPolygons and the FCDGeometryPolygonsInput classes.
*/
#ifndef _FCD_GEOMETRY_POLYGONS_H_
#define _FCD_GEOMETRY_POLYGONS_H_
#include "FCDocument/FCDObject.h"
#include "FUtils/FUDaeEnum.h"
class FCDocument;
class FRMeshPolygons;
class FCDMaterial;
class FCDGeometryMesh;
class FCDGeometrySource;
/**
An input data source for one mesh polygons set.
This structure knows the type of input data in the data source
as well as the set and offset for the data. It also contains a
pointer to the mesh data source.
Many polygon set inputs may have the same offset (or 'idx') when multiple
data sources are compressed together within the COLLADA document.
In this case, one and only one of the polygon set input will have
the 'ownsIdx' flag set. A polygon set input with this flag set will
contain valid indices. To find the indices of any polygon set input,
it is recommended that you use the FCDGeometryPolygons::FindIndicesForIdx function.
@ingroup FCDGeometry
*/
class FCDGeometryPolygonsInput
{
public:
/** Constructor. */
FCDGeometryPolygonsInput();
/** Determines the type of data to input. */
FUDaeGeometryInput::Semantic semantic;
/** Offset within the COLLADA document for this input.
All the inputs with the same offset value use the same indices within the COLLADA document. */
uint32 idx;
/** [INTERNAL] Offset owner flags. One and only one polygon set input will have this flag set for each offset value.
A polygon set input with this flag set will contain valid indices within the 'indices' member variable.
You should not set or access this flag directly. Instead, use the FCDGeometryPolygons::FindIndicesForIdx function. */
bool ownsIdx;
/** [INTERNAL] Tessellation indices. Use these indices to generate a list of unique vertices and generate your vertex buffers.
You should not set or access the indices directly. Instead, use the FCDGeometryPolygons::FindIndicesForIdx function. */
UInt32List indices;
/** Data source. This is the data source into which the indices are indexing. You need to take the data source
stride into consideration when unindexing the data. */
FCDGeometrySource* source;
/** Input set. Used to group together the texture coordinates with the texture tangents and binormals.
ColladaMax: this value should also represent the map channel index or texture coordinates
and vertex color channels. */
int32 set;
};
/** A dynamically-sized array of FCDGeometryPolygonsInput objects. */
typedef vector<FCDGeometryPolygonsInput*> FCDGeometryPolygonsInputList;
/**
A mesh polygon set.
Each polygon set contains a list of inputs and the tessellation information
to make polygons out of the data and indices of the input. FCollada
supports triangle lists as well as polygon lists and lists of polygons with holes.
This implies that each face has an undeterminate number of vertices.
The tessellation information creates polygons, but may also creates holes within the polygons.
@ingroup FCDGeometry
*/
class FCOLLADA_EXPORT FCDGeometryPolygons : public FCDObject
{
private:
FCDGeometryPolygonsInputList inputs;
FCDGeometryPolygonsInputList idxOwners;
UInt32List faceVertexCounts;
FCDGeometryMesh* parent;
size_t faceVertexCount;
UInt32List holeFaces;
// Buffered statistics
size_t faceOffset;
size_t faceVertexOffset;
size_t holeOffset;
// Material for this set of polygons
fstring materialSemantic;
public:
/** Constructor: do not use directly. Instead, use the FCDGeometryMesh::AddPolygons function
to create new polygon sets.
@param document The COLLADA document which owns this polygon set.
@param parent The geometric mesh which contains this polygon set.*/
FCDGeometryPolygons(FCDocument* document, FCDGeometryMesh* parent);
/** Destructor: do not use directly.
The mesh which contains this polygon set will handle its release. */
virtual ~FCDGeometryPolygons();
/** Retrieves the list of face-vertex counts. Each face within the polygon set
has one or more entry within this list, depending on the number of holes within that face.
Each face-vertex count indicates the number of ordered indices
within the polygon set inputs that are used to generate a face or its holes.
To find out if a face-vertex count represents a face or its holes, check
the hole-faces list retrieved using the GetHoleFaces function.
Indirectly, the face-vertex count indicates the degree of the polygon.
@see GetHoleFaces @see GetHoleCount
@return The list of face-vertex counts.*/
inline const UInt32List& GetFaceVertexCounts() const { return faceVertexCounts; }
/** Retrieves the number of holes within the faces of the polygon set.
@return The number of holes within the faces of the polygon set. */
inline size_t GetHoleCount() const { return holeFaces.size(); }
/** Retrieves the number of faces within the polygon set.
@return The number of faces within the polygon set. */
inline size_t GetFaceCount() const { return faceVertexCounts.size() - GetHoleCount(); }
/** Retrieves the number of faces which appear before this polygon set within the geometric mesh.
This value is useful when traversing all the faces of a geometric mesh.
@return The number of faces in previous polygon sets. */
inline size_t GetFaceOffset() const { return faceOffset; }
/** Retrieves the total number of face-vertex pairs within the polygon set.
This value is the total of all the values within the face-vertex count list.
Do remember that the list of face-vertex pairs includes holes.
@return The total number of face-vertex pairs within the polygon set. */
inline size_t GetFaceVertexCount() const { return faceVertexCount; }
/** Retrieves the number of face-vertex pairs for a given face.
This value includes face-vertex pairs that create the polygon and its holes.
@param index A face index.
@return The number of face-vertex pairs for a given face. */
size_t GetFaceVertexCount(size_t index) const;
/** Retrieves the total number of face-vertex pairs which appear
before this polygon set within the geometric mesh.
This value is useful when traversing all the face-vertex pairs of a geometric mesh.
@return The number of face-vertex pairs in previous polygon sets. */
inline size_t GetFaceVertexOffset() const { return faceVertexOffset; }
/** Retrieves the number of holes which appear before this polygon set.
This value is useful when traversing all the face-vertex pairs of a geometric mesh. */
inline size_t GetHoleOffset() const { return holeOffset; }
/** Retrieves the number of face-vertex pairs which appear
before a given face within the polygon set.
This value is useful when doing per-vertex mesh operations within the polygon set.
@param index The index of the face.
@return The number of face-vertex pairs before the given face, within the polygon set. */
size_t GetFaceVertexOffset(size_t index) const;
/** [INTERNAL] Sets the number of faces in previous polygon sets.
Used by the FCDGeometryMesh::Recalculate function.
@param offset The number of faces in previous polygon sets. */
inline void SetFaceOffset(size_t offset) { faceOffset = offset; }
/** [INTERNAL] Sets the number of face-vertex pairs in previous polygon sets.
Used by the FCDGeometryMesh::Recalculate function.
@param offset The number of face-vertex pairs in previous polygon sets. */
inline void SetFaceVertexOffset(size_t offset) { faceVertexOffset = offset; }
/** [INTERNAL] Sets the number of holes in previous polygon sets.
Used by the FCDGeometryMesh::Recalculate function.
@param offset The number of holes in previous polygon sets. */
inline void SetHoleOffset(size_t offset) { holeOffset = offset; }
/** Creates a new face.
Enough indices to fill the face will be added to the polygon set inputs: you will
want to overwrite those, as they will all be set to zero.
@param degree The degree of the polygon. This number implies the number of indices
that will be expected, in order, within each of the input index lists. */
void AddFace(uint32 degree);
/** Removes a face
@param index The index of the face to remove. All the indices associated
with this face will also be removed. */
void RemoveFace(size_t index);
/** Retrieves the list of polygon set inputs.
@see FCDGeometryPolygonsInput
@return The list of polygon set inputs. */
inline FCDGeometryPolygonsInputList& GetInputs() { return inputs; }
inline const FCDGeometryPolygonsInputList& GetInputs() const { return inputs; } /**< See above. */
/** Retrieves the number of polygon set inputs.
@return The number of polygon set inputs. */
inline size_t GetInputCount() const { return inputs.size(); }
/** Retrieves a specific polygon set input.
@param index The index of the polygon set input. This index should
not be greater than or equal to the number of polygon set inputs.
@return The specific polygon set input. This pointer will be NULL if the index is out-of-bounds. */
inline FCDGeometryPolygonsInput* GetInput(size_t index) { FUAssert(index < GetInputCount(), return NULL); return inputs.at(index); }
inline const FCDGeometryPolygonsInput* GetInput(size_t index) const { FUAssert(index < GetInputCount(), return NULL); return inputs.at(index); } /**< See above. */
/** Creates a new polygon set input.
@param source The data source for the polygon set input.
@param offset The tessellation indices offset for the polygon set input.
If this value is new to the list of polygon inputs, you will need to fill in the indices.
Please use the FindIndices function to verify that the offset is new and that indices need
to be provided. The offset of zero is reserved for per-vertex data sources.
@return The new polygon set input. */
FCDGeometryPolygonsInput* AddInput(FCDGeometrySource* source, uint32 offset);
/** Deletes a polygon set input.
This function releases the memory held by the polygon set input as well as moves
the indices to another polygon set input with the same offset, if the offset is re-used.
@param input The polygon set input to delete. */
void ReleaseInput(FCDGeometryPolygonsInput* input);
/** Retrieves the list of entries within the face-vertex count list
that are considered holes. COLLADA does not support holes within holes,
so each entry within this list implies a hole within the previous face.
@see GetFaceVertexCounts
@return The list of hole entries within the face-vertex counts. */
inline const UInt32List& GetHoleFaces() const { return holeFaces; }
/** Retrieves the number of holes within faces of the polygon set that appear
before the given face index. This value is useful when trying to access
a specific face of a mesh, as holes and faces appear together within the
face-vertex degree list.
@param index A face index.
@return The number of holes within the polygon set that appear
before the given face index. */
size_t GetHoleCountBefore(size_t index) const;
/** Retrieves the number of holes within a given face.
@param index A face index.
@return The number of holes within the given face. */
size_t GetHoleCount(size_t index) const;
/** Retrieves the first polygon set input found that has the given data type.
@param semantic A type of geometry data.
@return The polygon set input. This pointer will be NULL if
no polygon set input matches the data type. */
FCDGeometryPolygonsInput* FindInput(FUDaeGeometryInput::Semantic semantic);
const FCDGeometryPolygonsInput* FindInput(FUDaeGeometryInput::Semantic semantic) const; /**< See above. */
/** Retrieves the polygon set input that points towards a given data source.
@param source A geometry data source.
@return The polygon set input. This pointer will be NULL if
no polygon set input matches the data source. */
FCDGeometryPolygonsInput* FindInput(FCDGeometrySource* source);
const FCDGeometryPolygonsInput* FindInput(const FCDGeometrySource* source) const; /**< See above. */
/** [INTERNAL] Retrieves the polygon set input that points towards a given data source.
@param sourceId The COLLADA id of a geometry data source.
@return The polygon set input. This pointer will be NULL if
no polygon set input matches the COLLADA id. */
FCDGeometryPolygonsInput* FindInput(const string& sourceId);
/** Retrieves all the polygon set inputs that have the given data type.
@param semantic A type of geometry data.
@param inputs A list of polygon set inputs to fill in. This list is not emptied by the function
and may remain untouched, if no polygon set input matches the given data type. */
void FindInputs(FUDaeGeometryInput::Semantic semantic, FCDGeometryPolygonsInputList& inputs);
/** Retrieves the tessellation indices for a given polygon set input offset.
@deprecated Instead, use the FindIndices function.
@param idx A polygon set input offset.
@return The tessellation indices corresponding to the offset. This pointer
will be NULL if there are no polygon set input which uses the given offset. */
UInt32List* FindIndicesForIdx(uint32 idx);
const UInt32List* FindIndicesForIdx(uint32 idx) const; /**< See above. */
/** Retrieves the first tessellation index list for a given data source.
@param source A data source.
@return The first tessellation index list corresponding to the data source. This pointer
will be NULL if the data source is not used within this polygon set. */
UInt32List* FindIndices(FCDGeometrySource* source);
const UInt32List* FindIndices(const FCDGeometrySource* source) const; /**< See above. */
/** Retrieves the tessellation indices for a given polygon set input.
@param input A given polygon set input.
@return The tessellation indices corresponding to the polygon set input. This pointer
will be NULL if the polygon set input is not used within this polygon set. */
UInt32List* FindIndices(FCDGeometryPolygonsInput* input);
const UInt32List* FindIndices(const FCDGeometryPolygonsInput* input) const; /**< See above. */
/** Retrieves the symbolic name for the material used on this polygon set.
Match this symbolic name within a FCDGeometryInstance to get the
correct material instance.
@return A symbolic material name. */
inline const fstring& GetMaterialSemantic() const { return materialSemantic; }
/** Triangulates the polygon set.
A simple fanning techique is currently used: holes will not be triangulated correctly. */
void Triangulate();
/** [INTERNAL] Recalculates the buffered offset and count values for this polygon set. */
void Recalculate();
/** [INTERNAL] Reads in the polygon set element from a given COLLADA XML tree node.
COLLADA has multiple polygon set elements. The most common ones are \<triangles\> and \<polylist\>.
@param polygonNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the polygon set.*/
FUStatus LoadFromXML(xmlNode* polygonNode);
/** [INTERNAL] Writes out the correct polygon set element to the given COLLADA XML tree node.
COLLADA has multiple polygon set elements. The most common ones are \<triangles\> and \<polylist\>.
@param parentNode The COLLADA XML parent node in which to insert the geometric mesh.
@return The created XML tree node. */
xmlNode* WriteToXML(xmlNode* parentNode) const;
/** [INTERNAL] Creates a copy of this mesh.
You should use the FCDGeometry::Clone function instead of this function.
You will need to release the cloned entity.
@param cloneParent The geometric mesh which will contain the cloned polygon set.
@return An identical copy of the polygon set. */
FCDGeometryPolygons* Clone(FCDGeometryMesh* cloneParent);
private:
// Performs operations needed before tessellation
bool InitTessellation(xmlNode* itNode,
uint32* localFaceVertexCount, UInt32List& allIndices,
const char* content, xmlNode*& holeNode, uint32 idxCount,
bool* failed);
};
#endif // _FCD_GEOMETRY_POLYGONS_H_

View File

@@ -0,0 +1,147 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDocument.h"
#include "FCDocument/FCDAnimated.h"
#include "FCDocument/FCDGeometrySource.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
#include "FUtils/FUDaeEnum.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDGeometrySource::FCDGeometrySource(FCDocument* document) : FCDObjectWithId(document, "GeometrySource")
{
sourceNode = NULL;
sourceStride = 0;
sourceType = FUDaeGeometryInput::UNKNOWN;
}
FCDGeometrySource::~FCDGeometrySource()
{
animatedValues.clear();
}
void FCDGeometrySource::SetSourceData(const FloatList& _sourceData, uint32 _sourceStride, size_t offset, size_t count)
{
// Remove all the data currently held by the source.
sourceData.clear();
sourceStride = _sourceStride;
// Check the given bounds
size_t beg = min(offset, _sourceData.size()), end;
if (count == 0) end = _sourceData.size();
else end = min(count + offset, _sourceData.size());
sourceData.insert(sourceData.begin(), _sourceData.begin() + beg, _sourceData.begin() + end);
}
void FCDGeometrySource::SetSourceType(FUDaeGeometryInput::Semantic type)
{
sourceType = type;
animatedValues.clear();
// Most types should remain un-animated
if (sourceType != FUDaeGeometryInput::POSITION && sourceType != FUDaeGeometryInput::COLOR) return;
// Look for an animation on this source's objects
Int32List animatedIndices;
GetDocument()->FindAnimationChannelsArrayIndices(sourceNode, animatedIndices);
for (Int32List::iterator itA = animatedIndices.begin(); itA != animatedIndices.end(); ++itA)
{
// Check for repeated animated indices
Int32List::iterator itB = animatedIndices.begin();
for (; itB != itA && (*itA) != (*itB); ++itB) {}
if (itB != itA) continue;
FCDAnimated* animated = NULL;
if (sourceType == FUDaeGeometryInput::POSITION)
{
animated = FCDAnimatedPoint3::Create(GetDocument(), sourceNode, (FMVector3*)&(sourceData[(*itA) * sourceStride]), *itA);
}
else
{
animated = FCDAnimatedColor::Create(GetDocument(), sourceNode, (FMVector3*)&(sourceData[(*itA) * sourceStride]), *itA);
}
// Keep track of these animated values
if (animated != NULL) animatedValues.push_back(animated);
}
}
// Clone this data source
FCDGeometrySource* FCDGeometrySource::Clone() const
{
FCDGeometrySource* clone = new FCDGeometrySource(GetDocument());
FCDObjectWithId::Clone(clone);
clone->name = name;
clone->sourceData = sourceData;
clone->sourceNode = sourceNode;
clone->sourceStride = sourceStride;
clone->SetSourceType(sourceType);
return clone;
}
// Read in the <source> node of the COLLADA document
FUStatus FCDGeometrySource::LoadFromXML(xmlNode* _sourceNode)
{
FUStatus status;
sourceNode = _sourceNode;
// Read in the name and id of the source
name = TO_FSTRING(ReadNodeName(sourceNode));
string id = ReadNodeId(sourceNode);
if (id.empty())
{
status.Warning(FS("Geometry source with no 'id' is unusable."), sourceNode->line);
}
SetDaeId(id);
if (!id.empty() && GetDaeId() != id)
{
return status.Fail(FS("Geometry source has duplicate 'id': ") + TO_FSTRING(id), sourceNode->line);
}
// Read in the source data
sourceStride = ReadSource(sourceNode, sourceData);
if (sourceStride == 0)
{
status.Warning(FS("Geometry has source with no data."), sourceNode->line);
}
return status;
}
// Write out the <source> node to the COLLADA xml tree
xmlNode* FCDGeometrySource::WriteToXML(xmlNode* parentNode) const
{
xmlNode* sourceNode = NULL;
// Export the source directly, using the correct parameters and the length factor
switch (sourceType)
{
case FUDaeGeometryInput::POSITION: sourceNode = AddSourceFloat(parentNode, GetDaeId(), sourceData, sourceStride, FUDaeAccessor::XYZW, GetDocument()->GetLengthUnitConversion()); break;
case FUDaeGeometryInput::NORMAL: sourceNode = AddSourceFloat(parentNode, GetDaeId(), sourceData, sourceStride, FUDaeAccessor::XYZW); break;
case FUDaeGeometryInput::GEOTANGENT: sourceNode = AddSourceFloat(parentNode, GetDaeId(), sourceData, sourceStride, FUDaeAccessor::XYZW); break;
case FUDaeGeometryInput::GEOBINORMAL: sourceNode = AddSourceFloat(parentNode, GetDaeId(), sourceData, sourceStride, FUDaeAccessor::XYZW); break;
case FUDaeGeometryInput::TEXCOORD: sourceNode = AddSourceFloat(parentNode, GetDaeId(), sourceData, sourceStride, FUDaeAccessor::STPQ); break;
case FUDaeGeometryInput::TEXTANGENT: sourceNode = AddSourceFloat(parentNode, GetDaeId(), sourceData, sourceStride, FUDaeAccessor::XYZW); break;
case FUDaeGeometryInput::TEXBINORMAL: sourceNode = AddSourceFloat(parentNode, GetDaeId(), sourceData, sourceStride, FUDaeAccessor::XYZW); break;
case FUDaeGeometryInput::UV: sourceNode = AddSourceFloat(parentNode, GetDaeId(), sourceData, sourceStride, FUDaeAccessor::XYZW); break;
case FUDaeGeometryInput::COLOR: sourceNode = AddSourceFloat(parentNode, GetDaeId(), sourceData, sourceStride, FUDaeAccessor::RGBA); break;
case FUDaeGeometryInput::EXTRA: sourceNode = AddSourceFloat(parentNode, GetDaeId(), sourceData, sourceStride, NULL); break;
case FUDaeGeometryInput::UNKNOWN: sourceNode = AddSourceFloat(parentNode, GetDaeId(), sourceData, sourceStride, NULL); break;
case FUDaeGeometryInput::VERTEX: // Refuse to export these sources
default: break;
}
if (!name.empty())
{
AddAttribute(sourceNode, DAE_NAME_ATTRIBUTE, name);
}
return sourceNode;
}

View File

@@ -0,0 +1,141 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
/**
@file FCDGeometrySource.h
This file contains the FCDGeometrySource class.
*/
#ifndef _FCD_GEOMETRY_SOURCE_H_
#define _FCD_GEOMETRY_SOURCE_H_
#include "FCDocument/FCDObject.h"
#include "FUtils/FUDaeEnum.h"
class FCDAnimated;
/** A dynamically-sized array of FCDAnimated objects. */
typedef vector<FCDAnimated*> FCDAnimatedList;
/**
A COLLADA data source for geometric meshes.
A COLLADA data source for geometric meshes contains a list of floating-point values and the information
to parse these floating-point values into meaningful content: the stride of the list and the type of data
that the floating-point values represent. When the floating-point values are split according to the stride,
you get multiple elemental values of the given type. A data source may also have a user-generated name to
identify the data within. The name is optional and is used to keep around the user-friendly name for texture coordinate
sets or color sets.
The values of the COLLADA data source may be animated individually, or together: as an element.
@ingroup FCDGeometry
*/
class FCOLLADA_EXPORT FCDGeometrySource : public FCDObjectWithId
{
private:
fstring name;
FloatList sourceData;
uint32 sourceStride;
xmlNode* sourceNode;
FUDaeGeometryInput::Semantic sourceType;
// The animated values held here are contained within the document.
FCDAnimatedList animatedValues;
public:
/** Constructor: do not use directly.
Use FCDGeometryMesh::AddSource or FCDGeometryMesh::AddValueSource instead.
@param document The COLLADA document which owns the data source. */
FCDGeometrySource(FCDocument* document);
/** Destructor: do not use directly.
The geometric mesh which contains the data source will release it. */
virtual ~FCDGeometrySource();
/** Retrieves the name of the data source. The name is optional and is used to
keep around a user-friendly name for texture coordinate sets or color sets.
@return The name of the data source. */
const fstring& GetName() const { return name; }
/** Retrieves the pure data of the data source. This is a dynamically-sized array of
floating-point values that contains all the data of the source.
@return The pure data of the data source. */
FloatList& GetSourceData() { return sourceData; }
const FloatList& GetSourceData() const { return sourceData; } /**< See above. */
/** Retrieves the stride of the data within the source.
There is no guarantee that the number of data values within the source is a multiple of the stride,
yet you should always verify that the stride is at least the wanted dimension. For example, there is
no guarantee that your vertex position data source has a stride of 3. 3dsMax is known to always
export 3D texture coordinate positions.
@return The stride of the data. */
uint32 GetSourceStride() const { return sourceStride; }
/** @deprecated Retrieves the COLLADA id for the source.
Use the class parent's GetDaeId function instead.
@return The COLLADA id. */
const string& GetSourceId() const { return GetDaeId(); }
/** Retrieves the list of animated values for the data of the source.
@return The list of animated values. */
FCDAnimatedList& GetAnimatedValues() { return animatedValues; }
const FCDAnimatedList& GetAnimatedValues() const { return animatedValues; } /**< See above. */
/** @deprecated [INTERNAL] Retrieves the XML tree node that represent this source.
This is used when computing the list of animated values.
@todo Take the XML tree node out of this class.
@return The XML tree node. This pointer is invalid if accessed after the document is
fully parsed. */
xmlNode* GetSourceNode() { return sourceNode; } // Should be taken out of this class
/** Retrieves the type of data contained within the source.
Common values for the type of data are POSITION, NORMAL, COLOR and TEXCOORD.
Please see FUDaeGeometryInput for more information.
@see FUDaeGeometryInput.
@return The type of data contained within the source. */
FUDaeGeometryInput::Semantic GetSourceType() const { return sourceType; }
/** Sets the user-friendly name of the data source. The name is optional and is used to
keep around a user-friendly name for texture coordinate sets or color sets.
@param _name The user-friendly name of the data source. */
void SetName(const fstring& _name) { name = _name; }
/** Overwrites the data contained within the data source.
@param _sourceData The new data for this source.
@param _sourceStride The stride for the new data.
@param offset The offset at which to start retrieving the new data.
This argument defaults at 0 to indicate that the data copy should start from the beginning.
@param count The number of data entries to copy into the data source.
This argument defaults at 0 to indicate that the data copy should include everything. */
void SetSourceData(const FloatList& _sourceData, uint32 _sourceStride, size_t offset=0, size_t count=0);
/** [INTERNAL] Sets the XML tree node associated with the data source.
@todo Take the XML tree node out of this class.
@param _sourceNode A XML tree node. */
void SetSourceNode(xmlNode* _sourceNode) { sourceNode = _sourceNode; }
/** Sets the type of data contained within this data source.
@param type The new type of data for this data source. */
void SetSourceType(FUDaeGeometryInput::Semantic type);
/** [INTERNAL] Clones this data source. You will need to release this pointer manually.
@return An identical copy of the data source. */
FCDGeometrySource* Clone() const;
/** [INTERNAL] Reads in the \<source\> element from a given COLLADA XML tree node.
@param sourceNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the data source.*/
FUStatus LoadFromXML(xmlNode* sourceNode);
/** [INTERNAL] Writes out the \<source\> element to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the data source.
@return The created \<source\> element XML tree node. */
xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif // _FCD_GEOMETRY_SOURCE_H_

View File

@@ -0,0 +1,163 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDocument.h"
#include "FCDocument/FCDGeometry.h"
#include "FCDocument/FCDGeometrySource.h"
#include "FCDocument/FCDGeometrySpline.h"
#include "FUtils/FUStringConversion.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDGeometrySpline::FCDGeometrySpline(FCDocument* document, FCDGeometry* _parent) : FCDObject(document, "FCDGeometrySpline")
{
parent = _parent;
isClosed = false;
}
FCDGeometrySpline::~FCDGeometrySpline()
{
parent = NULL;
cvs.clear();
knots.clear();
}
// Read in the <spline> node of the COLLADA document
FUStatus FCDGeometrySpline::LoadFromXML(xmlNode* splineNode)
{
FUStatus status;
// Read the curve properties
isClosed = FUStringConversion::ToBoolean(ReadNodeProperty(splineNode, DAE_CLOSED_ATTRIBUTE));
// Read in the <control_vertices> element, which define the base type for this curve
xmlNode* cvsNode = FindChildByType(splineNode, DAE_CONTROL_VERTICES_ELEMENT);
if (cvsNode == NULL)
{
return status.Fail(FS("No <control_vertices> element in spline: ") + TO_FSTRING(parent->GetDaeId()), splineNode->line);
}
// Read in the per-vertex inputs
string positionSrc;
string sknots;
int hasPositions = 0;
int hasKnots = 0;
xmlNodeList vertexInputNodes;
FindChildrenByType(cvsNode, DAE_INPUT_ELEMENT, vertexInputNodes);
for (xmlNodeList::iterator it = vertexInputNodes.begin(); it < vertexInputNodes.end(); ++it)
{
xmlNode* vertexInputNode = *it;
string inputSemantic = ReadNodeSemantic(vertexInputNode);
if( strcmp(inputSemantic.c_str(), "POSITION" ) == 0 )
{
positionSrc = ReadNodeProperty(vertexInputNode,"source");
hasPositions = 1;
}
else if( strcmp(inputSemantic.c_str(), "KNOTSEQUENCES" ) == 0 )
{
sknots = ReadNodeProperty(vertexInputNode,"source");
hasKnots = 1;
}
}
if (!hasPositions)
{
return status.Warning(FS("No vertex position input node in spline: ") + TO_FSTRING(parent->GetDaeId()), splineNode->line);
}
if (!hasKnots)
{
return status.Warning(FS("No knot sequence input node in spline: ") + TO_FSTRING(parent->GetDaeId()), splineNode->line);
}
xmlNode* positionSrcNode = NULL;
xmlNode* knotSrcNode = NULL;
// Read in the data sources
xmlNodeList sourceDataNodes;
FindChildrenByType(splineNode, DAE_SOURCE_ELEMENT, sourceDataNodes);
for (xmlNodeList::iterator it = sourceDataNodes.begin(); it != sourceDataNodes.end(); ++it)
{
xmlNode* sourceNode = *it;
string srcid = ReadNodeProperty(*it,"id");
if( strcmp( srcid.c_str(), positionSrc.substr(1).c_str() ) == 0 )
positionSrcNode = sourceNode;
else if( strcmp( srcid.c_str(), sknots.substr(1).c_str() ) == 0 )
knotSrcNode = sourceNode;
}
if (positionSrcNode == NULL)
{
return status.Warning(FS("No vertex position source element in spline: ") + TO_FSTRING(parent->GetDaeId()), splineNode->line);
}
xmlNode* farrayNode = FindChildByType(positionSrcNode, "float_array");
if (farrayNode == NULL)
{
return status.Warning(FS("No vertex position float array element in spline: ") + TO_FSTRING(parent->GetDaeId()), positionSrcNode->line);
}
// Setup the curve data
const char* content = ReadNodeContentDirect(farrayNode);
int32 icount = ReadNodeCount(farrayNode);
for(int32 i = 0; i < icount / 3; ++i)
{
FMVector3 p = FUStringConversion::ToPoint(&content);
cvs.push_back(p);
}
farrayNode = FindChildByType(knotSrcNode, "float_array");
if(farrayNode==NULL)
{
return status.Warning(FS("No knot sequence float array element in spline: ") + TO_FSTRING(parent->GetDaeId()), farrayNode->line);
}
content = ReadNodeContentDirect(farrayNode);
icount = atoi(ReadNodeProperty( farrayNode, "count").c_str());
// setup the curve data
for( int i=0; i< icount; i++ )
{
float f = FUStringConversion::ToFloat(&content);
knots.push_back(double(f));
}
return status;
}
// Write out the <spline> node to the COLLADA xml tree
xmlNode* FCDGeometrySpline::WriteToXML(xmlNode* parentNode) const
{
xmlNode* splineNode = AddChild(parentNode, DAE_SPLINE_ELEMENT);
AddAttribute(splineNode, DAE_CLOSED_ATTRIBUTE, isClosed);
// Export the control point source
FUSStringBuilder controlPointSourceId(GetParent()->GetDaeId()); controlPointSourceId += "-cvs";
AddSourcePosition(splineNode, controlPointSourceId.ToCharPtr(), cvs);
// Export the knots
FUSStringBuilder knotSourceId(GetParent()->GetDaeId());
knotSourceId += "-knots";
FloatList floatKnots; floatKnots.reserve(knots.size());
for (FCDKnots::const_iterator itK = knots.begin(); itK != knots.end(); ++itK)
{
floatKnots.push_back(float(*itK));
}
AddSourceFloat(splineNode, knotSourceId.ToCharPtr(), floatKnots, "KNOT");
// Write out the control vertices information
xmlNode* verticesNode = AddChild(splineNode, DAE_CONTROL_VERTICES_ELEMENT);
AddInput(verticesNode, controlPointSourceId.ToCharPtr(), DAE_POSITION_SPLINE_INPUT);
AddInput(verticesNode, knotSourceId.ToCharPtr(), DAE_KNOT_SPLINE_INPUT);
return splineNode;
}

View File

@@ -0,0 +1,122 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
/**
@file FCDGeometrySpline.h
This file contains the FCDGeometrySpline class.
The FCDGeometrySpline class hold the information for one COLLADA geometric spline.
*/
#ifndef _FCD_GEOMETRY_SPLINE_H_
#define _FCD_GEOMETRY_SPLINE_H_
#include "FCDocument/FCDObject.h"
class FCDocument;
class FCDGeometry;
/** A dynamically-sized array of geometric spline control points. Each control point is simply one 3D position. @ingroup FCDGeometry */
typedef vector<FMVector3> FCDCVs;
/** A dynamically-sized array of weight values. Each weigth value represents a knot of a control point. @ingroup FCDGeometry */
typedef vector<double> FCDKnots;
/**
A COLLADA geometric spline.
A COLLADA spline contains a list of control points (CVs) that define an ordered list of 3D coordinates
that influence the spline. The spline also contains a matching list of knots: there should be as many control
points as there are knots.
A COLLADA spline may be closed or open. If the spline is closed, then the first control point should be
re-used when evaluating the last control point: the result should be a continuous curve, while an open
spline will result in a discontinuity at each end.
@todo: Insert the mathematical formula to calculate the spline position.
@ingroup FCDGeometry
*/
class FCOLLADA_EXPORT FCDGeometrySpline : public FCDObject
{
private:
FCDGeometry* parent;
FCDCVs cvs;
FCDKnots knots;
bool isClosed;
public:
/** Constructor: do not use directly. Use the FCDGeometry::CreateMesh function instead.
@param document The COLLADA document that owns the new spline.
@param parent The geometry entity that contains the new spline. */
FCDGeometrySpline(FCDocument* document, FCDGeometry* parent);
/** Destructor: do not use directly. All geometric splines are released with the geometry that they belong to. */
virtual ~FCDGeometrySpline();
/** Retrieve the parent of this geometric spline: the geometry entity.
@return The geometry entity that this spline belongs to. */
FCDGeometry* GetParent() { return parent; }
const FCDGeometry* GetParent() const { return parent; } /**< See above. */
/** Retrieves the list of control points for the spline.
@return The list of control points. */
inline FCDCVs& GetCVs() { return cvs; }
inline const FCDCVs& GetCVs() const { return cvs; } /**< See above. */
/** Retrieves the number of control points for the spline.
@return The control point count. */
inline size_t GetCVCount() const { return cvs.size(); }
/** Retrieves a specific control point of the spline.
@param index The index of the control point.
The index should always be less than the number of control point.
@return The control point. */
inline FMVector3* GetCV(size_t index) { FUAssert(index < GetCVCount(), return NULL); return &(cvs.at(index)); }
inline const FMVector3* GetCV(size_t index) const { FUAssert(index < GetCVCount(), return NULL); return &(cvs.at(index)); } /**< See above. */
/** Retrieves the list of knots for the spline.
@return The list of knots. */
inline FCDKnots& GetKnots() { return knots; }
inline const FCDKnots& GetKnots() const { return knots; } /**< See above. */
/** Retrieves the number of knots for the spline.
@return The knot count. */
inline size_t GetKnotCount() const { return knots.size(); }
/** Retrieves a specific knot of the spline.
@param index The index of the knot. The index should always be less than the number of knots.
@return The knot value. */
inline double GetKnot(size_t index) const { FUAssert(index < GetKnotCount(), return 0.0); return knots.at(index); }
/** Retrieves whether this spline is closed.
@return Whether the spline is closed. */
inline bool IsClosed() const { return isClosed; }
/** Retrieves whether this spline is open.
@return Whether the spline is open. */
inline bool IsOpen() const { return !isClosed; }
/** Overwrites the list of control points for this spline with a new ordered list of control points.
@param _cvs The new control points. */
inline void SetCVs(const FCDCVs& _cvs) { cvs = _cvs; }
/** Overwrites the list of knots for this spline with a new ordered list of knots.
@param _knots The new knots. */
inline void SetKnots(const FCDKnots& _knots) { knots = _knots; }
/** Sets the spline closed state.
@param _isClosed The new closed state. */
inline void SetClosed(bool _isClosed) { isClosed = _isClosed; }
/** [INTERNAL] Reads in the \<spline\> element from a given COLLADA XML tree node.
@param splineNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the spline.*/
FUStatus LoadFromXML(xmlNode* splineNode);
/** [INTERNAL] Writes out the \<spline\> element to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the spline information.
@return The created \<spline\> element XML tree node. */
xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif // _FCD_GEOMETRY_SPLINE_H_

View File

@@ -0,0 +1,82 @@
/*
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/FCDImage.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
#include "FUtils/FUFileManager.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDImage::FCDImage(FCDocument* document) : FCDEntity(document, "Image")
{
width = 0;
height = 0;
depth = 0;
}
FCDImage::~FCDImage()
{
}
// Read in the image information from the COLLADA document
FUStatus FCDImage::LoadFromXML(xmlNode* imageNode)
{
FUStatus status = FCDEntity::LoadFromXML(imageNode);
if (!status) return status;
if (!IsEquivalent(imageNode->name, DAE_IMAGE_ELEMENT))
{
return status.Warning(FS("Image library contains unknown element."), imageNode->line);
}
if(HasNodeProperty(imageNode, DAE_WIDTH_ELEMENT))
width = FUStringConversion::ToUInt32(ReadNodeProperty(imageNode, DAE_WIDTH_ELEMENT));
if(HasNodeProperty(imageNode, DAE_HEIGHT_ELEMENT))
height = FUStringConversion::ToUInt32(ReadNodeProperty(imageNode, DAE_HEIGHT_ELEMENT));
if(HasNodeProperty(imageNode, DAE_DEPTH_ELEMENT))
depth = FUStringConversion::ToUInt32(ReadNodeProperty(imageNode, DAE_DEPTH_ELEMENT));
// Read in the image's filename, within the <init_from> element: binary images are not supported.
xmlNode* filenameSourceNode = FindChildByType(imageNode, DAE_INITFROM_ELEMENT);
filename = TO_FSTRING(ReadNodeContentDirect(filenameSourceNode));
// COLLADA 1.3 backward-compatibility
if (filename.empty()) filename = TO_FSTRING(ReadNodeSource(imageNode));
// Convert the filename to something the OS can use
filename = GetDocument()->GetFileManager()->GetFilePath(filename);
if (filename.empty())
{
return status.Fail(FS("Invalid filename for image: ") + TO_FSTRING(GetDaeId()), imageNode->line);
}
return status;
}
// Write out the image information to the COLLADA xml tree node
xmlNode* FCDImage::WriteToXML(xmlNode* parentNode) const
{
xmlNode* imageNode = WriteToEntityXML(parentNode, DAE_IMAGE_ELEMENT);
if (!filename.empty())
{
fstring url = GetDocument()->GetFileManager()->GetFileURL(filename, true);
AddChild(imageNode, DAE_INITFROM_ELEMENT, url);
}
if (width > 0) AddAttribute(imageNode, DAE_WIDTH_ELEMENT, width);
if (height > 0) AddAttribute(imageNode, DAE_HEIGHT_ELEMENT, height);
if (depth > 0) AddAttribute(imageNode, DAE_DEPTH_ELEMENT, depth);
WriteToExtraXML(imageNode);
return imageNode;
}

View File

@@ -0,0 +1,125 @@
/*
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
*/
/**
@file FCDImage.h
This file contains the FCDImage class.
*/
#ifndef _FCD_IMAGE_H_
#define _FCD_IMAGE_H_
#include "FCDocument/FCDEntity.h"
class FCDocument;
/**
A COLLADA image.
A COLLADA image encapsulates an image file and are contained
within the image library. FCollada doesn't support inlined image bits.
An image is solely defined by its filename. For some
image types and optionally, the width, height and depth of
the image may be required and valid.
@ingroup FCDEffect
*/
class FCOLLADA_EXPORT FCDImage : public FCDEntity
{
private:
fstring filename;
uint32 width;
uint32 height;
uint32 depth;
public:
/** Constructor: do not use directly.
Instead, use the FCDLibrary::AddEntity function.
@param document The COLLADA document that owns the image. */
FCDImage(FCDocument* document);
/** Destructor: do not use directly.
Instead, use the FCDLibrary::ReleaseEntity function. */
virtual ~FCDImage();
/** Retrieves the entity type for this class. This function is part
of the FCDEntity class interface.
@return The entity type: IMAGE. */
virtual Type GetType() const { return IMAGE; }
/** Retrieves the filename of the image file.
This is the image file that you should load when attempting
to use the image bits. FCollada will deal with the filename
internally and provide an absolute filename.
@return The filename of the image file. */
const fstring& GetFilename() const { return filename; }
/** Sets the filename of the image file.
This is the image file that you should load when attempting
to use the image bits. FCollada will deal with the filename
internally and export a relative filename.
@param _filename The filename of the image file. */
void SetFilename(const fstring& _filename) { filename = _filename; }
/** Retrieves the width of the image.
This parameter is useful for off-screen render targets and is
optional for texture image files.
@return The width of the image. This value will be zero to indicate
that you should retrieve the width of the image from the image file. */
const uint32& GetWidth() const { return width; }
/** Sets the width of the image.
This parameter is useful for off-screen render targets and is
optional for texture image files.
@param _width The width of the image. This value can be zero to indicate
that you should retrieve the width of the image from the image file. */
void SetWidth(uint32 _width) { width = _width; }
/** Retrieves the height of the image.
This parameter is useful for off-screen render targets and is
optional for texture image files.
@return The height of the image. This value will be zero to indicate
that you should retrieve the height of the image from the image file. */
const uint32& GetHeight() const { return height; }
/** Sets the height of the image.
This parameter is useful for off-screen render targets and is
optional for texture image files.
@param _height The height of the image. This value can be zero to indicate
that you should retrieve the width of the image from the image file. */
void SetHeight(uint32 _height) { height = _height; }
/** Retrieves the depth of the 3D image.
This parameter is optional for texture image files.
@return The depth of the image. This value will be zero to indicate
that you should retrieve the depth of the image from the image file. */
const uint32& GetDepth() const { return depth; }
/** Sets the depth of the 3D image.
This parameter is optional for texture image files.
@param _depth The depth of the image. This value can be zero to indicate
that you should retrieve the depth of the image from the image file. */
void SetDepth(uint32 _depth) { depth = _depth; }
/** [INTERNAL] Reads in the \<image\> element from a given COLLADA XML tree node.
@param imageNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the image.*/
virtual FUStatus LoadFromXML(xmlNode* imageNode);
/** [INTERNAL] Writes out the \<image\> element to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the image.
@return The created element XML tree node. */
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif // _FCD_IMAGE_H_

View File

@@ -0,0 +1,112 @@
/*
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
*/
/**
@file FCDLibrary.h
This file contains the FCDLibrary template class.
See the FCDLibrary.hpp file for the template implementation.
*/
#ifndef _FCD_LIBRARY_
#define _FCD_LIBRARY_
class FCDocument;
class FCDEntity;
#include "FCDocument/FCDObject.h"
/**
A COLLADA library.
A COLLADA library holds a list of entities. There are libraries for the following entities:
animations (FCDAnimation), animation clips (FCDAnimationClip), meshes and splines (FCDGeometry),
materials (FCDMaterial), effects (FCDEffect), images (FCDImage), skins and morphers (FCDController),
cameras (FCDCamera), lights (FCDLight), physics models (FCDPhysicsModel), physics materials
(FCDPhysicsMaterial), physics scenes (FCDPhysicsSceneNode) and visual scenes (FCDSceneNode).
The COLLADA libraries are contained within the FCDocument object.
@ingroup FCDocument
*/
template <class T>
class FCDLibrary : public FCDObject
{
protected:
/** The list type for the entities. */
typedef vector<T*> FCDEntityList;
/** Entities list. This list should contain all the root entities of the correct type.
Note that the following entity types are tree-based, rather than list-based: FCDAnimation,
FCDSceneNode and FCDPhysicsSceneNode. */
FCDEntityList entities;
public:
/** Constructor: do not use directly.
All the necessary libraries are created by the FCDocument object during its creation.
@param document The parent document. */
FCDLibrary(FCDocument* document);
/** Destructor: do not use directly.
The libraries are released by the FCDocument, just before it is released. */
virtual ~FCDLibrary();
/** Create a new entity within this library.
@return The newly created entity. */
T* AddEntity();
/** Releases an entity contained within this library.
@param entity The entity to delete. */
void ReleaseEntity(T* entity);
/** Retrieve the library entity with the given COLLADA id.
@param daeId The COLLADA id of the entity.
@return The library entity which matches the COLLADA id.
This pointer will be NULL if no matching entity was found. */
T* FindDaeId(const string& daeId);
/** Returns whether the library contains no entities.
@return Whether the library is empty. */
inline bool IsEmpty() const { return entities.empty(); }
/** [INTERNAL] Reads in the contents of the library from the COLLADA XML document.
@param node The COLLADA XML tree node to parse into entities.
@return The status of the import. If the status is not successful, it may be dangerous to
extract information from the library. */
virtual FUStatus LoadFromXML(xmlNode* node);
/** [INTERNAL] Writes out the library entities to the COLLADA XML document.
@param node The COLLADA XML tree node in which to write the library entities. */
virtual void WriteToXML(xmlNode* node) const;
/** @deprecated [INTERNAL] Retrieves the list of post-processing commands for the entities of this library.
@return The list of post-processing commands. */
StringList GetPostProcessCmds() const;
/** Retrieve the number of entities within the library.
@return the number of entities contained within the library. */
inline size_t GetEntityCount() const { return entities.size(); }
/** Retrieve an indexed entity from the library.
@param index The index of the entity to retrieve.
Should be within the range [0, GetEntityCount()[.
@return The indexed entity. */
inline T* GetEntity(size_t index) { FUAssert(index < GetEntityCount(), return NULL); return entities.at(index); }
/** Retrieve an indexed entity from the library.
@param index The index of the entity to retrieve.
Should be within the range [0, GetEntityCount()[.
@return The indexed entity. */
inline const T* GetEntity(size_t index) const { FUAssert(index < GetEntityCount(), return NULL); return entities.at(index); }
};
#include "FCDocument/FCDLibrary.hpp"
#endif // _FCD_LIBRARY_

View File

@@ -0,0 +1,92 @@
/*
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 "FUtils/FUDaeParser.h"
template <class T>
FCDLibrary<T>::FCDLibrary(FCDocument* document) : FCDObject(document, "FCDLibrary")
{
}
template <class T>
FCDLibrary<T>::~FCDLibrary()
{
CLEAR_POINTER_VECTOR(entities);
}
// Create a new entity within this library
template <class T>
T* FCDLibrary<T>::AddEntity()
{
T* entity = new T(GetDocument());
entities.push_back(entity);
return entity;
}
// Deletes a entity of this library
template <class T>
void FCDLibrary<T>::ReleaseEntity(T* entity)
{
// Not yet implemented, as this will most likely result in dangling pointers!
// Needs more structure...
}
// Read in a list of entities for a library of a COLLADA document
template <class T>
FUStatus FCDLibrary<T>::LoadFromXML(xmlNode* node)
{
FUStatus status;
for (xmlNode* entityNode = node->children; entityNode != NULL; entityNode = entityNode->next)
{
if (entityNode->type == XML_ELEMENT_NODE)
{
T* entity = AddEntity();
status.AppendStatus(entity->LoadFromXML(entityNode));
}
}
return status;
}
// Write out the library to the COLLADA xml document
template <class T>
void FCDLibrary<T>::WriteToXML(xmlNode* node) const
{
for (typename FCDEntityList::const_iterator itEntity = entities.begin(); itEntity != entities.end(); ++itEntity)
{
const T* entity = (const T*) (*itEntity);
entity->WriteToXML(node);
}
}
// Search for the entity in this library with a given COLLADA id.
template <class T>
T* FCDLibrary<T>::FindDaeId(const string& _daeId)
{
const char* daeId = FUDaeParser::SkipPound(_daeId);
for (typename FCDEntityList::iterator itEntity = entities.begin(); itEntity != entities.end(); ++itEntity)
{
if ((*itEntity)->GetDaeId() == daeId) return (*itEntity);
}
return NULL;
}
template <class T>
StringList FCDLibrary<T>::GetPostProcessCmds() const
{
StringList res;
for (typename FCDEntityList::const_iterator itEntity = entities.begin(); itEntity != entities.end(); ++itEntity)
{
res = (*itEntity)->GetPostProcessCmds();
}
return res;
}

View File

@@ -0,0 +1,282 @@
/*
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/FCDLight.h"
#include "FCDocument/FCDSceneNode.h"
#include "FUtils/FUStringConversion.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDLight::FCDLight(FCDocument* document) : FCDTargetedEntity(document, "Light")
{
color = FMVector3(1.0f, 1.0f, 1.0f);
intensity = 1.0f;
lightType = POINT;
constantAttenuationFactor = linearAttenuationFactor = quadracticAttenuationFactor = 0.0f;
fallOffExponent = 1.0f;
outerAngle = fallOffAngle = 30.0f;
penumbraAngle = 0.0f;
dropoff = 10.0f;
overshoots = true;
}
FCDLight::~FCDLight()
{
}
// Load this light from the given COLLADA document's node
FUStatus FCDLight::LoadFromXML(xmlNode* lightNode)
{
FUStatus status = FCDEntity::LoadFromXML(lightNode);
if (!status) return status;
if (!IsEquivalent(lightNode->name, DAE_LIGHT_ELEMENT))
{
return status.Warning(FS("Light library contains unknown element."), lightNode->line);
}
// Grab the <technique_common> element. If not present, assume COLLADA 1.3
xmlNode* commonTechniqueNode = FindChildByType(lightNode, DAE_TECHNIQUE_COMMON_ELEMENT);
bool isCollada1_3 = commonTechniqueNode == NULL;
xmlNode* maxTechniqueNode = FindTechnique(lightNode, DAEMAX_MAX_PROFILE);
xmlNode* mayaTechniqueNode = FindTechnique(lightNode, DAEMAYA_MAYA_PROFILE);
// Create the correct light source
xmlNode* lightParameterNode = NULL;
if (isCollada1_3)
{
// COLLADA 1.3 backward-compatibility: read the 'type' attribute of the <light> element
string type = ReadNodeProperty(lightNode, DAE_TYPE_ATTRIBUTE);
if (type == DAE_AMBIENT_LIGHT_TYPE) lightType = AMBIENT;
else if (type == DAE_DIRECTIONAL_LIGHT_TYPE) lightType = DIRECTIONAL;
else if (type == DAE_POINT_LIGHT_TYPE) lightType = POINT;
else if (type == DAE_SPOT_LIGHT_TYPE) lightType = SPOT;
else
{
status.Warning(FS("Unknown light type value for light: ") + TO_FSTRING(GetDaeId()), lightNode->line);
}
// COLLADA 1.3.2 backward-compatibility: look for this hack for the parameters under a common-profile technique
lightParameterNode = FindTechnique(lightNode, DAE_COMMON_PROFILE);
if (lightParameterNode == NULL) lightParameterNode = lightNode;
}
else
{
// Look for the <point>, <directional>, <spot> or <ambient> element under the common-profile technique
for (xmlNode* child = commonTechniqueNode->children; child != NULL; child = child->next)
{
if (child->type != XML_ELEMENT_NODE) continue;
if (IsEquivalent(child->name, DAE_LIGHT_POINT_ELEMENT)) { lightParameterNode = child; lightType = POINT; break; }
else if (IsEquivalent(child->name, DAE_LIGHT_SPOT_ELEMENT)) { lightParameterNode = child; lightType = SPOT; break; }
else if (IsEquivalent(child->name, DAE_LIGHT_AMBIENT_ELEMENT)) { lightParameterNode = child; lightType = AMBIENT; break; }
else if (IsEquivalent(child->name, DAE_LIGHT_DIRECTIONAL_ELEMENT)) { lightParameterNode = child; lightType = DIRECTIONAL; break; }
else
{
status.Warning(FS("Unknown element under <light><technique_common> for light: ") + TO_FSTRING(GetDaeId()), child->line);
}
}
}
// Verify the light's basic structures are found
if (lightParameterNode == NULL)
{
return status.Fail(FS("Unable to find the parameter root node for light: ") + TO_FSTRING(GetDaeId()), lightNode->line);
}
// Retrieve the light parameters
StringList parameterNames;
xmlNodeList parameterNodes;
FindParameters(lightParameterNode, parameterNames, parameterNodes);
FindParameters(maxTechniqueNode, parameterNames, parameterNodes);
FindParameters(mayaTechniqueNode, parameterNames, parameterNodes);
xmlNode* extraNode = FindChildByType(lightNode, DAE_EXTRA_ELEMENT);
xmlNode* maxExtraNode = FindTechnique(extraNode, DAEMAX_MAX_PROFILE);
FindParameters(maxExtraNode, parameterNames, parameterNodes);
// Parse the light parameters
FUDaeFunction::Function attenuationFunction = FUDaeFunction::CONSTANT;
float attenuationFactor = 0.0f;
xmlNode* attenuationFactorNode = NULL;
size_t parameterCount = parameterNodes.size();
for (size_t i = 0; i < parameterCount; ++i)
{
xmlNode* parameterNode = parameterNodes[i];
const string& parameterName = parameterNames[i];
const char* content = ReadNodeContentDirect(parameterNode);
if (parameterName == DAE_COLOR_LIGHT_PARAMETER || parameterName == DAE_COLOR_LIGHT_PARAMETER1_3)
{
color = FUStringConversion::ToPoint(content);
FCDAnimatedColor::Create(GetDocument(), parameterNode, &color);
}
else if (parameterName == DAE_CONST_ATTENUATION_LIGHT_PARAMETER)
{
constantAttenuationFactor = FUStringConversion::ToFloat(content);
FCDAnimatedFloat::Create(GetDocument(), parameterNode, &constantAttenuationFactor);
}
else if (parameterName == DAE_LIN_ATTENUATION_LIGHT_PARAMETER)
{
linearAttenuationFactor = FUStringConversion::ToFloat(content);
FCDAnimatedFloat::Create(GetDocument(), parameterNode, &linearAttenuationFactor);
}
else if (parameterName == DAE_QUAD_ATTENUATION_LIGHT_PARAMETER)
{
quadracticAttenuationFactor = FUStringConversion::ToFloat(content);
FCDAnimatedFloat::Create(GetDocument(), parameterNode, &quadracticAttenuationFactor);
}
else if (parameterName == DAE_ATTENUATION_LIGHT_PARAMETER1_3)
{
attenuationFunction = FUDaeFunction::FromString(content);
}
else if (parameterName == DAE_ATTENUATIONSCALE_LIGHT_PARAMETER1_3)
{
attenuationFactor = FUStringConversion::ToFloat(content);
attenuationFactorNode = parameterNode;
}
else if (parameterName == DAE_FALLOFFEXPONENT_LIGHT_PARAMETER)
{
fallOffExponent = FUStringConversion::ToFloat(content);
FCDAnimatedFloat::Create(GetDocument(), parameterNode, &fallOffExponent);
}
else if (parameterName == DAE_FALLOFF_LIGHT_PARAMETER1_3)
{
fallOffExponent = (float) FUDaeFunction::FromString(content);
}
else if (parameterName == DAE_FALLOFFANGLE_LIGHT_PARAMETER || parameterName == DAE_ANGLE_LIGHT_PARAMETER1_3)
{
fallOffAngle = FUStringConversion::ToFloat(content);
FCDAnimatedFloat::Create(GetDocument(), parameterNode, &fallOffAngle);
}
else if (parameterName == DAESHD_INTENSITY_LIGHT_PARAMETER || parameterName == DAESHD_INTENSITY_LIGHT_PARAMETER1_3)
{
intensity = FUStringConversion::ToFloat(content);
FCDAnimatedFloat::Create(GetDocument(), parameterNode, &intensity);
}
else if (parameterName == DAEMAX_OUTERCONE_LIGHT_PARAMETER || parameterName == DAEMAX_OUTERCONE_LIGHT_PARAMETER1_3)
{
outerAngle = FUStringConversion::ToFloat(content);
FCDAnimatedFloat::Create(GetDocument(), parameterNode, &outerAngle);
}
else if (parameterName == DAEMAX_OVERSHOOT_LIGHT_PARAMETER || parameterName == DAEMAX_OVERSHOOT_LIGHT_PARAMETER1_3)
{
overshoots = FUStringConversion::ToBoolean(content);
}
else if (parameterName == DAEMAX_TARGET_LIGHT_PARAMETER || parameterName == DAEMAX_TARGET_LIGHT_PARAMETER1_3)
{
SetTargetId(content);
}
else if (parameterName == DAEMAYA_PENUMBRA_LIGHT_PARAMETER || parameterName == DAEMAYA_PENUMBRA_LIGHT_PARAMETER1_3)
{
penumbraAngle = FUStringConversion::ToFloat(content);
FCDAnimatedFloat::Create(GetDocument(), parameterNode, &penumbraAngle);
}
else if (parameterName == DAEMAYA_DROPOFF_LIGHT_PARAMETER || parameterName == DAE_FALLOFFSCALE_LIGHT_PARAMETER1_3)
{
dropoff = FUStringConversion::ToFloat(content);
FCDAnimatedFloat::Create(GetDocument(), parameterNode, &dropoff);
}
else if (parameterName == DAEMAX_ASPECTRATIO_LIGHT_PARAMETER || parameterName == DAEMAX_ASPECTRATIO_LIGHT_PARAMETER1_3)
{
aspectRatio = FUStringConversion::ToFloat(content);
FCDAnimatedFloat::Create(GetDocument(), parameterNode, &aspectRatio);
}
else
{
status.Warning(FS("Unknown program parameter for light: ") + TO_FSTRING(GetDaeId()), parameterNode->line);
}
}
if (attenuationFactorNode != NULL)
{
// Match the deprecated COLLADA 1.3 parameter's animation to the correct, new attenuation factor
switch (attenuationFunction)
{
case FUDaeFunction::CONSTANT:
constantAttenuationFactor = attenuationFactor;
FCDAnimatedFloat::Create(GetDocument(), attenuationFactorNode, &constantAttenuationFactor);
break;
case FUDaeFunction::LINEAR:
linearAttenuationFactor = attenuationFactor;
FCDAnimatedFloat::Create(GetDocument(), attenuationFactorNode, &linearAttenuationFactor);
break;
case FUDaeFunction::QUADRATIC:
quadracticAttenuationFactor = attenuationFactor;
FCDAnimatedFloat::Create(GetDocument(), attenuationFactorNode, &quadracticAttenuationFactor);
break;
default: break;
}
}
return status;
}
// Write out this light to the COLLADA XML document
xmlNode* FCDLight::WriteToXML(xmlNode* parentNode) const
{
// Create the base light node
xmlNode* lightNode = WriteToEntityXML(parentNode, DAE_LIGHT_ELEMENT);
xmlNode* baseNode = AddChild(lightNode, DAE_TECHNIQUE_COMMON_ELEMENT);
const char* baseNodeName;
switch (lightType)
{
case POINT: baseNodeName = DAE_LIGHT_POINT_ELEMENT; break;
case SPOT: baseNodeName = DAE_LIGHT_SPOT_ELEMENT; break;
case AMBIENT: baseNodeName = DAE_LIGHT_AMBIENT_ELEMENT; break;
case DIRECTIONAL: baseNodeName = DAE_LIGHT_DIRECTIONAL_ELEMENT; break;
default: baseNodeName = DAEERR_UNKNOWN_INPUT; break;
}
baseNode = AddChild(baseNode, baseNodeName);
// Add the application-specific technique
xmlNode* techniqueMayaNode = AddTechniqueChild(lightNode, DAEMAYA_MAYA_PROFILE);
xmlNode* techniqueMaxNode = AddTechniqueChild(lightNode, DAEMAX_MAX_PROFILE);
// Write out the light parameters
string colorValue = FUStringConversion::ToString(color);
xmlNode* colorNode = AddChild(baseNode, DAE_COLOR_LIGHT_PARAMETER, colorValue);
GetDocument()->WriteAnimatedValueToXML(&color.x, colorNode, "color");
xmlNode* attenuationBaseNode = (lightType == POINT || lightType == SPOT) ? baseNode : techniqueMaxNode;
xmlNode* attenuationNode = AddChild(attenuationBaseNode, DAE_CONST_ATTENUATION_LIGHT_PARAMETER, constantAttenuationFactor);
GetDocument()->WriteAnimatedValueToXML(&constantAttenuationFactor, attenuationNode, "constant_attenuation");
attenuationNode = AddChild(attenuationBaseNode, DAE_LIN_ATTENUATION_LIGHT_PARAMETER, linearAttenuationFactor);
GetDocument()->WriteAnimatedValueToXML(&linearAttenuationFactor, attenuationNode, "linear_attenuation");
attenuationNode = AddChild(attenuationBaseNode, DAE_QUAD_ATTENUATION_LIGHT_PARAMETER, quadracticAttenuationFactor);
GetDocument()->WriteAnimatedValueToXML(&quadracticAttenuationFactor, attenuationNode, "quadratic_attenuation");
xmlNode* falloffBaseNode = (lightType == SPOT) ? baseNode : techniqueMaxNode;
xmlNode* falloffNode = AddChild(falloffBaseNode, DAE_FALLOFFANGLE_LIGHT_PARAMETER, fallOffAngle);
GetDocument()->WriteAnimatedValueToXML(&fallOffAngle, falloffNode, "falloff_angle");
falloffNode = AddChild(falloffBaseNode, DAE_FALLOFFEXPONENT_LIGHT_PARAMETER, fallOffExponent);
GetDocument()->WriteAnimatedValueToXML(&fallOffExponent, falloffNode, "falloff_exponent");
xmlNode* intensityNode = AddChild(techniqueMaxNode, DAESHD_INTENSITY_LIGHT_PARAMETER, intensity);
AddChild(techniqueMayaNode, DAESHD_INTENSITY_LIGHT_PARAMETER, intensity);
GetDocument()->WriteAnimatedValueToXML(&intensity, intensityNode, "intensity");
xmlNode* outerAngleNode = AddChild(techniqueMaxNode, DAEMAX_OUTERCONE_LIGHT_PARAMETER, outerAngle);
GetDocument()->WriteAnimatedValueToXML(&outerAngle, outerAngleNode, "outer_angle");
xmlNode* penumbraAngleNode = AddChild(techniqueMayaNode, DAEMAYA_PENUMBRA_LIGHT_PARAMETER, penumbraAngle);
GetDocument()->WriteAnimatedValueToXML(&penumbraAngle, penumbraAngleNode, "penumbra_angle");
xmlNode* aspectRatioNode = AddChild(techniqueMaxNode, DAEMAX_ASPECTRATIO_LIGHT_PARAMETER, aspectRatio);
GetDocument()->WriteAnimatedValueToXML(&aspectRatio, aspectRatioNode, "aspect_ratio");
xmlNode* dropoffNode = AddChild(techniqueMayaNode, DAEMAYA_DROPOFF_LIGHT_PARAMETER, dropoff);
GetDocument()->WriteAnimatedValueToXML(&dropoff, dropoffNode, "dropoff");
AddChild(techniqueMaxNode, DAEMAX_OVERSHOOT_LIGHT_PARAMETER, overshoots);
if (GetTargetNode() != NULL) AddChild(techniqueMaxNode, DAEMAX_TARGET_LIGHT_PARAMETER, GetTargetNode()->GetDaeId());
FCDEntity::WriteToExtraXML(lightNode);
return lightNode;
}

View File

@@ -0,0 +1,286 @@
/*
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
*/
/**
@file FCDLight.h
This file contains the FCDLight class.
*/
#ifndef _FCD_LIGHT_H_
#define _FCD_LIGHT_H_
#include "FCDocument/FCDTargetedEntity.h"
#include "FUtils/FUDaeEnum.h"
class FCDocument;
class FCDSceneNode;
/**
A COLLADA light.
Based on the FCDTargetedEntity class to supported aimed lights.
COLLADA defines four types of native lights: point, spot, ambient and directional.
These four types are fully handled by this class: make sure to check the type flag
as well as which information to expect for each light type.
A COLLADA ambient light has a global color, which should be added to
all other lighting on all geometry.
A COLLADA directional light has a global color, which should be multiplied
to the cosine of the angle between the normal vector of a triangle
and the direction of the light. Note that the direction will be calculated
from the transforms, for each instance, and is not provided by this class.
A COLLADA point light has a color which attenuates as the distance increases
between the light position and the vertex being shaded. Note that the position
will be calculated from the transforms, for each instance,
and is not provided by this class.
A COLLADA spot light is a point light which lights only the objects that
appear within a specific angle, with respect to the direction of the light.
Note that the position and the direction will be calculated from the
transforms, for each instance, and is not provided by this class.
@ingroup FCDocument
*/
class FCOLLADA_EXPORT FCDLight : public FCDTargetedEntity
{
public:
/** The types of lights supported by this class. */
enum LightType
{
POINT, /**< A point light. This is the default type. */
SPOT, /**< A spot light. */
AMBIENT, /**< An ambient light. */
DIRECTIONAL /**< A directional light. */
};
private:
// Common Light parameters
FMVector3 color;
float intensity; // Max and Maya
LightType lightType;
// Point and spot light parameters
float constantAttenuationFactor;
float linearAttenuationFactor;
float quadracticAttenuationFactor;
// Spot-specific light parameters
float fallOffExponent;
float fallOffAngle;
float outerAngle; // Max-specific
float penumbraAngle; // Maya-specifc: these last two are are related as 'penumbra = outerAngle - fallOffAngle'.
float aspectRatio; // Max-specific, for rectangle lights
float dropoff; // Maya-specific
// Directional light parameters
// Overshoot is a Max-specific flag that sets a directional light to cover everything,
// rather than to be restricted to a cylinder defined by the fallOffAngle/outerAngle.
bool overshoots; // Max-specific
public:
/** Constructor: do not use directly. Create new lights using the FCDLibrary::AddEntity function.
@param document The COLLADA document that contains this light entity. */
FCDLight(FCDocument* document);
/** Destructor: do not release directly. Release lights using the FCDLibrary::ReleaseEntity function.
All lights are also released with the document that they belong to. */
virtual ~FCDLight();
/** Retrieves the entity type for this class. This function is part of the FCDEntity interface.
@return The entity type: LIGHT. */
virtual Type GetType() const { return LIGHT; }
/** Retrieves the base color for the light. To calculate the light color,
multiply the base color with the intensity.
@return The base color for the light. */
FMVector3& GetColor() { return color; }
const FMVector3& GetColor() const { return color; } /**< See above. */
/** Sets the base color for the light. To calculate the light color,
multiply the base color with the intensity.
@param col The base color for the light. */
void SetColor(const FMVector3& col) { color = col; }
/** Retrieves the intensity of the light. To calculate the light color,
multiply the base color with the intensity.
@return The intensity of the light. */
float& GetIntensity() { return intensity; }
const float& GetIntensity() const { return intensity; } /**< See above. */
/** Sets the intensity of the light. To calculate the light color,
multiply the base color with the intensity.
@param _intensity The intensity of the light. */
void SetIntensity(float _intensity) { intensity = _intensity; }
/** Retrieves the type of the light.
Make sure to check the type of light before using the values, as some values
may not make sense with some types of light.
@return The light type. */
LightType GetLightType() const { return lightType; }
/** Sets the type of the light. The default type of a new light is POINT.
@param type The light type. */
void SetLightType(LightType type) { lightType = type; }
/** Retrieves the constant attenuation factor for the light.
This value is valid only for point and spot lights.
@return The constant attenuation factor. */
float& GetConstantAttenuationFactor() { return constantAttenuationFactor; }
const float& GetConstantAttenuationFactor() const { return constantAttenuationFactor; } /**< See above. */
/** Sets the constant attenuation factor for the light.
This value is valid only for point and spot lights.
@param factor The constant attenuation factor. */
void SetConstantAttenuationFactor(float factor) { constantAttenuationFactor = factor; }
/** Retrieves the linear attenuation factor for the light.
This value is valid only for point and spot lights.
@return The linear attenuation factor. */
float& GetLinearAttenuationFactor() { return linearAttenuationFactor; }
const float& GetLinearAttenuationFactor() const { return linearAttenuationFactor; } /**< See above. */
/** Sets the linear attenuation factor for the light.
This value is valid only for point and spot lights.
@param factor The linear attenuation factor. */
void SetLinearAttenuationFactor(float factor) { linearAttenuationFactor = factor; }
/** Retrieves the quadratic attenuation factor for the light.
This value is valid only for point and spot lights.
@return The quadratic attenuation factor. */
float& GetQuadraticAttenuationFactor() { return quadracticAttenuationFactor; }
const float& GetQuadraticAttenuationFactor() const { return quadracticAttenuationFactor; } /**< See above. */
/** Sets the quadratic attenuation factor for the light.
This value is valid only for point and spot lights.
@param factor The quadratic attenuation factor. */
void SetQuadraticAttenuationFactor(float factor) { quadracticAttenuationFactor = factor; }
/** Retrieves the fall-off exponent for the light.
This value is valid only for spot lights. It determines
how fast the lighting turns off, with respect to
angles greater than the fall-off angle. This results in a smooth
lighting at the spot light's edges.
IMPORTANT NOTE: Neither ColladaMaya or ColladaMax use this value
as neither Maya or 3dsMax use this technique for soft lighting.
@return The spot light fall-off exponent. */
float& GetFallOffExponent() { return fallOffExponent; }
const float& GetFallOffExponent() const { return fallOffExponent; } /**< See above. */
/** Sets the fall-off exponent for the light.
@see GetFallOffExponent
@param exponent The spot light fall-off exponent. */
void SetFallOffExponent(float exponent) { fallOffExponent = exponent; }
/** Retrieves the fall-off angle for the light.
This value is valid only for spot lights. It defines
the cone of the spot light.
@return The spot light fall-off angle. */
float& GetFallOffAngle() { return fallOffAngle; }
const float& GetFallOffAngle() const { return fallOffAngle; } /**< See above. */
/** Sets the fall-off angle for the light.
@see GetFallOffAngle
@param angle The spot light fall-off angle. */
void SetFallOffAngle(float angle) { fallOffAngle = angle; }
/** Retrieves the outer angle for the light.
This value is valid only for spot lights. This value is only used
by documents exported by ColladaMax. This value should always be
greater than the fall-off angle. It represents the angle at which
the lighting is black. All lighting between the fall-off angle and
the outer angle is a linear interpolation between the light color
and black.
@return The spot light outer angle. */
float& GetOuterAngle() { return outerAngle; }
const float& GetOuterAngle() const { return outerAngle; } /**< See above. */
/** Sets the outer angle for the light.
@see GetOuterAngle
@param angle The spot light outer angle. */
void SetOuterAngle(float angle) { outerAngle = angle; }
/** Retrieves the penumbra angle for the light.
This value is valid only for spot lights. The value is only used
by documents exported by ColladaMaya. This value is relative to
the fall-off angle and may be negative. If this value is positive,
it determines the outer angle, as described above. If this value
is negative, the fall-off angle is used as the outer angle and the
fall-off angle + the penumbra angle is used as the full-lighting
angle.
@see GetOuterAngle
@return The spot light penumbra angle. */
float& GetPenumbraAngle() { return penumbraAngle; }
const float& GetPenumbraAngle() const { return penumbraAngle; } /**< See above. */
/** Sets the penumbra angle for the light.
@see GetPenumbraAngle
@param angle The spot light penumbra angle. */
void SetPenumbraAngle(float angle) { penumbraAngle = angle; }
/** Retrieves the aspect ratio for the light.
This value is only used by documents exported by ColladaMax.
This value is valid only for spot lights and directional lights
which project a rectangle (for pyramidal projection). It represents the ratio
of the projection's height to the projection's width and defines
the projection's rectangle. For pyramidal projections, the fall-off and outer angles
represent the width of the projection.
Note that there is no way to know if the projection is conic or pyramidal.
@return The aspect ratio of the light pyramidal projection. */
float& GetAspectRatio() { return aspectRatio; }
const float& GetAspectRatio() const { return aspectRatio; } /**< See above. */
/** Sets the aspect ratio for the light.
@see GetAspectRatio
@param ratio The aspect ratio of the light pyramidal projection. */
void SetAspectRatio(float ratio) { aspectRatio = ratio; }
/** Retrieves the drop-off for the light.
This value is only used by documents exported by ColladaMaya.
@return The drop-off for the light. */
float& GetDropoff() { return dropoff; }
const float& GetDropoff() const { return dropoff; } /**< See above. */
/** Sets the drop-off for the light.
This value is only used by documents exported by ColladaMaya.
@param factor The drop-off for the light. */
void SetDropoff(float factor) { dropoff = factor; }
/** Retrieves whether the directional light overshoots.
This value is only used by documents exported by ColladaMax.
This value is valid only for directional lights. This flag
represents whether the directional light has a global projection,
as defined in COLLADA, or a cylinder/prism projection.
Note that there is no way to know if the projection is conic or pyramidal.
@return Whether the directional light overshoots. */
bool DoesOvershoot() const { return overshoots; }
/** Sets whether the directional light overshoots.
@see DoesOvershoot
@param _overshoots The overshoot flag for the directional light. */
void SetOvershoot(bool _overshoots) { overshoots = _overshoots; }
/** [INTERNAL] Reads in the \<light\> element from a given COLLADA XML tree node.
@param lightNode A COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the light.*/
FUStatus LoadFromXML(xmlNode* lightNode);
/** [INTERNAL] Writes out the \<light\> element to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the geometry information.
@return The created XML tree node. */
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif // _FCD_LIGHT_H_

View File

@@ -0,0 +1,211 @@
/*
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/FCDEffect.h"
#include "FCDocument/FCDEffectParameter.h"
#include "FCDocument/FCDEffectParameterFactory.h"
#include "FCDocument/FCDEffectParameterList.h"
#include "FCDocument/FCDMaterial.h"
#include "FUtils/FUStringConversion.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
#include "FUtils/FUUniqueStringMap.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDMaterial::FCDMaterial(FCDocument* document) : FCDEntity(document, "VisualMaterial")
{
effect = NULL;
parameters = new FCDEffectParameterList(GetDocument(), true);
ownsEffect = false;
}
FCDMaterial::~FCDMaterial()
{
if (ownsEffect) SAFE_DELETE(effect);
effect = NULL;
SAFE_DELETE(parameters);
techniqueHints.clear();
}
// Cloning
FCDMaterial* FCDMaterial::Clone()
{
FCDMaterial* clone = new FCDMaterial(GetDocument());
FCDEntity::Clone(clone);
if (effect != NULL)
{
clone->ownsEffect = true;
clone->effect = effect->Clone();
}
SAFE_DELETE(clone->parameters);
clone->parameters = parameters->Clone();
return clone;
}
#ifdef __VISUALC__
#include <crtdbg.h>
#endif // __VISUALC__
// Flatten the material: remove all the modifier parameters from the parameter list, permanently modifying their base parameter
void FCDMaterial::Flatten()
{
for (FCDEffectParameterList::iterator itP = parameters->begin(); itP != parameters->end(); ++itP)
{
FCDEffectParameterList generators;
if ((*itP)->IsModifier())
{
// Overwrite the generators
FindParametersByReference((*itP)->GetReference(), generators);
for (FCDEffectParameterList::iterator itQ = generators.begin(); itQ != generators.end(); ++itQ)
{
if ((*itP) != (*itQ))
{
(*itP)->Overwrite(*itQ);
}
}
}
else
{
// Add this parameter to hierarchy below
if (effect != NULL) effect->AddParameter((*itP)->Clone());
}
}
CLEAR_POINTER_VECTOR(*parameters);
if (effect != NULL) effect->Flatten();
}
void FCDMaterial::AddParameter(FCDEffectParameter* parameter)
{
parameters->push_back(parameter);
}
// Look for the effect parameter with the correct semantic, in order to bind/set its value
FCDEffectParameter* FCDMaterial::FindParameterBySemantic(const string& semantic)
{
return (effect != NULL) ? effect->FindParameterBySemantic(semantic) : NULL;
}
void FCDMaterial::FindParametersBySemantic(const string& semantic, FCDEffectParameterList& _parameters)
{
parameters->FindSemantic(semantic, _parameters);
if (effect != NULL) effect->FindParametersBySemantic(semantic, _parameters);
}
void FCDMaterial::FindParametersByReference(const string& reference, FCDEffectParameterList& _parameters)
{
parameters->FindReference(reference, _parameters);
if (effect != NULL) effect->FindParametersByReference(reference, _parameters);
}
// Parse COLLADA document's <material> element
FUStatus FCDMaterial::LoadFromXML(xmlNode* materialNode)
{
CLEAR_POINTER_VECTOR(*parameters);
FUStatus status = FCDEntity::LoadFromXML(materialNode);
if (!status) return status;
if (!IsEquivalent(materialNode->name, DAE_MATERIAL_ELEMENT))
{
return status.Warning(FS("Unknown element in material library."), materialNode->line);
}
// Read in the effect pointer node
xmlNode* effectNode = FindChildByType(materialNode, DAE_INSTANCE_EFFECT_ELEMENT);
if (effectNode != NULL)
{
FUUri url = ReadNodeUrl(effectNode);
if (!url.prefix.empty())
{
return status.Warning(FS("Externally referenced effects are not supported. Material: ") + TO_FSTRING(GetDaeId()), effectNode->line);
}
else if (url.suffix.empty())
{
return status.Warning(FS("Empty material's <instance_effect> definition. Should instantiate an effect from the effect's library. Material: ") + TO_FSTRING(GetDaeId()), effectNode->line);
}
effect = GetDocument()->FindEffect(url.suffix);
// Read in the parameter modifications
for (xmlNode* child = effectNode->children; child != NULL; child = child->next)
{
if (child->type != XML_ELEMENT_NODE) continue;
if (IsEquivalent(child->name, DAE_FXCMN_SETPARAM_ELEMENT))
{
AddParameter(FCDEffectParameterFactory::LoadFromXML(GetDocument(), child, &status));
}
else if (IsEquivalent(child->name, DAE_FXCMN_HINT_ELEMENT))
{
FCDMaterialTechniqueHint& hint = *(techniqueHints.insert(techniqueHints.end(), FCDMaterialTechniqueHint()));
hint.platform = TO_FSTRING(ReadNodeProperty(child, DAE_PLATFORM_ATTRIBUTE));
hint.technique = ReadNodeProperty(child, DAE_REF_ATTRIBUTE);
}
}
}
else
{
// COLLADA 1.3 backward compatibility: look for the effect.
if(effect != NULL)
{
//kind of a hack: swap the ids between the material and the effect and append
//some weird extension to the effect id so that it doesn't conflict with anybody else.
effect->RemoveDaeId();
status = FCDEntity::LoadFromXML(materialNode);
if (!status) return status;
effect->SetDaeId(GetDaeId() + "_effect1.3");
}
}
if (effect == NULL)
{
return status.Warning(FS("Unable to find effect for material: ") + TO_FSTRING(GetDaeId()), materialNode->line);
}
return status;
}
// Write out the <material> element to the COLLADA xml tree
xmlNode* FCDMaterial::WriteToXML(xmlNode* parentNode) const
{
xmlNode* materialNode = WriteToEntityXML(parentNode, DAE_MATERIAL_ELEMENT);
// The <instance_effect> element is required in COLLADA 1.4
xmlNode* instanceEffectNode = AddChild(materialNode, DAE_INSTANCE_EFFECT_ELEMENT);
if (effect != NULL)
{
AddAttribute(instanceEffectNode, DAE_URL_ATTRIBUTE, string("#") + effect->GetDaeId());
// Write out the technique hints
for (FCDMaterialTechniqueHintList::const_iterator itH = techniqueHints.begin(); itH != techniqueHints.end(); ++itH)
{
xmlNode* hintNode = AddChild(instanceEffectNode, DAE_FXCMN_HINT_ELEMENT);
AddAttribute(hintNode, DAE_PLATFORM_ATTRIBUTE, (*itH).platform);
AddAttribute(hintNode, DAE_REF_ATTRIBUTE, (*itH).technique);
}
// Write out the parameters
for (FCDEffectParameterList::const_iterator itP = parameters->begin(); itP != parameters->end(); ++itP)
{
(*itP)->WriteToXML(instanceEffectNode);
}
}
else
{
AddAttribute(instanceEffectNode, DAE_URL_ATTRIBUTE, string("#"));
}
FCDEntity::WriteToExtraXML(materialNode);
return materialNode;
}

View File

@@ -0,0 +1,152 @@
/*
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
*/
/**
@file FCDMaterial.h
This file contains the FCDMaterail class and the FCDMaterialTechniqueHint structure.
*/
#ifndef _FCD_MATERIAL_H_
#define _FCD_MATERIAL_H_
#include "FCDocument/FCDEntity.h"
class FCDocument;
class FCDEffect;
class FCDEffectParameter;
class FCDEffectParameterList;
/**
A technique usage hint for a material.
This structure contains two strings to help applications
choose a technique within the material's instantiated effect
according to their application platform.
*/
class FCOLLADA_EXPORT FCDMaterialTechniqueHint
{
public:
fstring platform; /**< A platform semantic. COLLADA defines no platform semantics. */
string technique; /**< The sid for the technique to choose for the platform. */
};
/** A dynamically-sized list of material platform-technique hints. */
typedef vector<FCDMaterialTechniqueHint> FCDMaterialTechniqueHintList;
/**
A COLLADA material.
A COLLADA material is one of many abstraction level that defines how
to render mesh polygon sets. It instantiates an effect and may
overrides some of the effect parameters with its own values.
Unless you care about the construction history or memory, you should probably
use the FCDMaterialInstance::FlattenMaterial function.
@ingroup FCDocument
*/
class FCOLLADA_EXPORT FCDMaterial : public FCDEntity
{
private:
bool ownsEffect;
FCDEffect* effect;
FCDEffectParameterList* parameters;
FCDMaterialTechniqueHintList techniqueHints;
public:
/** Constructor: do not use directly.
Instead, use the FCDMaterialLibrary::AddMaterial function.
@param document The COLLADA document that owns the material. */
FCDMaterial(FCDocument* document);
/** Destructor: do not use directly.
The material library will release all the materials when it is
released. If you want to remove a material from the material library:
use the FCDMaterialLibrary::RemoveMaterial function. */
virtual ~FCDMaterial();
/** Retrieves the entity type for this class. This function is part
of the FCDEntity class interface.
@return The entity type: MATERIAL. */
virtual Type GetType() const { return FCDEntity::MATERIAL; }
/** Retrieves the effect instantiated for this material.
The parameters of the effect may be overwritten by this material.
You should either flatten the material using the FlattenMaterial function
or verify the parameter values manually using the parameter list accessors.
@return The instantiated effect. This pointer will be NULL if the material has no rendering. */
FCDEffect* GetEffect() { return effect; }
const FCDEffect* GetEffect() const { return effect; } /**< See above. */
/** Sets the effect instantiated for this material.
@param _effect The effect instantiated for this material. */
void SetEffect(FCDEffect* _effect) { effect = _effect; }
/** Retrieves the list of the material platform-technique hints.
@return The list of material platform-technique hints. */
FCDMaterialTechniqueHintList& GetTechniqueHints() { return techniqueHints; }
const FCDMaterialTechniqueHintList& GetTechniqueHints() const { return techniqueHints; } /**< See above. */
/** Retrieves the list of effect parameter overrides.
@return The list of effect parameter overrides. */
FCDEffectParameterList* GetParameters() { return parameters; }
const FCDEffectParameterList* GetParameters() const { return parameters; } /**< See above. */
/** Retrieves an effect parameter override. Looks for the effect parameter override with the correct
semantic, in order to bind or set its value. This function searches through the material and the
level of abstractions below.
@param semantic The effect parameter semantic to match.
@return The effect parameter override that matches the semantic.
This pointer will be NULL if no effect parameter override matches
the given semantic. */
FCDEffectParameter* FindParameterBySemantic(const string& semantic);
/** Retrieves a subset of the effect parameter override list.
Look for the effect parameter overrides with the correct semantic.
This function searches through the material and the level of abstractions below.
@param semantic The effect parameter semantic to match.
@param parameters The list of parameters to fill in. This list is not cleared. */
void FindParametersBySemantic(const string& semantic, FCDEffectParameterList& parameters);
/** Retrieves a subset of the effect parameter override list.
Look for the effect parameter overrides with the correct reference.
This function searches through the material and the level of abstractions below.
@param reference The effect parameter reference to match. In the case of effect
parameter generators, the reference is replaced by the sub-id.
@param parameters The list of parameters to fill in. This list is not cleared. */
void FindParametersByReference(const string& reference, FCDEffectParameterList& parameters);
/** [INTERNAL] Clones the material object. Everything is cloned, including the effect parameter.
You will need release the cloned material directly, by deleting the pointer.
@return The cloned material object. You will must delete this pointer. */
FCDMaterial* Clone();
/** [INTERNAL] Flattens the material, pushing all the effect parameter overrides
into the effect parameter generators and moving all the parameters to the
effect technique level of abstraction. To flatten the material, use the
FCDMaterialInstance::FlattenMaterial function. */
void Flatten();
/** [INTERNAL] Reads in the \<material\> element from a given COLLADA XML tree node.
@param materialNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the material.*/
virtual FUStatus LoadFromXML(xmlNode* materialNode);
/** [INTERNAL] Writes out the \<material\> element to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the material declaration.
@return The created element XML tree node. */
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
private:
void AddParameter(FCDEffectParameter* parameter);
};
#endif // _FCD_MATERIAL_H_

View File

@@ -0,0 +1,158 @@
/*
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/FCDEffectParameter.h"
#include "FCDocument/FCDEffectParameterFactory.h"
#include "FCDocument/FCDEffectParameterList.h"
#include "FCDocument/FCDGeometry.h"
#include "FCDocument/FCDController.h"
#include "FCDocument/FCDGeometryInstance.h"
#include "FCDocument/FCDGeometryMesh.h"
#include "FCDocument/FCDGeometryPolygons.h"
#include "FCDocument/FCDMaterial.h"
#include "FCDocument/FCDMaterialInstance.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDMaterialInstance::FCDMaterialInstance(FCDocument* document, FCDGeometryInstance* _parent) : FCDEntityInstance(document, NULL)
{
material = NULL;
parent = _parent;
}
FCDMaterialInstance::~FCDMaterialInstance()
{
bindings.clear();
parent = NULL;
material = NULL;
}
// Create a flattened version of the instantiated material: this is the
// prefered way to generate DCC/viewer materials from a COLLADA document
FCDMaterial* FCDMaterialInstance::FlattenMaterial()
{
FCDGeometry* geometry = NULL;
// Retrieve the necessary geometry and material information
if(parent->GetEntity()->GetType() == FCDEntity::CONTROLLER)
{
FCDController* controller = (FCDController*) parent->GetEntity();
FCDEntity* baseTarget = controller->GetBaseTarget();
if(baseTarget->GetType() == FCDEntity::GEOMETRY)
geometry = (FCDGeometry*) baseTarget;
}
else if(parent->GetEntity()->GetType() == FCDEntity::GEOMETRY)
{
geometry = (FCDGeometry*) parent->GetEntity();
}
if (material == NULL || geometry == NULL || !geometry->IsMesh()) return NULL;
// Retrieve the correct polygons for this material semantic
FCDGeometryMesh* mesh = geometry->GetMesh();
size_t polygonsCount = mesh->GetPolygonsCount();
FCDGeometryPolygons* polygons = NULL;
for (size_t i = 0; i < polygonsCount; ++i)
{
FCDGeometryPolygons* p = mesh->GetPolygons(i);
if (semantic == p->GetMaterialSemantic()) { polygons = p; break; }
}
if (polygons == NULL) return NULL;
FCDMaterial* clone = material->Clone();
clone->Flatten();
// Flatten: Apply the bindings to the cloned material
for (FCDMaterialInstanceBindList::iterator itB = bindings.begin(); itB != bindings.end(); ++itB)
{
FCDEffectParameterList parameters;
clone->FindParametersBySemantic((*itB).semantic, parameters);
for (FCDEffectParameterList::iterator itP = parameters.begin(); itP != parameters.end(); ++itP)
{
FCDEffectParameter* param = (*itP);
if (param->GetType() == FCDEffectParameter::INTEGER)
{
FCDEffectParameterInt* intParam = (FCDEffectParameterInt*) param;
// Fairly hacky: only supported bind type right now is the texture-texture coordinate sets, which are never animated
// Resolve the target as a geometry source
FCDGeometryPolygonsInput* input = polygons->FindInput((*itB).target);
if (input != NULL) intParam->SetValue(input->set);
}
}
}
return clone;
}
// Read in the <instance_material> element from the COLLADA document
FUStatus FCDMaterialInstance::LoadFromXML(xmlNode* instanceNode)
{
FUStatus status = FCDEntityInstance::LoadFromXML(instanceNode);
if (!status) return status;
bindings.clear();
semantic = TO_FSTRING(ReadNodeProperty(instanceNode, DAE_SYMBOL_ATTRIBUTE));
string materialId = ReadNodeProperty(instanceNode, DAE_TARGET_ATTRIBUTE);
entity = material = GetDocument()->FindMaterial(materialId);
if (material == NULL)
{
return status.Warning(FS("Invalid material binding in geometry instantiation."), instanceNode->line);
}
// Read in the ColladaFX bindings
xmlNodeList bindNodes;
FindChildrenByType(instanceNode, DAE_BIND_ELEMENT, bindNodes);
for (xmlNodeList::iterator itB = bindNodes.begin(); itB != bindNodes.end(); ++itB)
{
FCDMaterialInstanceBind& bind = (*bindings.insert(bindings.end(), FCDMaterialInstanceBind()));
bind.semantic = ReadNodeProperty(*itB, DAE_SEMANTIC_ATTRIBUTE);
bind.target = ReadNodeProperty(*itB, DAE_TARGET_ATTRIBUTE);
}
return status;
}
FUStatus FCDMaterialInstance::LoadFromId(const string& materialId)
{
FUStatus status;
bindings.clear();
// Copy the semantic over
semantic = TO_FSTRING(materialId);
// Find the material associated with this Id and clone it.
entity = material = GetDocument()->FindMaterial(materialId);
if (material == NULL)
{
return status.Warning(FS("Unknown material id or semantic: ") + TO_FSTRING(materialId));
}
return status;
}
// Write out the instantiation information to the xml node tree
xmlNode* FCDMaterialInstance::WriteToXML(xmlNode* parentNode) const
{
// Intentionally skip the parent WriteToXML class
xmlNode* instanceNode = AddChild(parentNode, DAE_INSTANCE_MATERIAL_ELEMENT);
const FCDMaterial* material = GetMaterial();
if (material != NULL)
{
AddAttribute(instanceNode, DAE_SYMBOL_ATTRIBUTE, semantic);
AddAttribute(instanceNode, DAE_TARGET_ATTRIBUTE, material->GetDaeId());
}
return instanceNode;
}

View File

@@ -0,0 +1,61 @@
/*
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
*/
#ifndef _FCD_MATERIAL_BIND_H_
#define _FCD_MATERIAL_BIND_H_
#include "FCDocument/FCDEntityInstance.h"
class FCDocument;
class FCDGeometryInstance;
class FCOLLADA_EXPORT FCDMaterialInstanceBind
{
public:
string semantic;
string target;
};
typedef vector<FCDMaterialInstanceBind> FCDMaterialInstanceBindList;
class FCOLLADA_EXPORT FCDMaterialInstance : public FCDEntityInstance
{
private:
FCDGeometryInstance* parent;
fstring semantic;
FCDMaterial* material;
FCDMaterialInstanceBindList bindings;
public:
FCDMaterialInstance(FCDocument* document, FCDGeometryInstance* parent);
virtual ~FCDMaterialInstance();
// Accessors
virtual Type GetType() const { return MATERIAL; }
const fstring& GetSemantic() const { return semantic; }
FCDMaterial* GetMaterial() { return material; }
const FCDMaterial* GetMaterial() const { return material; }
FCDMaterialInstanceBindList& GetBindings() { return bindings; }
const FCDMaterialInstanceBindList& GetBindings() const { return bindings; }
// Create a flattened version of the instantiated material: this is the
// prefered way to generate viewer materials from a COLLADA document
FCDMaterial* FlattenMaterial();
// Read in the materal instantiation from the COLLADA document
virtual FUStatus LoadFromXML(xmlNode* instanceNode);
FUStatus LoadFromId(const string& materialId); // COLLADA 1.3 backward compatibility
// Write out the instantiation information to the xml node tree
xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif // _FCD_MATERIAL_BIND_H_

View File

@@ -0,0 +1,162 @@
/*
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
*/
/*
* FCDMaterialLibrary covers the material and effect libraries.
* Covers as well the texture library for COLLADA 1.3 backward compatibility
*/
#include "StdAfx.h"
#include "FCDocument/FCDocument.h"
#include "FCDocument/FCDMaterial.h"
#include "FCDocument/FCDMaterialLibrary.h"
#include "FCDocument/FCDEffect.h"
#include "FCDocument/FCDTexture.h"
#include "FUtils/FUStringConversion.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDMaterialLibrary::FCDMaterialLibrary(FCDocument* document) : FCDLibrary<FCDEntity>(document)
{
}
FCDMaterialLibrary::~FCDMaterialLibrary()
{
// Textures, effects and material entities are deleted by the parent's destructor
textures.clear();
effects.clear();
materials.clear();
}
// Search for specific material elements
FCDTexture* FCDMaterialLibrary::FindTexture(const string& _daeId)
{
const char* daeId = SkipPound(_daeId);
for (FCDTextureList::iterator it = textures.begin(); it != textures.end(); ++it)
{
if ((*it)->GetDaeId() == FUDaeWriter::CleanId(daeId)) return *it;
}
return NULL;
}
FCDEffect* FCDMaterialLibrary::FindEffect(const string& _daeId)
{
const char* daeId = SkipPound(_daeId);
for (FCDEffectList::iterator it = effects.begin(); it != effects.end(); ++it)
{
if ((*it)->GetDaeId() == FUDaeWriter::CleanId(daeId)) return *it;
}
return NULL;
}
FCDMaterial* FCDMaterialLibrary::FindMaterial(const string& _daeId)
{
const char* daeId = SkipPound(_daeId);
for (FCDMaterialList::iterator it = materials.begin(); it != materials.end(); ++it)
{
if ((*it)->GetDaeId() == FUDaeWriter::CleanId(daeId)) return *it;
}
return NULL;
}
// Add new entities
FCDEffect* FCDMaterialLibrary::AddEffect()
{
FCDEffect* effect = new FCDEffect(GetDocument());
effects.push_back(effect);
entities.push_back(effect);
return effect;
}
FCDMaterial* FCDMaterialLibrary::AddMaterial()
{
FCDMaterial* material = new FCDMaterial(GetDocument());
materials.push_back(material);
entities.push_back(material);
return material;
}
// Releases entities
void FCDMaterialLibrary::ReleaseEffect(FCDEffect* UNUSED(effect))
{
// TODO: IMPLEMENT!
}
// Releases entities
void FCDMaterialLibrary::ReleaseMaterial(FCDMaterial* UNUSED(material))
{
// TODO: IMPLEMENT!
}
// Read in the COLLADA material/effect library nodes
// Also read in the texture library for COLLADA 1.3 backward compatibility
FUStatus FCDMaterialLibrary::LoadFromXML(xmlNode* node)
{
FUStatus status;
// Determine the library type
string libraryType = ReadNodeProperty(node, DAE_TYPE_ATTRIBUTE);
bool loadEffect = (IsEquivalent(node->name, DAE_LIBRARY_EFFECT_ELEMENT) ||
IsEquivalent(node->name, DAE_LIBRARY_ELEMENT) && (libraryType == DAE_EFFECT_TYPE || libraryType == DAE_MATERIAL_TYPE));
bool loadMaterial = (IsEquivalent(node->name, DAE_LIBRARY_MATERIAL_ELEMENT) ||
IsEquivalent(node->name, DAE_LIBRARY_ELEMENT) && libraryType == DAE_MATERIAL_TYPE);
bool loadTexture = (IsEquivalent(node->name, DAE_LIBRARY_ELEMENT) && libraryType == DAE_TEXTURE_TYPE);
for (xmlNode* child = node->children; child != NULL; child = child->next)
{
if (child->type != XML_ELEMENT_NODE) continue;
FCDEffect* effect = NULL;
if(loadEffect)
{
// Parse the <effect> elements
// COLLADA 1.3. backward compatibility: also parse the <material> elements to generate the standard effects.
effect = AddEffect();
status.AppendStatus(effect->LoadFromXML(child));
}
if(loadMaterial)
{
// Parse the <material> elements
FCDMaterial* material = AddMaterial();
if (effect != NULL) material->SetEffect(effect);
status.AppendStatus(material->LoadFromXML(child));
}
if(loadTexture)
{
// Parse the <texture> elements
FCDTexture* texture = new FCDTexture(GetDocument());
status.AppendStatus(texture->LoadFromXML(child));
textures.push_back(texture);
entities.push_back(texture);
}
}
return status;
}
// Write out the COLLADA material and effect library nodes
void FCDMaterialLibrary::WriteToXML(xmlNode* libraryNode) const
{
// Write out the materials
for (FCDMaterialList::const_iterator itM = materials.begin(); itM != materials.end(); ++itM)
{
(*itM)->WriteToXML(libraryNode);
}
// Also write out the effects in their library, as a sibling of this node
xmlNode* effectLibraryNode = AddSibling(libraryNode, DAE_LIBRARY_EFFECT_ELEMENT);
for (FCDEffectList::const_iterator itE = effects.begin(); itE != effects.end(); ++itE)
{
(*itE)->WriteToXML(effectLibraryNode);
}
}

View File

@@ -0,0 +1,138 @@
/*
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
*/
/**
@file FCDMaterialLibrary.h
This file contains the FCDMaterialLibrary.h.
*/
#ifndef _FCD_MATERIAL_LIBRARY_H_
#define _FCD_MATERIAL_LIBRARY_H_
class FCDocument;
class FCDTexture;
class FCDEffect;
class FCDMaterial;
typedef vector<FCDTexture*> FCDTextureList; /**< A dynamically-sized list of textures. */
typedef vector<FCDEffect*> FCDEffectList; /**< A dynamically-sized list of effects. */
typedef vector<FCDMaterial*> FCDMaterialList; /**< A dynamically-sized list of materials. */
#include "FCDocument/FCDLibrary.h"
/**
The shared COLLADA material and effect libraries.
This class covers the material and effect libraries, as well as the
texture library for COLLADA 1.3 backward compatibility.
@todo When information push is fully implemented: split the effect library out of this one.
@ingroup FCDocument
*/
class FCOLLADA_EXPORT FCDMaterialLibrary : public FCDLibrary<FCDEntity>
{
private:
FCDTextureList textures;
FCDEffectList effects;
FCDMaterialList materials;
public:
/** Constructor: do not use directly.
The document object will create the one and only object of this class.
@param document The COLLADA document that owns this library. */
FCDMaterialLibrary(FCDocument* document);
/** Destructor: do not use directly.
The document object will release its libraries. */
virtual ~FCDMaterialLibrary();
/** Retrieves the list of effects contained by this library.
@return The list of effects. */
FCDEffectList& GetEffects() { return effects; }
const FCDEffectList& GetEffects() const { return effects; } /**< See above. */
/** Retrieves the number of effects contained by this library.
@return The number of effects within the library. */
size_t GetEffectCount() const { return effects.size(); }
/** Retrieves an effect contained by this library.
@param index The index of the effect.
@return The given effect. This pointer will be NULL if no effect matches the index. */
FCDEffect* GetEffect(size_t index) { FUAssert(index < GetEffectCount(), return NULL); return effects.at(index); }
const FCDEffect* GetEffect(size_t index) const { FUAssert(index < GetEffectCount(), return NULL); return effects.at(index); } /**< See above. */
/** [INTERNAL] Retrieves an effect contained by this library.
@param daeId The COLLADA id of the effect.
@return The matching effect. This pointer will be NULL if no effect matches the COLLADA id. */
FCDEffect* FindEffect(const string& daeId);
/** Creates a new effect.
@return The newly created effect. */
FCDEffect* AddEffect();
/** Releases an effect.
@todo Implement FCDMaterialLibrary::ReleaseEffect.
@param effect The effect to release. */
void ReleaseEffect(FCDEffect* effect);
/** Retrieves the list of materials contained by this library.
@return The list of materials. */
FCDMaterialList& GetMaterials() { return materials; }
const FCDMaterialList& GetMaterials() const { return materials; } /**< See above. */
/** Retrieves the number of materials contained by this library.
@return The number of materials within the library. */
size_t GetMaterialCount() const { return materials.size(); }
/** Retrieves a material contained by this library.
@param index The index of the material.
@return The given material. This pointer will be NULL if no material matches the index. */
FCDMaterial* GetMaterial(size_t index) { FUAssert(index < GetMaterialCount(), return NULL); return materials.at(index); }
const FCDMaterial* GetMaterial(size_t index) const { FUAssert(index < GetMaterialCount(), return NULL); return materials.at(index); } /**< See above. */
/** [INTERNAL] Retrieves a material contained by this library.
@param daeId The COLLADA id of the material.
@return The matching material. This pointer will be NULL
if no material matches the COLLADA id. */
FCDMaterial* FindMaterial(const string& daeId);
/** [INTERNAL] Retrieves a texture contained by this library.
@param daeId The COLLADA id of the texture.
@return The matching texture. This pointer will be NULL
if no texture matches the COLLADA id. */
FCDTexture* FindTexture(const string& daeId);
/** Creates a new material.
@return The newly created material. */
FCDMaterial* AddMaterial();
/** Releases a material.
@todo Implement FCDMaterialLibrary::ReleaseMaterial.
@param material The material to release. */
void ReleaseMaterial(FCDMaterial* material);
/** [INTERNAL] Reads in the contents of the library from the COLLADA XML document.
This method will be called once for the effect library and once for the material library.
It may also be called once, for COLLADA 1.3 backward compatibility, for the texture library.
@param node The COLLADA XML tree node to parse into entities.
@return The status of the import. If the status is not successful, it may be dangerous to
extract information from the library. */
virtual FUStatus LoadFromXML(xmlNode* node);
/** [INTERNAL] Writes out the library entities to the COLLADA XML document.
This method writes out the material library within the given node and
writes out the effect library as a sibling node to the given node.
@param libraryNode The COLLADA XML tree node in which to write the materials. */
virtual void WriteToXML(xmlNode* libraryNode) const;
};
#endif // _FCD_MATERIAL_LIBRARY_H_

View File

@@ -0,0 +1,355 @@
/*
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/FCDController.h"
#include "FCDocument/FCDGeometry.h"
#include "FCDocument/FCDGeometryMesh.h"
#include "FCDocument/FCDGeometryPolygons.h"
#include "FCDocument/FCDGeometrySource.h"
#include "FCDocument/FCDGeometrySpline.h"
#include "FCDocument/FCDMorphController.h"
#include "FCDocument/FCDSceneNode.h"
#include "FUtils/FUStringConversion.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDMorphController::FCDMorphController(FCDocument* document, FCDController* _parent) : FCDObject(document, "FCDMorphController")
{
parent = _parent;
baseTarget = NULL;
}
FCDMorphController::~FCDMorphController()
{
baseTarget = NULL;
parent = NULL;
CLEAR_POINTER_VECTOR(morphTargets);
}
// Changes the base target of the morpher
void FCDMorphController::SetBaseTarget(FCDEntity* entity)
{
baseTarget = NULL;
// Retrieve the actual base entity, as you can chain controllers.
FCDEntity* baseEntity = entity;
while (baseEntity != NULL && baseEntity->GetType() == FCDEntity::CONTROLLER)
{
baseEntity = ((FCDController*) baseEntity)->GetBaseTarget();
}
if (baseEntity != NULL && baseEntity->GetType() == FCDEntity::GEOMETRY)
{
baseTarget = entity;
// Remove the old morph targets which are not similar, anymore, to the new base entity.
for (size_t i = 0; i < morphTargets.size();)
{
if (IsSimilar(morphTargets[i]->GetGeometry()))
{
++i;
}
else
{
ReleaseTarget(morphTargets[i]);
}
}
}
else
{
// The new base target is not valid.
CLEAR_POINTER_VECTOR(morphTargets);
}
}
// Adds a new morph target.
FCDMorphTarget* FCDMorphController::AddTarget(FCDGeometry* geometry, float weight)
{
FCDMorphTarget* target = NULL;
if (IsSimilar(geometry))
{
target = new FCDMorphTarget(GetDocument(), this);
target->SetGeometry(geometry);
target->SetWeight(weight);
morphTargets.push_back(target);
}
return target;
}
// Releases a morph target used in this morpher.
void FCDMorphController::ReleaseTarget(FCDMorphTarget* target)
{
FCDMorphTargetList::iterator it = std::find(morphTargets.begin(), morphTargets.end(), target);
if (it != morphTargets.end())
{
delete *it;
morphTargets.erase(it);
}
}
// Retrieves whether a given entity is similar to the base target.
bool FCDMorphController::IsSimilar(FCDEntity* entity)
{
bool similar = false;
if (entity != NULL && baseTarget != NULL)
{
size_t vertexCount = 0;
bool isMesh = false;
bool isSpline = false;
// Find the number of vertices in the base target
FCDEntity* baseEntity = baseTarget;
while (baseEntity != NULL && baseEntity->GetType() == FCDEntity::CONTROLLER)
{
baseEntity = ((FCDController*) baseEntity)->GetBaseTarget();
}
if (baseEntity != NULL && baseEntity->GetType() == FCDEntity::GEOMETRY)
{
FCDGeometry* g = (FCDGeometry*) baseEntity;
if (g->IsMesh())
{
isMesh = true;
FCDGeometryMesh* m = g->GetMesh();
FCDGeometrySource* positions = m->GetPositionSource();
if (positions != NULL)
{
vertexCount = positions->GetSourceData().size() / positions->GetSourceStride();
}
}
if (g->IsSpline())
{
isSpline = true;
FCDGeometrySpline* s = g->GetSpline();
vertexCount = s->GetCVCount();
}
}
// Find the number of vertices in the given entity
baseEntity = entity;
while (baseEntity != NULL && baseEntity->GetType() == FCDEntity::CONTROLLER)
{
baseEntity = ((FCDController*) baseEntity)->GetBaseTarget();
}
if (baseEntity != NULL && baseEntity->GetType() == FCDEntity::GEOMETRY)
{
FCDGeometry* g = (FCDGeometry*) baseEntity;
if (g->IsMesh() && isMesh)
{
FCDGeometryMesh* m = g->GetMesh();
FCDGeometrySource* positions = m->GetPositionSource();
if (positions != NULL)
{
similar = (vertexCount == positions->GetSourceData().size() / positions->GetSourceStride());
}
}
if (g->IsSpline() && isSpline)
{
FCDGeometrySpline* s = g->GetSpline();
similar = (vertexCount == s->GetCVCount());
}
}
}
return similar;
}
// Load this controller from a Collada <controller> node
FUStatus FCDMorphController::LoadFromXML(xmlNode* morphNode)
{
FUStatus status;
if (!IsEquivalent(morphNode->name, DAE_CONTROLLER_MORPH_ELEMENT))
{
return status.Warning(FS("Unexpected node in controller library: ") + TO_FSTRING((const char*) morphNode->name), morphNode->line);
}
// Parse in the morph method
string methodValue = ReadNodeProperty(morphNode, DAE_METHOD_ATTRIBUTE);
method = FUDaeMorphMethod::FromString(methodValue);
if (method == FUDaeMorphMethod::UNKNOWN)
{
status.Warning(FS("Unknown processing method from morph controller: ") + TO_FSTRING(parent->GetDaeId()), morphNode->line);
}
// Find the base geometry
string baseTargetId = ReadNodeSource(morphNode);
baseTarget = GetDocument()->FindGeometry(baseTargetId);
if (baseTarget == NULL) GetDocument()->FindController(baseTargetId);
if (baseTarget == NULL)
{
return status.Warning(FS("Cannot find base target for morph controller: ") + TO_FSTRING(parent->GetDaeId()), morphNode->line);
}
// Find the <targets> element and process its inputs
xmlNode* targetsNode = FindChildByType(morphNode, DAE_TARGETS_ELEMENT);
if (targetsNode == NULL)
{
return status.Fail(FS("Cannot find necessary <targets> element for morph controller: ") + TO_FSTRING(parent->GetDaeId()), morphNode->line);
}
xmlNodeList inputNodes;
FindChildrenByType(targetsNode, DAE_INPUT_ELEMENT, inputNodes);
// Find the TARGET and WEIGHT input necessary sources
xmlNode* targetSourceNode = NULL,* weightSourceNode = NULL;
for (xmlNodeList::iterator it = inputNodes.begin(); it != inputNodes.end(); ++it)
{
xmlNode* inputNode = (*it);
string semantic = ReadNodeSemantic(inputNode);
string sourceId = ReadNodeSource(inputNode);
if (semantic == DAE_WEIGHT_MORPH_INPUT || semantic == DAE_WEIGHT_MORPH_INPUT_DEPRECATED)
{
weightSourceNode = FindChildById(morphNode, sourceId);
}
else if (semantic == DAE_TARGET_MORPH_INPUT || semantic == DAE_TARGET_MORPH_INPUT_DEPRECATED)
{
targetSourceNode = FindChildById(morphNode, sourceId);
}
else
{
status.Warning(FS("Unknown morph targets input type in morph controller: ") + TO_FSTRING(parent->GetDaeId()), inputNode->line);
}
}
if (targetSourceNode == NULL)
{
return status.Fail(FS("Cannot find TARGET source for morph controller: ") + TO_FSTRING(parent->GetDaeId()), targetsNode->line);
}
if (weightSourceNode == NULL)
{
return status.Fail(FS("Cannot find WEIGHT source for morph controller: ") + TO_FSTRING(parent->GetDaeId()), targetsNode->line);
}
// Read in the sources
StringList morphTargetIds;
ReadSource(targetSourceNode, morphTargetIds);
FloatList weights;
ReadSource(weightSourceNode, weights);
size_t targetCount = morphTargetIds.size();
if (weights.size() != targetCount)
{
return status.Fail(FS("TARGET and WEIGHT sources should be the same size for morph controller: ") + TO_FSTRING(parent->GetDaeId()), targetSourceNode->line);
}
// Find the target geometries and build the morph targets
morphTargets.reserve(targetCount);
for (int32 i = 0; i < (int32) targetCount; ++i)
{
FCDGeometry* targetGeometry = GetDocument()->FindGeometry(morphTargetIds[i]);
if (targetGeometry == NULL)
{
status.Warning(FS("Unable to find target geometry, '") + TO_FSTRING(morphTargetIds[i]) + FS("' for morph controller: ") + TO_FSTRING(parent->GetDaeId()), morphNode->line);
}
FCDMorphTarget* morphTarget = AddTarget(targetGeometry, weights[i]);
// Record the morphing weight as animatable
FCDAnimatedFloat::Create(GetDocument(), weightSourceNode, &morphTarget->GetWeight(), i);
}
return status;
}
// Write out this controller to a COLLADA xml node tree
xmlNode* FCDMorphController::WriteToXML(xmlNode* parentNode) const
{
size_t targetCount = GetTargetCount();
// Create the <morph> node and set its attributes
xmlNode* morphNode = AddChild(parentNode, DAE_CONTROLLER_MORPH_ELEMENT);
AddAttribute(morphNode, DAE_METHOD_ATTRIBUTE, FUDaeMorphMethod::ToString(method));
if (baseTarget != NULL)
{
AddAttribute(morphNode, DAE_SOURCE_ATTRIBUTE, string("#") + baseTarget->GetDaeId());
}
// Gather up the morph target ids and the morphing weights
StringList targetIds; targetIds.reserve(targetCount);
FloatList weights; weights.reserve(targetCount);
for (FCDMorphTargetList::const_iterator it = morphTargets.begin(); it != morphTargets.end(); ++it)
{
FCDMorphTarget* t = (*it);
targetIds.push_back(t->GetGeometry() != NULL ? t->GetGeometry()->GetDaeId() : DAEERR_UNKNOWN_IDREF);
weights.push_back(t->GetWeight());
}
// Export the target id source
FUSStringBuilder targetSourceId(parent->GetDaeId()); targetSourceId.append("-targets");
AddSourceIDRef(morphNode, targetSourceId.ToCharPtr(), targetIds, DAE_TARGET_MORPH_INPUT);
// Export the weight source
FUSStringBuilder weightSourceId(parent->GetDaeId()); weightSourceId.append("-morph_weights");
xmlNode* weightSourceNode = AddSourceFloat(morphNode, weightSourceId.ToCharPtr(), weights, DAE_WEIGHT_MORPH_INPUT);
// Export the <targets> elements
xmlNode* targetsNode = AddChild(morphNode, DAE_TARGETS_ELEMENT);
AddInput(targetsNode, targetSourceId.ToCharPtr(), DAE_TARGET_MORPH_INPUT);
AddInput(targetsNode, weightSourceId.ToCharPtr(), DAE_WEIGHT_MORPH_INPUT);
// Record the morphing weight animations
for (int32 i = 0; i < (int32) targetCount; ++i)
{
FCDMorphTarget* t = morphTargets[i];
GetDocument()->WriteAnimatedValueToXML(&t->GetWeight(), weightSourceNode, "morphing_weights", i);
}
return morphNode;
}
FUStatus FCDMorphController::Link()
{
return FUStatus(1);
}
// Morph Target Class Implementation
FCDMorphTarget::FCDMorphTarget(FCDocument* document, FCDMorphController* _parent) : FCDObject(document, "FCDMorphTarget")
{
parent = _parent;
geometry = NULL;
weight = 0.0f;
}
FCDMorphTarget::~FCDMorphTarget()
{
parent = NULL;
geometry = NULL;
weight = 0.0f;
}
void FCDMorphTarget::SetGeometry(FCDGeometry* _geometry)
{
// Let go of the old geometry
geometry = NULL;
// Check if this geometry is similar to the controller base target
if (GetParent()->IsSimilar(_geometry))
{
geometry = _geometry;
}
}
FCDAnimated* FCDMorphTarget::GetAnimatedWeight()
{
return GetDocument()->FindAnimatedValue(&weight);
}
const FCDAnimated* FCDMorphTarget::GetAnimatedWeight() const
{
return GetDocument()->FindAnimatedValue(&weight);
}
bool FCDMorphTarget::IsAnimated() const
{
return GetDocument()->IsValueAnimated(&weight);
}

View File

@@ -0,0 +1,202 @@
/*
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
*/
/**
@file FCDMorphController.h
This file contains the FCDMorphController and the FCDMorphTarget classes.
*/
#ifndef _FCD_MORPH_CONTROLLER_H_
#define _FCD_MORPH_CONTROLLER_H_
#include "FUtils/FUDaeEnum.h"
#include "FCDocument/FCDObject.h"
class FCDocument;
class FCDController;
class FCDGeometry;
class FCDMorphController;
/**
A COLLADA morph target.
A morph target is just a geometric entity with a weight assigned.
The weight may be animated.
*/
class FCOLLADA_EXPORT FCDMorphTarget : public FCDObject
{
private:
FCDMorphController* parent;
FCDGeometry* geometry;
float weight;
public:
/** Constructor: do not use directly.
Instead, use the FCDMorphController::AddTarget function.
@param document The COLLADA document that owns the morph target.
@param parent The morph controller that contains the morph target. */
FCDMorphTarget(FCDocument* document, FCDMorphController* parent);
/** Destructor. */
virtual ~FCDMorphTarget();
/** Retrieves the morph controller which contains this target.
@return The parent morpher. */
FCDMorphController* GetParent() { return parent; }
const FCDMorphController* GetParent() const { return parent; } /**< See above. */
/** Retrieves the target geometry.
This is what the morphed geometry should look like if
the morphing weight is set to 1.0f.
@return The target geometry. */
FCDGeometry* GetGeometry() { return geometry; }
const FCDGeometry* GetGeometry() const { return geometry; } /**< See above. */
/** Sets the target geometry.
This is what the morphed geometry should look like if
the morphing weight is set to 1.0f. As such, the target geometry
should be similar to the base target geometry. You can verify
this using the FCDMorphController::IsSimilar function.
@param geometry The target geometry. */
void SetGeometry(FCDGeometry* geometry);
/** Retrieves the morphing weight.
@return The morphing weight. */
float& GetWeight() { return weight; }
const float& GetWeight() const { return weight; } /**< See above. */
/** Sets the morphing weight.
This function has no impact on any animations that target the morphing weight.
@param _weight The morphing weight. */
void SetWeight(float _weight) { weight = _weight; }
/** Retrieves whether the morphing weight is animated.
@return Whether the morphing weight is animated. */
bool IsAnimated() const;
/** Retrieves the animation associated with the morphing weight.
@return The animated value associated with the morphing weight.
This pointer will be NULL if the morphing weight is not animated. */
FCDAnimated* GetAnimatedWeight();
const FCDAnimated* GetAnimatedWeight() const; /**< See above. */
};
/** A dynamically-sized array of morph targets. */
typedef vector<FCDMorphTarget*> FCDMorphTargetList;
/**
A COLLADA morpher.
A morpher holds a base geometry and a set of morph targets
that contains a geometry and a weight. The geometry must be similar to the
base geometry and the weights are used to interpolate the vertex positions
of the base geometry. To be similar, two meshes must have the same number of
vertices and two splines must have the same number of control points.
The morphing weights can be animated.
There are two interpolation functions defined in COLLADA.
See the FUDaeMorphMethod::Method enumerated type for more information.
@see FCDMorphTarget FUDaeMorphMethod
@ingroup FCDGeometry
*/
class FCOLLADA_EXPORT FCDMorphController : public FCDObject
{
private:
FCDController* parent;
FCDocument* document;
FUDaeMorphMethod::Method method;
FCDEntity* baseTarget;
FCDMorphTargetList morphTargets;
public:
/** Constructor: do not use directly.
Instead, use the FCDController::CreateMorphController function.
@param document The COLLADA document that owns the morpher.
@param parent The COLLADA controller that contains this morpher. */
FCDMorphController(FCDocument* document, FCDController* parent);
/** Destructor: do not use directly.
Instead, release the parent controller or create a new skin/morpher. */
virtual ~FCDMorphController();
/** Retrieves the base entity controlled by this morpher.
This entity may be a geometry or another controller.
@return The base target. */
FCDEntity* GetBaseTarget() { return baseTarget; }
const FCDEntity* GetBaseTarget() const { return baseTarget; } /**< See above. */
/** Sets the base entity controlled by this morpher.
This entity may be a geometry or another controller.
Since the morph targets must be similar to this entity,
all the morph targets that are not similar to the new base entity will be removed.
@param entity The new base entity. */
void SetBaseTarget(FCDEntity* entity);
/** Retrieves the list of the morph targets.
All the morph target geometries should be similar to the base entity.
@return The morph targets. */
FCDMorphTargetList& GetTargets() { return morphTargets; }
const FCDMorphTargetList& GetTargets() const { return morphTargets; } /**< See above. */
/** Retrieves the number of morph targets.
@return The number of morph targets. */
size_t GetTargetCount() const { return morphTargets.size(); }
/** Retrieves a specific morph target.
@param index The index of the morph target.
@return The morph target. This pointer will be NULL if the index is out-of-bounds. */
FCDMorphTarget* GetTarget(size_t index) { FUAssert(index < GetTargetCount(), return NULL); return morphTargets.at(index); }
const FCDMorphTarget* GetTarget(size_t index) const { FUAssert(index < GetTargetCount(), return NULL); return morphTargets.at(index); } /**< See above. */
/** Adds a new morph target.
@param geometry The morph target geometry.
@param weight The morphing weight.
@return The new morph target. */
FCDMorphTarget* AddTarget(FCDGeometry* geometry = NULL, float weight = 0.0f);
/** Releases a morph target used in this morpher.
@param target The morph target to release. */
void ReleaseTarget(FCDMorphTarget* target);
/** Retrieves the method used to interpolate between the different morph targets.
@return The interpolation method. */
FUDaeMorphMethod::Method GetMethod() const { return method; }
/** Sets the method used to interpolate between the different morph targets.
@param _method The interpolation method. */
void SetMethod(FUDaeMorphMethod::Method _method) { method = _method; }
/** Retrieves whether a given entity is similar to the base target.
Entities must be similar to be able to morph between them.
@param entity An entity.
@return Whether the given entity is similar to the base target. */
bool IsSimilar(FCDEntity* entity);
/** [INTERNAL] Reads in the \<morph\> element from a given COLLADA XML tree node.
@param morphNode The COLLADA XML tree node.
@return The status of the import. If the status is not successful,
it may be dangerous to extract information from the morpher.*/
FUStatus LoadFromXML(xmlNode* morphNode);
/** [INTERNAL] Writes out the \<morph\> element to the given COLLADA XML tree node.
@param parentNode The COLLADA XML parent node in which to insert the morphing information.
@return The created element XML tree node. */
xmlNode* WriteToXML(xmlNode* parentNode) const;
/** [INTERNAL] Links the controller with its entities.
Since geometries are loaded before the controllers, no linkage is necessary.
@return The status of the linkage: always successful. */
FUStatus Link();
};
#endif // _FCD_MORPH_CONTROLLER_H_

View File

@@ -0,0 +1,93 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDocument.h"
#include "FCDocument/FCDObject.h"
#include "FUtils/FUUniqueStringMap.h"
#include "FUtils/FUDaeWriter.h"
//
// FCDObject
//
FCDObject::FCDObject(FUObjectContainer* container)
: FUObject_Construct(container, "FCDObject")
{
}
FCDObject::FCDObject(FCDocument* document, const char* UNUSED_NDEBUG(className))
: FUObject_Construct(document, className)
{
}
//
// FCDObjectWithId
//
FCDObjectWithId::FCDObjectWithId(FCDocument* document, const char* baseId)
: FCDObject(document, baseId)
{
daeId = baseId;
hasUniqueId = false;
}
FCDObjectWithId::~FCDObjectWithId()
{
RemoveDaeId();
}
void FCDObjectWithId::Clone(FCDObjectWithId* clone) const
{
clone->daeId = daeId;
clone->hasUniqueId = hasUniqueId;
}
const string& FCDObjectWithId::GetDaeId() const
{
if (!hasUniqueId)
{
// Generate a new id
FCDObjectWithId* e = const_cast<FCDObjectWithId*>(this);
FUSUniqueStringMap* names = e->GetDocument()->GetUniqueNameMap();
FUAssert(!e->daeId.empty(), e->daeId = "unknown_object");
names->AddUniqueString(e->daeId);
e->hasUniqueId = true;
}
return daeId;
}
void FCDObjectWithId::SetDaeId(const string& id)
{
RemoveDaeId();
// Use this id to enforce a unique id.
FUSUniqueStringMap* names = GetDocument()->GetUniqueNameMap();
daeId = FUDaeWriter::CleanId(id);
names->AddUniqueString(daeId);
hasUniqueId = true;
}
void FCDObjectWithId::SetDaeId(string& id)
{
RemoveDaeId();
// Use this id to enforce a unique id.
FUSUniqueStringMap* names = GetDocument()->GetUniqueNameMap();
daeId = FUDaeWriter::CleanId(id);
names->AddUniqueString(daeId);
id = daeId;
hasUniqueId = true;
}
void FCDObjectWithId::RemoveDaeId()
{
if (hasUniqueId)
{
FUSUniqueStringMap* names = GetDocument()->GetUniqueNameMap();
names->Erase(daeId);
hasUniqueId = false;
}
}

View File

@@ -0,0 +1,107 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
/**
@file FCDObject.h
This file contains the FCDObject and the FCDObjectWithId classes.
*/
#ifndef __FCD_OBJECT_H_
#define __FCD_OBJECT_H_
#include "FUtils/FUObject.h"
#include "FCDocument/FCDocument.h"
/**
A basic COLLADA document object.
All the objects owned by the COLLADA document derive from this class.
The FCDocument object is accessible through this interface to all the object which it owns.
@ingroup FCDocument
*/
class FCOLLADA_EXPORT FCDObject : public FUObject
{
private:
// Don't use this constructor directly.
FCDObject(FUObjectContainer* container);
public:
/** Constructor: sets the COLLADA document object and the informative name.
The name of the class is used only for debugging purposes and is
not accessible in release and retail builds. Therefore, it is not meant to replace or implement RTTI.
@param document The COLLADA document which owns this object.
@param className A information name to identify the class of the object. */
FCDObject(FCDocument* document, const char* className);
/** Destructor. */
virtual ~FCDObject() {}
/** Retrieves the COLLADA document which owns this object.
@return The COLLADA document. */
inline FCDocument* GetDocument() { return (FCDocument*) GetContainer(); }
inline FCDocument* GetDocument() const { return (FCDocument*) GetContainer(); } /**< See above. */
};
/**
A basic COLLADA object which has a unique COLLADA id.
Many COLLADA structures such as entities and sources need a unique COLLADA id.
The COLLADA document contains a map of all the COLLADA ids known in its scope.
The interface of the FCDObjectWithId class allows for the retrieval and the modification
of the unique COLLADA id attached to these objects.
A unique COLLADA id is built, if none are provided, using the 'baseId' field of the constructor.
A unique COLLADA id is generated only on demand.
@ingroup FCDocument
*/
class FCOLLADA_EXPORT FCDObjectWithId : public FCDObject
{
private:
string daeId;
bool hasUniqueId;
public:
/** Constructor: sets the prefix COLLADA id to be used if no COLLADA id is provided.
@param document The COLLADA document which owns this object.
@param baseId The prefix COLLADA id to be used if no COLLADA id is provided. */
FCDObjectWithId(FCDocument* document, const char* baseId = "ObjectWithID");
/** Destructor. */
virtual ~FCDObjectWithId();
/** Retrieves the unique COLLADA id for this object.
If no unique COLLADA id has been previously generated or provided, this function
has the side-effect of generating a unique COLLADA id.
@return The unique COLLADA id. */
const string& GetDaeId() const;
/** Sets the COLLADA id for this object.
There is no guarantee that the given COLLADA id will be used, as it may not be unique.
You can call the GetDaeId function after this call to retrieve the final, unique COLLADA id.
@param id The wanted COLLADA id for this object. This COLLADA id does not need to be unique.
If the COLLADA id is not unique, a new unique COLLADA id will be generated. */
void SetDaeId(const string& id);
/** Sets the COLLADA id for this object.
There is no guarantee that the given COLLADA id will be used, as it may not be unique.
@param id The wanted COLLADA id for this object. This COLLADA id does not need to be unique.
If the COLLADA id is not unique, a new unique COLLADA id will be generated and
this formal variable will be modified to contain the new COLLADA id. */
void SetDaeId(string& id);
/** [INTERNAL] Release the unique COLLADA id of an object.
Use this function wisely, as it leaves the object id-less and without a way to automatically
generate a COLLADA id. */
void RemoveDaeId();
/** [INTERNAL] Clones the object. The unique COLLADA id will be copied over to the clone object.
Use carefully: when a cloned object with an id is released, it
does remove the unique COLLADA id from the unique name map.
@param clone The object clone. */
void Clone(FCDObjectWithId* clone) const;
};
#endif // __FCD_OBJECT_H_

View File

@@ -0,0 +1,369 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDPhysicsAnalyticalGeometry.h"
#include "FCDocument/FCDPhysicsParameterGeneric.h"
#include "FCDocument/FCDocument.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDPhysicsAnalyticalGeometry::FCDPhysicsAnalyticalGeometry(FCDocument* document) : FCDEntity(document, "AnalyticalGeometry")
{
}
FCDPhysicsAnalyticalGeometry::~FCDPhysicsAnalyticalGeometry()
{
}
// Load from a XML node the given physicsAnalyticalGeometry
FUStatus FCDPhysicsAnalyticalGeometry::LoadFromXML(xmlNode* node)
{
FUStatus status = FCDEntity::LoadFromXML(node);
return status;
}
FCDPASBox::FCDPASBox(FCDocument* document) : FCDPhysicsAnalyticalGeometry(document)
{
halfExtents.x = halfExtents.y = halfExtents.z = 0.f;
}
FCDPhysicsAnalyticalGeometry* FCDPASBox::Clone()
{
FCDPASBox* clone = new FCDPASBox(GetDocument());
FCDEntity::Clone(clone);
clone->halfExtents = halfExtents;
return clone;
}
FUStatus FCDPASBox::LoadFromXML(xmlNode* node)
{
FUStatus status;
if (!IsEquivalent(node->name, DAE_BOX_ELEMENT))
{
return status.Warning(FS("Box is not of the right type."), node->line);
}
for (xmlNode* child = node->children; child != NULL; child = child->next)
{
if (child->type != XML_ELEMENT_NODE) continue;
if(IsEquivalent(child->name, DAE_HALF_EXTENTS_ELEMENT))
{
const char* halfExt = ReadNodeContentDirect(child);
halfExtents.x = FUStringConversion::ToFloat(&halfExt);
halfExtents.y = FUStringConversion::ToFloat(&halfExt);
halfExtents.z = FUStringConversion::ToFloat(&halfExt);
}
}
return status;
}
xmlNode* FCDPASBox::WriteToXML(xmlNode* node) const
{
xmlNode* geomNode = AddChild(node, DAE_BOX_ELEMENT);
string s = FUStringConversion::ToString(halfExtents);
AddChild(geomNode, DAE_HALF_EXTENTS_ELEMENT, s);
return geomNode;
}
FCDPASPlane::FCDPASPlane(FCDocument* document) : FCDPhysicsAnalyticalGeometry(document)
{
normal.x = normal.y = normal.z = d = 0.f;
}
FCDPhysicsAnalyticalGeometry* FCDPASPlane::Clone()
{
FCDPASPlane* clone = new FCDPASPlane(GetDocument());
FCDEntity::Clone(clone);
clone->normal = normal;
return clone;
}
FUStatus FCDPASPlane::LoadFromXML(xmlNode* node)
{
FUStatus status;
if (!IsEquivalent(node->name, DAE_PLANE_ELEMENT))
{
return status.Warning(FS("Plane is not of the right type."), node->line);
}
for (xmlNode* child = node->children; child != NULL; child = child->next)
{
if (child->type != XML_ELEMENT_NODE) continue;
if(IsEquivalent(child->name, DAE_EQUATION_ELEMENT))
{
const char* eq = ReadNodeContentDirect(child);
normal.x = FUStringConversion::ToFloat(&eq);
normal.y = FUStringConversion::ToFloat(&eq);
normal.z = FUStringConversion::ToFloat(&eq);
d = FUStringConversion::ToFloat(&eq);
}
}
return status;
}
xmlNode* FCDPASPlane::WriteToXML(xmlNode* node) const
{
xmlNode* geomNode = AddChild(node, DAE_PLANE_ELEMENT);
FMVector4 equation;
equation.w = normal.x; equation.x = normal.y; equation.y = normal.z; equation.z = d;
string s = FUStringConversion::ToString(equation);
AddChild(geomNode, DAE_EQUATION_ELEMENT, s);
return geomNode;
}
FCDPASSphere::FCDPASSphere(FCDocument* document) : FCDPhysicsAnalyticalGeometry(document)
{
radius = 0.f;
}
FCDPhysicsAnalyticalGeometry* FCDPASSphere::Clone()
{
FCDPASSphere* clone = new FCDPASSphere(GetDocument());
FCDEntity::Clone(clone);
clone->radius = radius;
return clone;
}
FUStatus FCDPASSphere::LoadFromXML(xmlNode* node)
{
FUStatus status;
if (!IsEquivalent(node->name, DAE_SPHERE_ELEMENT))
{
return status.Warning(FS("Sphere is not of the right type."), node->line);
}
for (xmlNode* child = node->children; child != NULL; child = child->next)
{
if (child->type != XML_ELEMENT_NODE) continue;
if(IsEquivalent(child->name, DAE_RADIUS_ELEMENT))
{
radius = FUStringConversion::ToFloat(ReadNodeContentDirect(child));
}
}
return status;
}
xmlNode* FCDPASSphere::WriteToXML(xmlNode* node) const
{
xmlNode* geomNode = AddChild(node, DAE_SPHERE_ELEMENT);
AddChild(geomNode, DAE_RADIUS_ELEMENT, radius);
return geomNode;
}
FCDPASCylinder::FCDPASCylinder(FCDocument* document) : FCDPhysicsAnalyticalGeometry(document)
{
height = 0.f;
radius = 0.f;
}
FCDPhysicsAnalyticalGeometry* FCDPASCylinder::Clone()
{
FCDPASCylinder* clone = new FCDPASCylinder(GetDocument());
FCDEntity::Clone(clone);
clone->radius = radius;
clone->height = height;
return clone;
}
FUStatus FCDPASCylinder::LoadFromXML(xmlNode* node)
{
FUStatus status;
if (!IsEquivalent(node->name, DAE_CYLINDER_ELEMENT))
{
return status.Warning(FS("Sphere is not of the right type."), node->line);
}
for (xmlNode* child = node->children; child != NULL; child = child->next)
{
if (child->type != XML_ELEMENT_NODE) continue;
if(IsEquivalent(child->name, DAE_HEIGHT_ELEMENT))
{
height = FUStringConversion::ToFloat(ReadNodeContentDirect(child));
}
else if(IsEquivalent(child->name, DAE_RADIUS_ELEMENT))
{
radius = FUStringConversion::ToFloat(ReadNodeContentDirect(child));
}
}
return status;
}
xmlNode* FCDPASCylinder::WriteToXML(xmlNode* node) const
{
xmlNode* geomNode = AddChild(node, DAE_CYLINDER_ELEMENT);
AddChild(geomNode, DAE_HEIGHT_ELEMENT, height);
AddChild(geomNode, DAE_RADIUS_ELEMENT, radius);
return geomNode;
}
FCDPASCapsule::FCDPASCapsule(FCDocument* document) : FCDPhysicsAnalyticalGeometry(document)
{
height = 0.f;
radius = 0.f;
}
FCDPhysicsAnalyticalGeometry* FCDPASCapsule::Clone()
{
FCDPASCapsule* clone = new FCDPASCapsule(GetDocument());
FCDEntity::Clone(clone);
clone->radius = radius;
clone->height = height;
return clone;
}
FUStatus FCDPASCapsule::LoadFromXML(xmlNode* node)
{
FUStatus status;
if (!IsEquivalent(node->name, DAE_CAPSULE_ELEMENT))
{
return status.Warning(FS("Capsule is not of the right type."), node->line);
}
for (xmlNode* child = node->children; child != NULL; child = child->next)
{
if (child->type != XML_ELEMENT_NODE) continue;
if(IsEquivalent(child->name, DAE_HEIGHT_ELEMENT))
{
height = FUStringConversion::ToFloat(ReadNodeContentDirect(child));
}
else if(IsEquivalent(child->name, DAE_RADIUS_ELEMENT))
{
radius = FUStringConversion::ToFloat(ReadNodeContentDirect(child));
}
}
return status;
}
xmlNode* FCDPASCapsule::WriteToXML(xmlNode* node) const
{
xmlNode* geomNode = AddChild(node, DAE_CAPSULE_ELEMENT);
AddChild(geomNode, DAE_HEIGHT_ELEMENT, height);
AddChild(geomNode, DAE_RADIUS_ELEMENT, radius);
return geomNode;
}
FCDPASTaperedCapsule::FCDPASTaperedCapsule(FCDocument* document) : FCDPASCapsule(document)
{
radius2 = 0.f;
}
FCDPhysicsAnalyticalGeometry* FCDPASTaperedCapsule::Clone()
{
FCDPASTaperedCapsule* clone = new FCDPASTaperedCapsule(GetDocument());
FCDEntity::Clone(clone);
clone->radius = radius;
return clone;
}
FUStatus FCDPASTaperedCapsule::LoadFromXML(xmlNode* node)
{
FUStatus status;
if (!IsEquivalent(node->name, DAE_TAPERED_CAPSULE_ELEMENT))
{
return status.Warning(FS("Tapered Capsule is not of the right type."), node->line);
}
for (xmlNode* child = node->children; child != NULL; child = child->next)
{
if (child->type != XML_ELEMENT_NODE) continue;
if(IsEquivalent(child->name, DAE_HEIGHT_ELEMENT))
{
const char* h = ReadNodeContentDirect(child);
height = FUStringConversion::ToFloat(&h);
}
else if(IsEquivalent(child->name, DAE_RADIUS1_ELEMENT))
{
const char* rad = ReadNodeContentDirect(child);
radius = FUStringConversion::ToFloat(&rad);
}
else if(IsEquivalent(child->name, DAE_RADIUS2_ELEMENT))
{
const char* rad = ReadNodeContentDirect(child);
radius2 = FUStringConversion::ToFloat(&rad);
}
}
return status;
}
xmlNode* FCDPASTaperedCapsule::WriteToXML(xmlNode* node) const
{
xmlNode* geomNode = AddChild(node, DAE_TAPERED_CAPSULE_ELEMENT);
AddChild(geomNode, DAE_HEIGHT_ELEMENT, height);
AddChild(geomNode, DAE_RADIUS1_ELEMENT, radius);
AddChild(geomNode, DAE_RADIUS2_ELEMENT, radius2);
return geomNode;
}
FCDPASTaperedCylinder::FCDPASTaperedCylinder(FCDocument* document) : FCDPASCylinder(document)
{
radius2 = 0.f;
}
FCDPhysicsAnalyticalGeometry* FCDPASTaperedCylinder::Clone()
{
FCDPASTaperedCylinder* clone = new FCDPASTaperedCylinder(GetDocument());
FCDEntity::Clone(clone);
clone->radius = radius;
return clone;
}
FUStatus FCDPASTaperedCylinder::LoadFromXML(xmlNode* node)
{
FUStatus status;
if (!IsEquivalent(node->name, DAE_TAPERED_CYLINDER_ELEMENT))
{
return status.Warning(FS("Tapered cylinder is not of the right type."), node->line);
}
for (xmlNode* child = node->children; child != NULL; child = child->next)
{
if (child->type != XML_ELEMENT_NODE) continue;
if(IsEquivalent(child->name, DAE_HEIGHT_ELEMENT))
{
const char* h = ReadNodeContentDirect(child);
height = FUStringConversion::ToFloat(&h);
}
else if(IsEquivalent(child->name, DAE_RADIUS1_ELEMENT))
{
const char* rad = ReadNodeContentDirect(child);
radius = FUStringConversion::ToFloat(&rad);
}
else if(IsEquivalent(child->name, DAE_RADIUS2_ELEMENT))
{
const char* rad = ReadNodeContentDirect(child);
radius2 = FUStringConversion::ToFloat(&rad);
}
}
return status;
}
xmlNode* FCDPASTaperedCylinder::WriteToXML(xmlNode* node) const
{
xmlNode* geomNode = AddChild(node, DAE_TAPERED_CYLINDER_ELEMENT);
AddChild(geomNode, DAE_HEIGHT_ELEMENT, height);
AddChild(geomNode, DAE_RADIUS1_ELEMENT, radius);
AddChild(geomNode, DAE_RADIUS2_ELEMENT, radius2);
return geomNode;
}

View File

@@ -0,0 +1,152 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#ifndef _FCD_PHYSICS_ANALYTICAL_GEOM_H_
#define _FCD_PHYSICS_ANALYTICAL_GEOM_H_
#include "FCDocument/FCDEntity.h"
#include "FCDocument/FCDEntityInstance.h"
#include "FUtils/FUDaeEnum.h"
class FCDocument;
class FCDPhysicsParameterGeneric;
typedef std::vector<FCDPhysicsParameterGeneric*> FCDPhysicsParameterList;
class FCOLLADA_EXPORT FCDPhysicsAnalyticalGeometry : public FCDEntity
{
public:
enum GeomType { BOX, PLANE, SPHERE, CYLINDER, CAPSULE, TAPERED_CYLINDER, TAPERED_CAPSULE };
FCDPhysicsAnalyticalGeometry(FCDocument* document);
virtual ~FCDPhysicsAnalyticalGeometry();
virtual Type GetType() const {return PHYSICS_ANALYTICAL_GEOMETRY;}
// Returns the entity type
virtual GeomType GetGeomType() const = 0;
// Create a copy of this analyticalGeometry
virtual FCDPhysicsAnalyticalGeometry* Clone() = 0;
// Read in the <physics_analyticalGeometry> node of the COLLADA document
virtual FUStatus LoadFromXML(xmlNode* node);
// Write out the <physics_analyticalGeometry> node to the COLLADA xml tree
virtual xmlNode* WriteToXML(xmlNode* parentNode) const = 0;
};
class FCOLLADA_EXPORT FCDPASBox : public FCDPhysicsAnalyticalGeometry
{
public:
FCDPASBox(FCDocument* document);
virtual ~FCDPASBox() {}
virtual FUStatus LoadFromXML(xmlNode* node);
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
virtual GeomType GetGeomType() const {return BOX;}
virtual FCDPhysicsAnalyticalGeometry* Clone();
public:
FMVector3 halfExtents;
};
class FCOLLADA_EXPORT FCDPASPlane : public FCDPhysicsAnalyticalGeometry
{
public:
FCDPASPlane(FCDocument* document);
virtual ~FCDPASPlane() {}
virtual FUStatus LoadFromXML(xmlNode* node);
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
virtual GeomType GetGeomType() const {return PLANE;}
virtual FCDPhysicsAnalyticalGeometry* Clone();
public:
FMVector3 normal;
float d;
};
class FCOLLADA_EXPORT FCDPASSphere : public FCDPhysicsAnalyticalGeometry
{
public:
FCDPASSphere(FCDocument* document);
virtual ~FCDPASSphere() {}
virtual FUStatus LoadFromXML(xmlNode* node);
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
virtual GeomType GetGeomType() const {return SPHERE;}
virtual FCDPhysicsAnalyticalGeometry* Clone();
public:
float radius;
};
class FCOLLADA_EXPORT FCDPASCylinder : public FCDPhysicsAnalyticalGeometry
{
public:
FCDPASCylinder(FCDocument* document);
virtual ~FCDPASCylinder() {}
virtual FUStatus LoadFromXML(xmlNode* node);
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
virtual GeomType GetGeomType() const {return CYLINDER;}
virtual FCDPhysicsAnalyticalGeometry* Clone();
public:
float height;
float radius;
};
class FCOLLADA_EXPORT FCDPASCapsule : public FCDPhysicsAnalyticalGeometry
{
public:
FCDPASCapsule(FCDocument* document);
virtual ~FCDPASCapsule() {}
virtual FUStatus LoadFromXML(xmlNode* node);
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
virtual GeomType GetGeomType() const {return CAPSULE;}
virtual FCDPhysicsAnalyticalGeometry* Clone();
public:
float height;
float radius;
};
class FCOLLADA_EXPORT FCDPASTaperedCapsule : public FCDPASCapsule
{
public:
FCDPASTaperedCapsule(FCDocument* document);
virtual ~FCDPASTaperedCapsule() {}
virtual FUStatus LoadFromXML(xmlNode* node);
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
virtual GeomType GetGeomType() const {return TAPERED_CAPSULE;}
virtual FCDPhysicsAnalyticalGeometry* Clone();
public:
//inherits all other attributes from Capsule
float radius2;
};
class FCOLLADA_EXPORT FCDPASTaperedCylinder : public FCDPASCylinder
{
public:
FCDPASTaperedCylinder(FCDocument* document);
virtual ~FCDPASTaperedCylinder() {}
virtual FUStatus LoadFromXML(xmlNode* node);
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
virtual GeomType GetGeomType() const {return TAPERED_CYLINDER;}
virtual FCDPhysicsAnalyticalGeometry* Clone();
public:
//inherits all other attributes from Cylinder
float radius2;
};
#endif // _FCD_PHYSICS_ANALYTICAL_GEOMETRY_H_

View File

@@ -0,0 +1,88 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDocument.h"
#include "FCDocument/FCDPhysicsMaterial.h"
#include "FUtils/FUStringConversion.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDPhysicsMaterial::FCDPhysicsMaterial(FCDocument* document) : FCDEntity(document, "PhysicsMaterial")
{
staticFriction = 0.f;
dynamicFriction = 0.f;
restitution = 0.f;
}
FCDPhysicsMaterial::~FCDPhysicsMaterial()
{
}
// Cloning
FCDPhysicsMaterial* FCDPhysicsMaterial::Clone()
{
FCDPhysicsMaterial* clone = new FCDPhysicsMaterial(GetDocument());
FCDEntity::Clone(clone);
clone->SetStaticFriction(staticFriction);
clone->SetDynamicFriction(dynamicFriction);
clone->SetRestitution(restitution);
return clone;
}
// Parse COLLADA document's <physics_material> element
FUStatus FCDPhysicsMaterial::LoadFromXML(xmlNode* physicsMaterialNode)
{
FUStatus status = FCDEntity::LoadFromXML(physicsMaterialNode);
if (!status) return status;
if (!IsEquivalent(physicsMaterialNode->name, DAE_PHYSICS_MATERIAL_ELEMENT))
{
return status.Warning(FS("Unknown element in physics material library."), physicsMaterialNode->line);
}
//read in the <technique_common> element
xmlNode* commonTechniqueNode = FindTechnique(physicsMaterialNode, DAE_COMMON_PROFILE);
if (commonTechniqueNode == NULL)
{
return status.Fail(FS("Unable to find common technique for physics material: ") + TO_FSTRING(GetDaeId()), physicsMaterialNode->line);
}
xmlNode* paramNode = FindChildByType(commonTechniqueNode, DAE_PHYSICS_STATIC_FRICTION);
if (paramNode != NULL)
{
const char* content = ReadNodeContentDirect(paramNode);
staticFriction = FUStringConversion::ToFloat(content);
}
paramNode = FindChildByType(commonTechniqueNode, DAE_PHYSICS_DYNAMIC_FRICTION);
if (paramNode != NULL)
{
const char* content = ReadNodeContentDirect(paramNode);
dynamicFriction = FUStringConversion::ToFloat(content);
}
paramNode = FindChildByType(commonTechniqueNode, DAE_PHYSICS_RESTITUTION);
if (paramNode != NULL)
{
const char* content = ReadNodeContentDirect(paramNode);
restitution = FUStringConversion::ToFloat(content);
}
return status;
}
// Write out the <physics_material> element to the COLLADA xml tree
xmlNode* FCDPhysicsMaterial::WriteToXML(xmlNode* parentNode) const
{
xmlNode* physicsMaterialNode = WriteToEntityXML(parentNode, DAE_PHYSICS_MATERIAL_ELEMENT);
AddChild(physicsMaterialNode, DAE_PHYSICS_STATIC_FRICTION, staticFriction);
AddChild(physicsMaterialNode, DAE_PHYSICS_DYNAMIC_FRICTION, dynamicFriction);
AddChild(physicsMaterialNode, DAE_PHYSICS_RESTITUTION, restitution);
FCDEntity::WriteToExtraXML(physicsMaterialNode);
return physicsMaterialNode;
}

View File

@@ -0,0 +1,43 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#ifndef _FCD_PHYSICSMATERIAL_H_
#define _FCD_PHYSICSMATERIAL_H_
#include "FCDocument/FCDEntity.h"
class FCDocument;
class FCOLLADA_EXPORT FCDPhysicsMaterial : public FCDEntity
{
private:
float staticFriction;
float dynamicFriction;
float restitution;
public:
FCDPhysicsMaterial(FCDocument* document);
virtual ~FCDPhysicsMaterial();
// Accessors
virtual Type GetType() const { return FCDEntity::PHYSICS_MATERIAL; }
float GetStaticFriction() const { return staticFriction; }
void SetStaticFriction(float _staticFriction) { staticFriction = _staticFriction; }
float GetDynamicFriction() const { return dynamicFriction; }
void SetDynamicFriction(float _dynamicFriction) { dynamicFriction = _dynamicFriction; }
float GetRestitution() const { return restitution; }
void SetRestitution(float _restitution) { restitution = _restitution;}
// Cloning
FCDPhysicsMaterial* Clone();
// Parse COLLADA document's <material> element
virtual FUStatus LoadFromXML(xmlNode* physicsMaterialNode);
// Write out the <material> element to the COLLADA xml tree
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif // _FCD_MATERIAL_H_

View File

@@ -0,0 +1,134 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDPhysicsModel.h"
#include "FCDocument/FCDPhysicsRigidBody.h"
#include "FCDocument/FCDPhysicsRigidConstraint.h"
#include "FCDocument/FCDocument.h"
#include "FCDocument/FCDAnimated.h"
#include "FUtils/FUStringConversion.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDPhysicsModel::FCDPhysicsModel(FCDocument* document) : FCDEntity(document, "PhysicsModel")
{
}
FCDPhysicsModel::~FCDPhysicsModel()
{
CLEAR_POINTER_VECTOR(instances);
CLEAR_POINTER_VECTOR(rigidBodies);
CLEAR_POINTER_VECTOR(rigidConstraints);
}
// Create a copy of this physicsModel, with the vertices overwritten
FCDPhysicsModel* FCDPhysicsModel::Clone(/*FloatList& newPositions, uint32 newPositionsStride, FloatList& newNormals, uint32 newNormalsStride*/)
{
FCDPhysicsModel* clone = new FCDPhysicsModel(GetDocument());
return clone;
}
FCDPhysicsRigidBody* FCDPhysicsModel::FindRigidBodyFromSid(const string& sid)
{
for(FCDPhysicsRigidBodyList::iterator it = rigidBodies.begin(); it!= rigidBodies.end(); ++it)
{
if((*it)->GetSid()==sid) return (*it);
}
return NULL;
}
FCDPhysicsRigidConstraint* FCDPhysicsModel::FindRigidConstraintFromSid(const string& sid)
{
for(FCDPhysicsRigidConstraintList::iterator it = rigidConstraints.begin(); it!= rigidConstraints.end(); ++it)
{
if((*it)->GetSid()==sid) return (*it);
}
return NULL;
}
// Load from a XML node the given physicsModel
FUStatus FCDPhysicsModel::LoadFromXML(xmlNode* physicsModelNode)
{
FUStatus status = FCDEntity::LoadFromXML(physicsModelNode);
if (!status) return status;
if (!IsEquivalent(physicsModelNode->name, DAE_PHYSICS_MODEL_ELEMENT))
{
return status.Warning(FS("PhysicsModel library contains unknown element."), physicsModelNode->line);
}
// Read in the first valid child element found
for (xmlNode* child = physicsModelNode->children; child != NULL; child = child->next)
{
if (child->type != XML_ELEMENT_NODE) continue;
if(IsEquivalent(child->name, DAE_RIGID_BODY_ELEMENT))
{
FCDPhysicsRigidBody* rigidBody = new FCDPhysicsRigidBody(GetDocument());
status.AppendStatus(rigidBody->LoadFromXML(child));
rigidBodies.push_back(rigidBody);
}
else if(IsEquivalent(child->name, DAE_RIGID_CONSTRAINT_ELEMENT))
{
FCDPhysicsRigidConstraint* rigidConstraint = new FCDPhysicsRigidConstraint(GetDocument(), this);
status.AppendStatus(rigidConstraint->LoadFromXML(child));
rigidConstraints.push_back(rigidConstraint);
}
else if(IsEquivalent(child->name, DAE_INSTANCE_PHYSICS_MODEL_ELEMENT))
{
//FIXME: the instantiated physicsModel might not have been parsed yet
FUUri url = ReadNodeUrl(child);
if (url.prefix.empty())
{
FCDEntity* entity = GetDocument()->FindPhysicsModel(url.suffix);
if (entity != NULL)
{
FCDEntityInstance* instance = new FCDEntityInstance(GetDocument(), entity);
instances.push_back(instance);
status.AppendStatus(instance->LoadFromXML(child));
}
else
{
status.Warning(FS("Unable to retrieve instance for scene node: ") + TO_FSTRING(GetDaeId()), child->line);
}
}
}
else if(IsEquivalent(child->name, DAE_ASSET_ELEMENT))
{
}
else if(IsEquivalent(child->name, DAE_EXTRA_ELEMENT))
{
}
}
return status;
}
// Write out the <physicsModel> node
xmlNode* FCDPhysicsModel::WriteToXML(xmlNode* parentNode) const
{
xmlNode* physicsModelNode = WriteToEntityXML(parentNode, DAE_PHYSICS_MODEL_ELEMENT);
for(FCDEntityInstanceList::const_iterator it = instances.begin(); it != instances.end(); ++it)
{
(*it)->WriteToXML(physicsModelNode);
}
for(FCDPhysicsRigidBodyList::const_iterator it = rigidBodies.begin(); it != rigidBodies.end(); ++it)
{
(*it)->WriteToXML(physicsModelNode);
}
for(FCDPhysicsRigidConstraintList::const_iterator it = rigidConstraints.begin(); it != rigidConstraints.end(); ++it)
{
(*it)->WriteToXML(physicsModelNode);
}
//TODO: Add asset and extra
FCDEntity::WriteToExtraXML(physicsModelNode);
return physicsModelNode;
}

View File

@@ -0,0 +1,52 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#ifndef _FCD_PHYSICSMODEL_H_
#define _FCD_PHYSICSMODEL_H_
#include "FCDocument/FCDEntity.h"
#include "FCDocument/FCDEntityInstance.h"
#include "FUtils/FUDaeEnum.h"
class FCDocument;
class FCDPhysicsRigidBody;
class FCDPhysicsRigidConstraint;
typedef vector<FCDEntityInstance*> FCDEntityInstanceList;
typedef vector<FCDPhysicsRigidBody*> FCDPhysicsRigidBodyList;
typedef vector<FCDPhysicsRigidConstraint*> FCDPhysicsRigidConstraintList;
class FCOLLADA_EXPORT FCDPhysicsModel : public FCDEntity
{
private:
FCDEntityInstanceList instances;
FCDPhysicsRigidBodyList rigidBodies;
FCDPhysicsRigidConstraintList rigidConstraints;
public:
FCDPhysicsModel(FCDocument* document);
virtual ~FCDPhysicsModel();
// Returns the entity type
virtual Type GetType() const { return PHYSICS_MODEL; }
// Direct Accessors
FCDEntityInstanceList& GetInstances() { return instances; }
const FCDEntityInstanceList& GetInstances() const { return instances; }
FCDPhysicsRigidBody* FindRigidBodyFromSid(const string& sid);
FCDPhysicsRigidConstraint* FindRigidConstraintFromSid(const string& sid);
// Create a copy of this physicsmodel, with the vertices overwritten
FCDPhysicsModel* Clone(/*FloatList& newPositions, uint32 newPositionsStride, FloatList& newNormals, uint32 newNormalsStride*/);
// Read in the <physics_model> node of the COLLADA document
virtual FUStatus LoadFromXML(xmlNode* node);
// Write out the <physics_model> node to the COLLADA xml tree
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif // _FCD_PHYSICSMODEL_H_

View File

@@ -0,0 +1,91 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDocument.h"
#include "FCDocument/FCDController.h"
#include "FCDocument/FCDEntity.h"
#include "FCDocument/FCDPhysicsModel.h"
#include "FCDocument/FCDPhysicsModelInstance.h"
#include "FCDocument/FCDPhysicsRigidBodyInstance.h"
#include "FCDocument/FCDPhysicsRigidConstraintInstance.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDPhysicsModelInstance::FCDPhysicsModelInstance(FCDocument* document, FCDEntity* entity) : FCDEntityInstance(document, entity)
{
SetClassName("FCDPhysicsModelInstance");
}
FCDPhysicsModelInstance::~FCDPhysicsModelInstance()
{
CLEAR_POINTER_VECTOR(instances);
}
// Load the geometry instance from the COLLADA document
FUStatus FCDPhysicsModelInstance::LoadFromXML(xmlNode* instanceNode)
{
FUStatus status = FCDEntityInstance::LoadFromXML(instanceNode);
if (!status) return status;
if (entity == NULL)
{
return status.Fail(FS("Trying to instantiate non-valid physics entity."), instanceNode->line);
}
// Check for the expected instantiation node type
if (!IsEquivalent(instanceNode->name, DAE_INSTANCE_PHYSICS_MODEL_ELEMENT))
{
return status.Fail(FS("Unknown element for instantiation of entity: ") + TO_FSTRING(entity->GetDaeId()), instanceNode->line);
}
//this is already done in the FCDSceneNode
// string physicsModelId = ReadNodeProperty(instanceNode, DAE_TARGET_ATTRIBUTE);
// entity = GetDocument()->FindPhysicsModel(physicsModelId);
// if(!entity) return status.Fail(FS("Couldn't find physics model for instantiation"), instanceNode->line);
xmlNodeList rigidBodyNodes;
FindChildrenByType(instanceNode, DAE_INSTANCE_RIGID_BODY_ELEMENT, rigidBodyNodes);
for(xmlNodeList::iterator itB = rigidBodyNodes.begin(); itB != rigidBodyNodes.end(); ++itB)
{
FCDPhysicsRigidBodyInstance* instance = new FCDPhysicsRigidBodyInstance(GetDocument(), entity);
status.AppendStatus(instance->LoadFromXML(*itB));
instances.push_back(instance);
}
xmlNodeList rigidConstraintNodes;
FindChildrenByType(instanceNode, DAE_INSTANCE_RIGID_CONSTRAINT_ELEMENT, rigidConstraintNodes);
for(xmlNodeList::iterator itC = rigidConstraintNodes.begin(); itC != rigidConstraintNodes.end(); ++itC)
{
FCDPhysicsRigidConstraintInstance* instance = new FCDPhysicsRigidConstraintInstance(GetDocument(), entity);
status.AppendStatus(instance->LoadFromXML(*itC));
instances.push_back(instance);
}
//FIXME: create a FCDPhysicsForceFieldInstance class
xmlNodeList forceFieldNodes;
FindChildrenByType(instanceNode, DAE_INSTANCE_FORCE_FIELD_ELEMENT, forceFieldNodes);
for(xmlNodeList::iterator itN = forceFieldNodes.begin(); itN != forceFieldNodes.end(); ++itN)
{
FCDEntityInstance* instance = new FCDEntityInstance(GetDocument(), NULL);
status.AppendStatus(instance->LoadFromXML(*itN));
instances.push_back(instance);
}
return status;
}
// Write out the instantiation information to the xml node tree
xmlNode* FCDPhysicsModelInstance::WriteToXML(xmlNode* parentNode) const
{
xmlNode* instanceNode = FCDEntityInstance::WriteToXML(parentNode);
for(FCDEntityInstanceList::const_iterator it = instances.begin(); it != instances.end(); ++it)
{
(*it)->WriteToXML(instanceNode);
}
return instanceNode;
}

View File

@@ -0,0 +1,36 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#ifndef _FCD_PHYSICS_MODEL_ENTITY_H_
#define _FCD_PHYSICS_MODEL_ENTITY_H_
#include "FCDocument/FCDEntityInstance.h"
class FCDocument;
typedef vector<FCDEntityInstance*> FCDEntityInstanceList;
class FCOLLADA_EXPORT FCDPhysicsModelInstance : public FCDEntityInstance
{
private:
FCDEntityInstanceList instances;
public:
FCDPhysicsModelInstance(FCDocument* document, FCDEntity* entity);
virtual ~FCDPhysicsModelInstance();
FCDEntityInstanceList& GetInstances() {return instances;}
// FCDEntity override for RTTI-like
virtual Type GetType() const { return PHYSICS_MODEL; }
// Load the geometry instance from the COLLADA document
virtual FUStatus LoadFromXML(xmlNode* instanceNode);
// Write out the instantiation information to the xml node tree
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif // _FCD_PHYSICS_MODEL_ENTITY_H_

View File

@@ -0,0 +1,45 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#ifndef _FCD_PHYSICS_PARAMETER_H_
#define _FCD_PHYSICS_PARAMETER_H_
#include "FCDocument/FCDPhysicsParameterGeneric.h"
class FCDocument;
template <class T>
class FCOLLADA_EXPORT FCDPhysicsParameter: public FCDPhysicsParameterGeneric
{
public:
FCDPhysicsParameter(FCDocument* document, const string& ref);
virtual ~FCDPhysicsParameter();
// Clone
virtual FCDPhysicsParameterGeneric* Clone();
void SetValue(T val);
void SetValue(T* val);
T* GetValue() const {return value;}
// Flattening: overwrite the target parameter with this parameter
virtual void Overwrite(FCDPhysicsParameterGeneric* target);
// Parse in this ColladaFX parameter from the xml node tree
// virtual FUStatus LoadFromXML(xmlNode* parameterNode);
// Write out this ColladaFX parameter to the xml node tree
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
protected:
T* value;
};
#include "FCDPhysicsParameter.hpp"
#endif // _FCD_PHYSICS_PARAMETER_H_

View File

@@ -0,0 +1,77 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDocument.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeWriter;
template <class T>
FCDPhysicsParameter<T>::FCDPhysicsParameter(FCDocument* document, const string& ref) : FCDPhysicsParameterGeneric(document, ref)
{
value = NULL;
}
template <class T>
FCDPhysicsParameter<T>::~FCDPhysicsParameter()
{
SAFE_DELETE(value);
}
// Clone
template <class T>
FCDPhysicsParameterGeneric* FCDPhysicsParameter<T>::Clone()
{
FCDPhysicsParameterGeneric *clone = new FCDPhysicsParameter<T>(GetDocument(), reference);
((FCDPhysicsParameter<T>*)clone)->value = new T(*value);
return clone;
}
template <class T>
void FCDPhysicsParameter<T>::SetValue(T val)
{
if(value)
{
SAFE_DELETE(value);
}
value = new T();
*value = val;
}
template <class T>
void FCDPhysicsParameter<T>::SetValue(T* val)
{
if(value)
{
SAFE_DELETE(value);
}
value = val;
}
// Flattening: overwrite the target parameter with this parameter
template <class T>
void FCDPhysicsParameter<T>::Overwrite(FCDPhysicsParameterGeneric* target)
{
((FCDPhysicsParameter<T>*) target)->SetValue(value);
}
/*
// Parse in this Collada parameter from the xml node tree
template <class T>
FUStatus FCDPhysicsParameter<T>::LoadFromXML(xmlNode* parameterNode)
{
FUStatus status;
return status;
}
*/
// Write out this ColladaFX parameter to the xml node tree
template <class T>
xmlNode* FCDPhysicsParameter<T>::WriteToXML(xmlNode* parentNode) const
{
xmlNode* parameterNode = FUXmlWriter::AddChild(parentNode, reference.c_str());
//TODO: complete
return parameterNode;
}

View File

@@ -0,0 +1,18 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDPhysicsParameterGeneric.h"
#include "FCDocument/FCDocument.h"
FCDPhysicsParameterGeneric::FCDPhysicsParameterGeneric(FCDocument* document, const string& ref) : FCDObject(document, "FCDPhysicsParameterGeneric")
{
isGenerator = true;
reference = ref;
}
FCDPhysicsParameterGeneric::~FCDPhysicsParameterGeneric()
{
}

View File

@@ -0,0 +1,41 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#ifndef _FCD_PHYSICS_PARAMETER_GENERIC_H_
#define _FCD_PHYSICS_PARAMETER_GENERIC_H_
#include "FCDocument/FCDObject.h"
class FCDocument;
class FCOLLADA_EXPORT FCDPhysicsParameterGeneric: public FCDObject
{
public:
FCDPhysicsParameterGeneric(FCDocument* document, const string& ref);
virtual ~FCDPhysicsParameterGeneric();
virtual FCDPhysicsParameterGeneric* Clone()=0;
bool IsGenerator() const { return isGenerator; }
bool IsModifier() const { return !isGenerator; }
const string& GetReference() const {return reference;};
void SetReference(const string& ref) {reference = ref;};
void SetGenerator(bool val) {isGenerator = val;}
virtual void Overwrite(FCDPhysicsParameterGeneric* target) = 0;
// Parse in this ColladaFX parameter from the xml node tree
// virtual FUStatus LoadFromXML(xmlNode* parameterNode) = 0;
// Write out this ColladaFX parameter to the xml node tree
virtual xmlNode* WriteToXML(xmlNode* parentNode) const = 0;
protected:
bool isGenerator; // whether this effect parameter structure generates a new value or modifies an existing value (is <newparam>?)
string reference;
};
#endif // _FCD_PHYSICS_PARAMETER_GENERIC_H_

View File

@@ -0,0 +1,253 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDPhysicsRigidBody.h"
#include "FCDocument/FCDPhysicsMaterial.h"
#include "FCDocument/FCDocument.h"
#include "FUtils/FUStringConversion.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDPhysicsRigidBody::FCDPhysicsRigidBody(FCDocument* document) : FCDEntity(document, "RigidBody")
{
physicsMaterial = NULL;
SetMaterialOwnership(false);
}
FCDPhysicsRigidBody::~FCDPhysicsRigidBody()
{
CLEAR_POINTER_VECTOR(parameters);
CLEAR_POINTER_VECTOR(physicsShape);
if(ownsPhysicsMaterial)
{
SAFE_DELETE(physicsMaterial);
}
else
{
physicsMaterial = NULL;
}
}
// Create a copy of this physicsRigidBody
FCDPhysicsRigidBody* FCDPhysicsRigidBody::Clone()
{
FCDPhysicsRigidBody* clone = new FCDPhysicsRigidBody(GetDocument());
FCDEntity::Clone(clone);
clone->SetParameters(parameters);
clone->SetPhysicsShapes(physicsShape);
clone->SetPhysicsMaterial(physicsMaterial);
return clone;
}
void FCDPhysicsRigidBody::SetParameters(FCDPhysicsParameterList& params)
{
for (size_t i = 0; i < params.size(); ++i)
{
CopyParameter(params[i]);
}
}
void FCDPhysicsRigidBody::CopyParameter(FCDPhysicsParameterGeneric* parameter)
{
FCDPhysicsParameterGeneric* p = parameter->Clone();
parameters.push_back(p);
}
void FCDPhysicsRigidBody::AddParameter(FCDPhysicsParameterGeneric* parameter)
{
parameters.push_back(parameter);
}
void FCDPhysicsRigidBody::SetPhysicsMaterial(FCDPhysicsMaterial* _physicsMaterial)
{
if(physicsMaterial && ownsPhysicsMaterial)
SAFE_DELETE(physicsMaterial);
physicsMaterial = _physicsMaterial;
SetMaterialOwnership(false);
}
void FCDPhysicsRigidBody::SetPhysicsShapes(FCDPhysicsShapeList& _physicsShape)
{
physicsShape.clear();
for(FCDPhysicsShapeList::iterator it = _physicsShape.begin(); it != _physicsShape.end(); it++)
physicsShape.push_back((*it)->Clone());
}
// Load from a XML node the given physicsRigidBody
//FIXME: Default values not assigned if child elements not found
FUStatus FCDPhysicsRigidBody::LoadFromXML(xmlNode* physicsRigidBodyNode)
{
FUStatus status = FCDEntity::LoadFromXML(physicsRigidBodyNode);
if (!status) return status;
if (!IsEquivalent(physicsRigidBodyNode->name, DAE_RIGID_BODY_ELEMENT))
{
return status.Warning(FS("PhysicsRigidBody library contains unknown element."), physicsRigidBodyNode->line);
}
sid = FUDaeParser::ReadNodeSid(physicsRigidBodyNode);
xmlNode* techniqueNode = FindChildByType(physicsRigidBodyNode, DAE_TECHNIQUE_COMMON_ELEMENT);
if (techniqueNode != NULL)
{
xmlNode* param = FindChildByType(techniqueNode, DAE_DYNAMIC_ELEMENT);
if(param)
{
FCDPhysicsParameter<bool>* p = new FCDPhysicsParameter<bool>(GetDocument(), DAE_DYNAMIC_ELEMENT);
p->SetValue(FUStringConversion::ToBoolean(ReadNodeContentDirect(param)));
AddParameter(p);
}
xmlNode* massFrame;
massFrame = FindChildByType(techniqueNode, DAE_MASS_FRAME_ELEMENT);
if(massFrame)
{
param = FindChildByType(massFrame, DAE_TRANSLATE_ELEMENT);
if(param)
{
FCDPhysicsParameter<FMVector3>* p = new FCDPhysicsParameter<FMVector3>(GetDocument(), DAE_TRANSLATE_ELEMENT);
p->SetValue(FUStringConversion::ToPoint(ReadNodeContentDirect(param)));
AddParameter(p);
}
param = FindChildByType(massFrame, DAE_ROTATE_ELEMENT);
if(param)
{
FCDPhysicsParameter<FMVector3>* p = new FCDPhysicsParameter<FMVector3>(GetDocument(), DAE_ROTATE_ELEMENT);
p->SetValue(FUStringConversion::ToPoint(ReadNodeContentDirect(param)));
AddParameter(p);
}
}
param = FindChildByType(techniqueNode, DAE_INERTIA_ELEMENT);
if(param)
{
FCDPhysicsParameter<FMVector3>* p = new FCDPhysicsParameter<FMVector3>(GetDocument(), DAE_INERTIA_ELEMENT);
p->SetValue(FUStringConversion::ToPoint(ReadNodeContentDirect(param)));
AddParameter(p);
}
param = FindChildByType(techniqueNode, DAE_MASS_ELEMENT);
if(param)
{
FCDPhysicsParameter<float>* p = new FCDPhysicsParameter<float>(GetDocument(), DAE_MASS_ELEMENT);
p->SetValue(FUStringConversion::ToFloat(ReadNodeContentDirect(param)));
AddParameter(p);
}
xmlNodeList shapeNodes;
FindChildrenByType(techniqueNode, DAE_SHAPE_ELEMENT, shapeNodes);
for(xmlNodeList::iterator itS = shapeNodes.begin(); itS != shapeNodes.end(); ++itS)
{
FCDPhysicsShape* shape = new FCDPhysicsShape(GetDocument());
status.AppendStatus(shape->LoadFromXML(*itS));
physicsShape.push_back(shape);
}
param = FindChildByType(techniqueNode, DAE_PHYSICS_MATERIAL_ELEMENT);
if(param)
{
if(physicsMaterial && ownsPhysicsMaterial)
SAFE_DELETE(physicsMaterial);
physicsMaterial = new FCDPhysicsMaterial(GetDocument());
physicsMaterial->LoadFromXML(param);
SetMaterialOwnership(true);
}
else
{
param = FindChildByType(techniqueNode, DAE_INSTANCE_PHYSICS_MATERIAL_ELEMENT);
if (param == NULL)
{
return status.Fail(FS("Error: No physics material defined in rigid body."), techniqueNode->line);
}
FUUri url = ReadNodeUrl(param);
if (url.prefix.empty())
{
physicsMaterial = GetDocument()->FindPhysicsMaterial(url.suffix);
if(!physicsMaterial)
{
return status.Fail(FS("Error: Instantiated physics material in rigid body was not found."), techniqueNode->line);
}
}
}
}
return status;
}
// Flatten the rigid body: remove all the modifier parameters from the parameter list, permanently modifying their base parameter
void FCDPhysicsRigidBody::Flatten()
{
vector<FCDPhysicsParameterList::iterator> toDelete;
for (FCDPhysicsParameterList::iterator itP = parameters.begin(); itP != parameters.end(); ++itP)
{
FCDPhysicsParameterList generators;
if ((*itP)->IsModifier())
{
// Overwrite the generators
FCDPhysicsParameterGeneric* generator = FindParameterByReference((*itP)->GetReference());
if(generator)
{
(*itP)->Overwrite(generator);
toDelete.push_back(itP);
}
else
{
(*itP)->SetGenerator(true);
}
}
}
while(!toDelete.empty())
{
parameters.erase(*toDelete.begin());
SAFE_DELETE(**(toDelete.begin()));
toDelete.erase(toDelete.begin());
}
}
FCDPhysicsParameterGeneric* FCDPhysicsRigidBody::FindParameterByReference(const string& reference)
{
for (FCDPhysicsParameterList::iterator it = parameters.begin(); it != parameters.end(); ++it)
{
if ((*it)->GetReference() == reference) return (*it);
}
return NULL;
}
// Write out the <physicsRigidBody> node
xmlNode* FCDPhysicsRigidBody::WriteToXML(xmlNode* parentNode) const
{
xmlNode* physicsRigidBodyNode = WriteToEntityXML(parentNode, DAE_RIGID_BODY_ELEMENT);
xmlNode* baseNode = AddChild(physicsRigidBodyNode, DAE_TECHNIQUE_COMMON_ELEMENT);
if(physicsMaterial)
physicsMaterial->WriteToXML(baseNode);
for(FCDPhysicsShapeList::const_iterator it = physicsShape.begin(); it != physicsShape.end(); ++it)
{
(*it)->WriteToXML(baseNode);
}
for(FCDPhysicsParameterList::const_iterator it = parameters.begin(); it != parameters.end(); ++it)
{
(*it)->WriteToXML(baseNode);
}
FCDEntity::WriteToExtraXML(physicsRigidBodyNode);
return physicsRigidBodyNode;
}

View File

@@ -0,0 +1,64 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#ifndef _FCD_PHYSICSRIGIDBODY_H_
#define _FCD_PHYSICSRIGIDBODY_H_
#include "FCDocument/FCDEntity.h"
#include "FCDocument/FCDEntityInstance.h"
#include "FCDocument/FCDPhysicsParameter.h"
#include "FCDocument/FCDTransform.h"
#include "FCDocument/FCDPhysicsShape.h"
#include "FUtils/FUDaeEnum.h"
class FCDocument;
typedef std::vector<FCDPhysicsParameterGeneric*> FCDPhysicsParameterList;
typedef std::vector<FCDPhysicsShape*> FCDPhysicsShapeList;
class FCOLLADA_EXPORT FCDPhysicsRigidBody : public FCDEntity
{
private:
string sid;
bool ownsPhysicsMaterial;
FCDPhysicsMaterial* physicsMaterial;
FCDPhysicsParameterList parameters;
FCDPhysicsShapeList physicsShape;
public:
FCDPhysicsRigidBody(FCDocument* document);
virtual ~FCDPhysicsRigidBody();
string GetSid() const { return sid; }
// Returns the entity type
virtual Type GetType() const { return PHYSICS_RIGID_BODY; }
void AddParameter(FCDPhysicsParameterGeneric* parameter);
void CopyParameter(FCDPhysicsParameterGeneric* parameter);
void SetParameters(FCDPhysicsParameterList& params);
FCDPhysicsParameterGeneric* FindParameterByReference(const string& reference);
// Direct Accessors
FCDPhysicsMaterial* GetPhysicsMaterial() const {return physicsMaterial;}
void SetPhysicsMaterial(FCDPhysicsMaterial* _physicsMaterial);
FCDPhysicsShapeList& GetPhysicsShapeList() {return physicsShape;}
void SetPhysicsShapes(FCDPhysicsShapeList& _physicsShape);
void SetMaterialOwnership(bool val) {ownsPhysicsMaterial = val;}
void Flatten();
// Create a copy of this physicsmodel, with the vertices overwritten
FCDPhysicsRigidBody* Clone();
// Read in the <physics_model> node of the COLLADA document
virtual FUStatus LoadFromXML(xmlNode* node);
// Write out the <physics_model> node to the COLLADA xml tree
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif // _FCD_PHYSICSRIGIDBODY_H_

View File

@@ -0,0 +1,198 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDocument.h"
#include "FCDocument/FCDEntity.h"
#include "FCDocument/FCDPhysicsMaterial.h"
#include "FCDocument/FCDPhysicsModel.h"
#include "FCDocument/FCDPhysicsModelInstance.h"
#include "FCDocument/FCDPhysicsRigidBody.h"
#include "FCDocument/FCDPhysicsRigidBodyInstance.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDPhysicsRigidBodyInstance::FCDPhysicsRigidBodyInstance(FCDocument* document, FCDEntity* _parent) : FCDEntityInstance(document, NULL)
{
if(_parent->GetType() == FCDEntity::PHYSICS_MODEL)
parent = (FCDPhysicsModel*)_parent;
rigidBody = NULL;
physicsMaterial = NULL;
ownsPhysicsMaterial = false;
SetClassName("FCDPhysicsRigidBodyInstance");
}
FCDPhysicsRigidBodyInstance::~FCDPhysicsRigidBodyInstance()
{
parent = NULL;
rigidBody = NULL;
CLEAR_POINTER_VECTOR(parameters);
if(ownsPhysicsMaterial)
{
SAFE_DELETE(physicsMaterial);
}
else
{
physicsMaterial = NULL;
}
}
void FCDPhysicsRigidBodyInstance::AddParameter(FCDPhysicsParameterGeneric* parameter)
{
parameters.push_back(parameter);
}
// Load the geometry instance from the COLLADA document
FUStatus FCDPhysicsRigidBodyInstance::LoadFromXML(xmlNode* instanceNode)
{
FUStatus status = FCDEntityInstance::LoadFromXML(instanceNode);
if (!status) return status;
// Check for the expected instantiation node type
if (!IsEquivalent(instanceNode->name, DAE_INSTANCE_RIGID_BODY_ELEMENT))
{
return status.Fail(FS("Unknown element for instantiation of entity: ") + TO_FSTRING(entity->GetDaeId()), instanceNode->line);
}
if (parent == NULL)
{
return status.Fail(FS("No Physics Model parent for rigid body instantiation"), instanceNode->line);
}
string targetNodeId = ReadNodeProperty(instanceNode, DAE_TARGET_ATTRIBUTE);
targetNode = GetDocument()->FindSceneNode(SkipPound(targetNodeId));
if(!targetNode)
{
return status.Fail(FS("Couldn't find target node for instantiation of rigid body"), instanceNode->line);
}
string physicsRigidBodySid = ReadNodeProperty(instanceNode, DAE_BODY_ATTRIBUTE);
entity = rigidBody = parent->FindRigidBodyFromSid(physicsRigidBodySid);
if(!rigidBody)
{
return status.Fail(FS("Couldn't find rigid body for instantiation"), instanceNode->line);
}
//Read in the same children as rigid_body + velocity and angular_velocity
xmlNode* techniqueNode = FindChildByType(instanceNode, DAE_TECHNIQUE_COMMON_ELEMENT);
xmlNode* param = FindChildByType(techniqueNode, DAE_DYNAMIC_ELEMENT);
if(param)
{
FCDPhysicsParameter<bool>* p = new FCDPhysicsParameter<bool>(GetDocument(), DAE_DYNAMIC_ELEMENT);
p->SetValue(FUStringConversion::ToBoolean(ReadNodeContentDirect(param)));
AddParameter(p);
}
xmlNode* massFrame;
massFrame = FindChildByType(techniqueNode, DAE_MASS_FRAME_ELEMENT);
if(massFrame)
{
param = FindChildByType(massFrame, DAE_TRANSLATE_ELEMENT);
if(param)
{
FCDPhysicsParameter<FMVector3>* p = new FCDPhysicsParameter<FMVector3>(GetDocument(), DAE_TRANSLATE_ELEMENT);
p->SetValue(FUStringConversion::ToPoint(ReadNodeContentDirect(param)));
AddParameter(p);
}
param = FindChildByType(massFrame, DAE_ROTATE_ELEMENT);
if(param)
{
FCDPhysicsParameter<FMVector3>* p = new FCDPhysicsParameter<FMVector3>(GetDocument(), DAE_ROTATE_ELEMENT);
p->SetValue(FUStringConversion::ToPoint(ReadNodeContentDirect(param)));
AddParameter(p);
}
}
param = FindChildByType(techniqueNode, DAE_INERTIA_ELEMENT);
if(param)
{
FCDPhysicsParameter<FMVector3>* p = new FCDPhysicsParameter<FMVector3>(GetDocument(), DAE_INERTIA_ELEMENT);
p->SetValue(FUStringConversion::ToPoint(ReadNodeContentDirect(param)));
AddParameter(p);
}
param = FindChildByType(techniqueNode, DAE_MASS_ELEMENT);
if(param)
{
FCDPhysicsParameter<float>* p = new FCDPhysicsParameter<float>(GetDocument(), DAE_MASS_ELEMENT);
p->SetValue(FUStringConversion::ToFloat(ReadNodeContentDirect(param)));
AddParameter(p);
}
param = FindChildByType(techniqueNode, DAE_PHYSICS_MATERIAL_ELEMENT);
if(param)
{
if(physicsMaterial && ownsPhysicsMaterial)
SAFE_DELETE(physicsMaterial);
physicsMaterial = new FCDPhysicsMaterial(GetDocument());
physicsMaterial->LoadFromXML(param);
ownsPhysicsMaterial = true;
}
else
{
param = FindChildByType(techniqueNode, DAE_INSTANCE_PHYSICS_MATERIAL_ELEMENT);
if(param)
{
physicsMaterial = GetDocument()->FindPhysicsMaterial(ReadNodeId(param));
ownsPhysicsMaterial = false;
}
}
param = FindChildByType(techniqueNode, DAE_VELOCITY_ELEMENT);
if(param)
{
FCDPhysicsParameter<FMVector3>* p = new FCDPhysicsParameter<FMVector3>(GetDocument(), DAE_VELOCITY_ELEMENT);
p->SetValue(FUStringConversion::ToPoint(ReadNodeContentDirect(param)));
AddParameter(p);
}
param = FindChildByType(techniqueNode, DAE_ANGULAR_VELOCITY_ELEMENT);
if(param)
{
FCDPhysicsParameter<FMVector3>* p = new FCDPhysicsParameter<FMVector3>(GetDocument(), DAE_ANGULAR_VELOCITY_ELEMENT);
p->SetValue(FUStringConversion::ToPoint(ReadNodeContentDirect(param)));
AddParameter(p);
}
return status;
}
FCDPhysicsRigidBody* FCDPhysicsRigidBodyInstance::FlattenRigidBody()
{
FCDPhysicsRigidBody* clone = rigidBody->Clone();
clone->Flatten();
for (FCDPhysicsParameterList::iterator itP = parameters.begin(); itP != parameters.end(); ++itP)
{
FCDPhysicsParameterGeneric* param = clone->FindParameterByReference((*itP)->GetReference());
if(param)
{
(*itP)->Overwrite(param);
}
else
{
clone->CopyParameter(*itP);
}
}
if(physicsMaterial)
clone->SetPhysicsMaterial(physicsMaterial);
return clone;
}
// Write out the instantiation information to the xml node tree
xmlNode* FCDPhysicsRigidBodyInstance::WriteToXML(xmlNode* parentNode) const
{
xmlNode* instanceNode = FCDEntityInstance::WriteToXML(parentNode);
//TODO
return instanceNode;
}

View File

@@ -0,0 +1,52 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#ifndef _FCD_PHYSICS_RIGID_BODY_ENTITY_H_
#define _FCD_PHYSICS_RIGID_BODY_ENTITY_H_
#include "FCDocument/FCDEntityInstance.h"
class FCDocument;
class FCDSceneNode;
class FCDPhysicsRigidBody;
class FCDPhysicsMaterial;
class FCDPhysicsModelInstance;
class FCDPhysicsParameterGeneric;
typedef std::vector<FCDPhysicsParameterGeneric*> FCDPhysicsParameterList;
class FCOLLADA_EXPORT FCDPhysicsRigidBodyInstance : public FCDEntityInstance
{
private:
FCDPhysicsParameterList parameters;
FCDPhysicsModel* parent;
FCDPhysicsRigidBody* rigidBody;
FCDPhysicsMaterial* physicsMaterial;
bool ownsPhysicsMaterial;
FCDSceneNode* targetNode;
public:
FCDPhysicsRigidBodyInstance(FCDocument* document, FCDEntity* _parent);
virtual ~FCDPhysicsRigidBodyInstance();
void AddParameter(FCDPhysicsParameterGeneric* parameter);
FCDPhysicsRigidBody* FlattenRigidBody();
FCDSceneNode* GetTargetNode() const {return targetNode;}
// FCDEntity override for RTTI-like
virtual Type GetType() const { return PHYSICS_RIGID_BODY; }
// Load the geometry instance from the COLLADA document
virtual FUStatus LoadFromXML(xmlNode* instanceNode);
// Write out the instantiation information to the xml node tree
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif // _FCD_PHYSICS_RIGID_BODY_ENTITY_H_

View File

@@ -0,0 +1,273 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDPhysicsModel.h"
#include "FCDocument/FCDPhysicsRigidConstraint.h"
#include "FCDocument/FCDPhysicsRigidBody.h"
#include "FCDocument/FCDocument.h"
#include "FUtils/FUStringConversion.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDPhysicsRigidConstraint::FCDPhysicsRigidConstraint(FCDocument* document, FCDPhysicsModel* _parent) : FCDEntity(document, "PhysicsRigidConstraint")
{
enabled = true;
interpenetrate = false;
parent = _parent;
limitsLinearMin = FMVector3(0.f, 0.f, 0.f);
limitsLinearMax = FMVector3(0.f, 0.f, 0.f);
limitsSCTMin = FMVector3(0.f, 0.f, 0.f);
limitsSCTMax = FMVector3(0.f, 0.f, 0.f);
referenceRigidBody = NULL;
targetRigidBody = NULL;
springLinearStiffness = 1.f;
springLinearDamping = 0.f;
springLinearTargetValue = 0.f;
springAngularStiffness = 1.f;
springAngularDamping = 0.f;
springAngularTargetValue = 0.f;
}
FCDPhysicsRigidConstraint::~FCDPhysicsRigidConstraint()
{
referenceRigidBody = NULL;
targetRigidBody = NULL;
CLEAR_POINTER_VECTOR(transformsRef);
CLEAR_POINTER_VECTOR(transformsTar);
}
// Create a copy of this physicsRigidConstraint, with the vertices overwritten
FCDPhysicsRigidConstraint* FCDPhysicsRigidConstraint::Clone()
{
FCDPhysicsRigidConstraint* clone = new FCDPhysicsRigidConstraint(GetDocument(), parent);
clone->enabled = enabled;
clone->interpenetrate = interpenetrate;
clone->referenceRigidBody = referenceRigidBody;
clone->targetRigidBody = targetRigidBody;
clone->limitsLinearMax = limitsLinearMax;
clone->limitsLinearMin = limitsLinearMin;
clone->limitsSCTMax = limitsSCTMax;
clone->limitsSCTMin = limitsSCTMin;
clone->springAngularDamping = springAngularDamping;
clone->springAngularStiffness = springAngularStiffness;
clone->springAngularTargetValue = springAngularTargetValue;
clone->springLinearDamping = springLinearDamping;
clone->springLinearStiffness = springLinearStiffness;
clone->springLinearTargetValue = springLinearTargetValue;
return clone;
}
// Load from a XML node the given physicsRigidConstraint
FUStatus FCDPhysicsRigidConstraint::LoadFromXML(xmlNode* physicsRigidConstraintNode)
{
FUStatus status = FCDEntity::LoadFromXML(physicsRigidConstraintNode);
if (!status) return status;
if (!IsEquivalent(physicsRigidConstraintNode->name, DAE_RIGID_CONSTRAINT_ELEMENT))
{
return status.Warning(FS("PhysicsRigidConstraint library contains unknown element."), physicsRigidConstraintNode->line);
}
sid = FUDaeParser::ReadNodeSid(physicsRigidConstraintNode);
#define PARSE_TRANSFORM(node, className, nodeName, vector) { \
xmlNodeList transformNodes; \
FindChildrenByType(node, nodeName, transformNodes); \
for(xmlNodeList::iterator itT = transformNodes.begin(); itT != transformNodes.end(); ++itT) { \
if (IsEquivalent((*itT)->name, nodeName)) { \
className* transform = new className(GetDocument(), NULL); \
vector.push_back(transform); \
status = transform->LoadFromXML(*itT); \
if (!status) { \
status.Warning(fstring(FC("Invalid <") FC(nodeName) FC("> transform in node: ")) + TO_FSTRING(GetDaeId()), (*itT)->line);} \
} \
} }
//Reference-frame body
xmlNode* referenceBodyNode = FindChildByType(physicsRigidConstraintNode, DAE_REF_ATTACHMENT_ELEMENT);
if (referenceBodyNode == NULL)
{
return status.Fail(FS("Reference-frame rigid body not defined in rigid constraint:") + TO_FSTRING(GetDaeId()), physicsRigidConstraintNode->line);
}
string strRigidBody = ReadNodeProperty(referenceBodyNode, DAE_RIGID_BODY_ELEMENT);
referenceRigidBody = parent->FindRigidBodyFromSid(strRigidBody);
if (referenceRigidBody == NULL)
{
return status.Fail(FS("Reference-frame rigid body specified in rigid_constraint ") + TO_FSTRING(GetDaeId()) + FS(" not found in physics model"), referenceBodyNode->line);
}
// Parse the node's transforms: <rotate>, <translate>
PARSE_TRANSFORM(referenceBodyNode, FCDTRotation, DAE_ROTATE_ELEMENT, transformsRef)
PARSE_TRANSFORM(referenceBodyNode, FCDTTranslation, DAE_TRANSLATE_ELEMENT, transformsRef)
// target body
xmlNode* bodyNode = FindChildByType(physicsRigidConstraintNode, DAE_ATTACHMENT_ELEMENT);
if (bodyNode == NULL)
{
return status.Fail(FS("Target rigid body not defined in rigid constraint") + TO_FSTRING(GetDaeId()), physicsRigidConstraintNode->line);
}
strRigidBody = ReadNodeProperty(bodyNode, DAE_RIGID_BODY_ELEMENT);
targetRigidBody = parent->FindRigidBodyFromSid(strRigidBody);
if (targetRigidBody == NULL)
{
return status.Fail(FS("Target rigid body specified in rigid_constraint ") + TO_FSTRING(GetDaeId()) + FS(" not found in physics model"), bodyNode->line);
}
// Parse the node's transforms: <rotate>, <scale>, <translate>
PARSE_TRANSFORM(bodyNode, FCDTRotation, DAE_ROTATE_ELEMENT, transformsTar)
PARSE_TRANSFORM(bodyNode, FCDTTranslation, DAE_TRANSLATE_ELEMENT, transformsTar)
#undef PARSE_TRANSFORM
//technique_common
xmlNode* techniqueNode = FindChildByType(physicsRigidConstraintNode, DAE_TECHNIQUE_COMMON_ELEMENT);
if (techniqueNode == NULL)
{
return status.Fail(FS("Technique node not specified in rigid_constraint ") + TO_FSTRING(GetDaeId()), physicsRigidConstraintNode->line);
}
xmlNode* enabledNode = FindChildByType(techniqueNode, DAE_ENABLED_ELEMENT);
if (enabledNode != NULL)
{
enabled = FUStringConversion::ToBoolean(ReadNodeContentDirect(enabledNode));
}
xmlNode* interpenetrateNode = FindChildByType(techniqueNode, DAE_INTERPENETRATE_ELEMENT);
if (interpenetrateNode != NULL)
{
interpenetrate = FUStringConversion::ToBoolean(ReadNodeContentDirect(interpenetrateNode));
}
xmlNode* limitsNode = FindChildByType(techniqueNode, DAE_LIMITS_ELEMENT);
if (limitsNode != NULL)
{
xmlNode* linearNode = FindChildByType(limitsNode, DAE_LINEAR_ELEMENT);
if (linearNode != NULL)
{
xmlNode* linearMinNode = FindChildByType(linearNode, DAE_MIN_ELEMENT);
if (linearMinNode != NULL)
{
const char* min = ReadNodeContentDirect(linearMinNode);
limitsLinearMin.x = FUStringConversion::ToFloat(&min);
limitsLinearMin.y = FUStringConversion::ToFloat(&min);
limitsLinearMin.z = FUStringConversion::ToFloat(&min);
}
xmlNode* linearMaxNode = FindChildByType(linearNode, DAE_MAX_ELEMENT);
if (linearMaxNode != NULL)
{
const char* max = ReadNodeContentDirect(linearMaxNode);
limitsLinearMax.x = FUStringConversion::ToFloat(&max);
limitsLinearMax.y = FUStringConversion::ToFloat(&max);
limitsLinearMax.z = FUStringConversion::ToFloat(&max);
}
}
xmlNode* sctNode = FindChildByType(limitsNode, DAE_SWING_CONE_AND_TWIST_ELEMENT);
if (sctNode != NULL)
{
xmlNode* sctMinNode = FindChildByType(sctNode, DAE_MIN_ELEMENT);
if (sctMinNode != NULL)
{
const char* min = ReadNodeContentDirect(sctMinNode);
limitsSCTMin.x = FUStringConversion::ToFloat(&min);
limitsSCTMin.y = FUStringConversion::ToFloat(&min);
limitsSCTMin.z = FUStringConversion::ToFloat(&min);
}
xmlNode* sctMaxNode = FindChildByType(sctNode, DAE_MAX_ELEMENT);
if (sctMaxNode != NULL)
{
const char* max = ReadNodeContentDirect(sctMaxNode);
limitsSCTMax.x = FUStringConversion::ToFloat(&max);
limitsSCTMax.y = FUStringConversion::ToFloat(&max);
limitsSCTMax.z = FUStringConversion::ToFloat(&max);
}
}
}
xmlNode* spring = FindChildByType(physicsRigidConstraintNode, DAE_SPRING_ELEMENT);
if(spring)
{
xmlNode* linearSpring = FindChildByType(spring, DAE_LINEAR_ELEMENT);
if(linearSpring)
{
xmlNode* param = FindChildByType(linearSpring, DAE_DAMPING_ELEMENT);
if(param) springLinearDamping = FUStringConversion::ToFloat(ReadNodeContentDirect(param));
param = FindChildByType(linearSpring, DAE_STIFFNESS_ELEMENT);
if(param) springLinearStiffness = FUStringConversion::ToFloat(ReadNodeContentDirect(param));
param = FindChildByType(linearSpring, DAE_TARGET_VALUE_ELEMENT);
if(param) springLinearTargetValue = FUStringConversion::ToFloat(ReadNodeContentDirect(param));
}
xmlNode* angularSpring = FindChildByType(spring, DAE_ANGULAR_ELEMENT);
if(angularSpring)
{
xmlNode* param = FindChildByType(angularSpring, DAE_DAMPING_ELEMENT);
if(param) springAngularDamping = FUStringConversion::ToFloat(ReadNodeContentDirect(param));
param = FindChildByType(angularSpring, DAE_STIFFNESS_ELEMENT);
if(param) springAngularStiffness = FUStringConversion::ToFloat(ReadNodeContentDirect(param));
param = FindChildByType(angularSpring, DAE_TARGET_VALUE_ELEMENT);
if(param) springAngularTargetValue = FUStringConversion::ToFloat(ReadNodeContentDirect(param));
}
}
return status;
}
// Write out the <physicsRigidConstraint> node
xmlNode* FCDPhysicsRigidConstraint::WriteToXML(xmlNode* parentNode) const
{
xmlNode* physicsRigidConstraintNode = WriteToEntityXML(parentNode, DAE_RIGID_CONSTRAINT_ELEMENT);
xmlNode* refNode = AddChild(physicsRigidConstraintNode, DAE_REF_ATTACHMENT_ELEMENT);
AddAttribute(refNode, DAE_RIGID_BODY_ELEMENT, referenceRigidBody->GetDaeId());
for (FCDTransformList::const_iterator itT = transformsRef.begin(); itT != transformsRef.end(); ++itT)
{
(*itT)->WriteToXML(refNode);
}
xmlNode* tarNode = AddChild(physicsRigidConstraintNode, DAE_ATTACHMENT_ELEMENT);
AddAttribute(tarNode, DAE_RIGID_BODY_ELEMENT, referenceRigidBody->GetDaeId());
for (FCDTransformList::const_iterator itT = transformsTar.begin(); itT != transformsTar.end(); ++itT)
{
(*itT)->WriteToXML(tarNode);
}
xmlNode* baseNode = AddChild(physicsRigidConstraintNode, DAE_TECHNIQUE_COMMON_ELEMENT);
AddChild(baseNode, DAE_ENABLED_ELEMENT, enabled);
AddChild(baseNode, DAE_INTERPENETRATE_ELEMENT, interpenetrate);
xmlNode* limitsNode = AddChild(baseNode, DAE_LIMITS_ELEMENT);
xmlNode* linearNode = AddChild(limitsNode, DAE_LINEAR_ELEMENT);
string s = FUStringConversion::ToString(limitsLinearMin);
AddChild(linearNode, DAE_MIN_ELEMENT, s);
s = FUStringConversion::ToString(limitsLinearMax);
AddChild(linearNode, DAE_MAX_ELEMENT, s);
xmlNode* sctNode = AddChild(limitsNode, DAE_SWING_CONE_AND_TWIST_ELEMENT);
s = FUStringConversion::ToString(limitsSCTMin);
AddChild(sctNode, DAE_MIN_ELEMENT, s);
s = FUStringConversion::ToString(limitsSCTMax);
AddChild(sctNode, DAE_MAX_ELEMENT, s);
xmlNode* springNode = AddChild(baseNode, DAE_SPRING_ELEMENT);
xmlNode* sLinearNode = AddChild(springNode, DAE_LINEAR_ELEMENT);
AddChild(sLinearNode, DAE_STIFFNESS_ELEMENT, springLinearStiffness);
AddChild(sLinearNode, DAE_DAMPING_ELEMENT, springLinearDamping);
AddChild(sLinearNode, DAE_TARGET_VALUE_ELEMENT, springLinearTargetValue);
xmlNode* sAngularNode = AddChild(springNode, DAE_ANGULAR_ELEMENT);
AddChild(sAngularNode, DAE_STIFFNESS_ELEMENT, springAngularStiffness);
AddChild(sAngularNode, DAE_DAMPING_ELEMENT, springAngularDamping);
AddChild(sAngularNode, DAE_TARGET_VALUE_ELEMENT, springAngularTargetValue);
//FIXME: what about <technique> and <extra>?
FCDEntity::WriteToExtraXML(physicsRigidConstraintNode);
return physicsRigidConstraintNode;
}

View File

@@ -0,0 +1,85 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#ifndef _FCD_PHYSICS_RIGID_CONSTRAINT_H_
#define _FCD_PHYSICS_RIGID_CONSTRAINT_H_
#include "FCDocument/FCDEntity.h"
#include "FCDocument/FCDEntityInstance.h"
#include "FCDocument/FCDTransform.h"
#include "FUtils/FUDaeEnum.h"
class FCDocument;
class FCDPhysicsModel;
class FCDPhysicsRigidBody;
typedef vector<FCDTransform*> FCDTransformList;
class FCOLLADA_EXPORT FCDPhysicsRigidConstraint : public FCDEntity
{
private:
string sid;
bool enabled;
bool interpenetrate;
FCDPhysicsRigidBody* referenceRigidBody;
FCDPhysicsRigidBody* targetRigidBody;
FMVector3 limitsLinearMin;
FMVector3 limitsLinearMax;
FMVector3 limitsSCTMin;
FMVector3 limitsSCTMax;
FCDPhysicsModel* parent;
float springLinearStiffness;
float springLinearDamping;
float springLinearTargetValue;
float springAngularStiffness;
float springAngularDamping;
float springAngularTargetValue;
FCDTransformList transformsRef;
FCDTransformList transformsTar;
public:
FCDPhysicsRigidConstraint(FCDocument* document, FCDPhysicsModel* _parent);
virtual ~FCDPhysicsRigidConstraint();
string GetSid() const { return sid; }
// Returns the entity type
virtual Type GetType() const { return PHYSICS_RIGID_CONSTRAINT; }
const bool& GetEnabled() const { return enabled;}
const bool& GetInterpenetrate() const { return interpenetrate;}
FCDPhysicsRigidBody* GetReferenceRigidBody() const { return referenceRigidBody;}
FCDPhysicsRigidBody* GetTargetRigidBody() const { return targetRigidBody;}
const FCDTransformList& GetTransformsRef() const { return transformsRef; }
const FCDTransformList& GetTransformsTar() const { return transformsTar; }
FMVector3 GetLimitsLinearMin() const { return limitsLinearMin;}
FMVector3 GetLimitsLinearMax() const { return limitsLinearMax;}
FMVector3 GetLimitsSCTMin() const { return limitsSCTMin;}
FMVector3 GetLimitsSCTMax() const { return limitsSCTMax;}
float GetSpringLinearStiffness() const { return springLinearStiffness;}
float GetSpringLinearDamping() const { return springLinearDamping;}
float GetSpringLinearTargetValue() const { return springLinearTargetValue;}
float GetSpringAngularStiffness() const { return springAngularStiffness;}
float GetSpringAngularDamping() const { return springAngularDamping;}
float GetSpringAngularTargetValue() const { return springAngularTargetValue;}
// Create a copy of this physicsmodel, with the vertices overwritten
FCDPhysicsRigidConstraint* Clone();
// Read in the <physics_model> node of the COLLADA document
virtual FUStatus LoadFromXML(xmlNode* node);
// Write out the <physics_model> node to the COLLADA xml tree
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif // _FCD_PHYSICS_RIGID_CONSTRAINT_H_

View File

@@ -0,0 +1,69 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDocument.h"
#include "FCDocument/FCDEntity.h"
#include "FCDocument/FCDPhysicsModel.h"
#include "FCDocument/FCDPhysicsModelInstance.h"
#include "FCDocument/FCDPhysicsRigidConstraint.h"
#include "FCDocument/FCDPhysicsRigidConstraintInstance.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDPhysicsRigidConstraintInstance::FCDPhysicsRigidConstraintInstance(FCDocument* document, FCDEntity* _parent) : FCDEntityInstance(document, NULL)
{
if (_parent->GetType() == FCDEntity::PHYSICS_MODEL)
parent = (FCDPhysicsModel*)_parent;
rigidConstraint = NULL;
SetClassName("FCDPhysicsRigidConstraintInstance");
}
FCDPhysicsRigidConstraintInstance::~FCDPhysicsRigidConstraintInstance()
{
parent = NULL;
rigidConstraint = NULL;
}
// Load the geometry instance from the COLLADA document
FUStatus FCDPhysicsRigidConstraintInstance::LoadFromXML(xmlNode* instanceNode)
{
FUStatus status = FCDEntityInstance::LoadFromXML(instanceNode);
if (!status) return status;
// Check for the expected instantiation node type
if (!IsEquivalent(instanceNode->name, DAE_INSTANCE_RIGID_CONSTRAINT_ELEMENT))
{
return status.Fail(FS("Unknown element for instantiation of entity: ") + TO_FSTRING(entity->GetDaeId()), instanceNode->line);
}
if (parent == NULL)
{
return status.Fail(FS("No Physics Model parent for rigid constraint instantiation"), instanceNode->line);
}
string physicsRigidConstraintSid = ReadNodeProperty(instanceNode, DAE_CONSTRAINT_ATTRIBUTE);
entity = rigidConstraint = parent->FindRigidConstraintFromSid(physicsRigidConstraintSid);
if(!rigidConstraint)
{
return status.Fail(FS("Couldn't find rigid constraint for instantiation"), instanceNode->line);
}
return status;
}
// Write out the instantiation information to the xml node tree
xmlNode* FCDPhysicsRigidConstraintInstance::WriteToXML(xmlNode* parentNode) const
{
xmlNode* instanceNode = FCDEntityInstance::WriteToXML(parentNode);
//TODO
return instanceNode;
}

View File

@@ -0,0 +1,39 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#ifndef _FCD_PHYSICS_RIGID_CONSTRAINT_INSTANCE_H_
#define _FCD_PHYSICS_RIGID_CONSTRAINT_INSTANCE_H_
#include "FCDocument/FCDEntityInstance.h"
class FCDocument;
class FCDSceneNode;
class FCDPhysicsModel;
class FCDPhysicsRigidConstraint;
class FCOLLADA_EXPORT FCDPhysicsRigidConstraintInstance : public FCDEntityInstance
{
private:
FCDPhysicsModel* parent;
FCDPhysicsRigidConstraint* rigidConstraint;
public:
FCDPhysicsRigidConstraintInstance(FCDocument* document, FCDEntity* _parent);
virtual ~FCDPhysicsRigidConstraintInstance();
// FCDEntity override for RTTI-like
virtual Type GetType() const { return PHYSICS_RIGID_CONSTRAINT; }
// Load the geometry instance from the COLLADA document
virtual FUStatus LoadFromXML(xmlNode* instanceNode);
// Write out the instantiation information to the xml node tree
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif // _FCD_PHYSICS_RIGID_CONSTRAINT_INSTANCE_H_

View File

@@ -0,0 +1,112 @@
/*
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/FCDPhysicsSceneNode.h"
#include "FCDocument/FCDPhysicsModelInstance.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
#include "FUtils/FUFileManager.h"
#include "FUtils/FUStringConversion.h"
#include "FCDocument/FCDExtra.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDPhysicsSceneNode::FCDPhysicsSceneNode(FCDocument* document) : FCDEntity(document, "PhysicsSceneNode")
{
//FIXME: no default values are specified in the 1.4 spec!
gravity.x = 0.f; gravity.y = -9.8f; gravity.z = 0.f;
timestep = 1.f;
}
FCDPhysicsSceneNode::~FCDPhysicsSceneNode()
{
CLEAR_POINTER_VECTOR(instances);
}
// Parse a <scene> or a <node> node from a COLLADA document
FUStatus FCDPhysicsSceneNode::LoadFromXML(xmlNode* sceneNode)
{
FUStatus status = FCDEntity::LoadFromXML(sceneNode);
if (!status) return status;
if(IsEquivalent(sceneNode->name, DAE_PHYSICS_SCENE_ELEMENT))
{
for (xmlNode* child = sceneNode->children; child != NULL; child = child->next)
{
if (child->type != XML_ELEMENT_NODE) continue;
// Look for instantiation elements
if (IsEquivalent(child->name, DAE_INSTANCE_PHYSICS_MODEL_ELEMENT))
{
FUUri url = ReadNodeUrl(child);
if (url.prefix.empty())
{
FCDPhysicsModel* entity = GetDocument()->FindPhysicsModel(url.suffix);
if (entity != NULL)
{
FCDPhysicsModelInstance* instance = new FCDPhysicsModelInstance(GetDocument(), (FCDEntity*)entity);
instances.push_back(instance);
status.AppendStatus(instance->LoadFromXML(child));
continue;
}
}
status.Warning(FS("Unable to retrieve FCDPhysicsModel instance for scene node: ") + TO_FSTRING(GetDaeId()), child->line);
}
else if(IsEquivalent(child->name, DAE_TECHNIQUE_COMMON_ELEMENT))
{
xmlNode* gravityNode = FindChildByType(child, DAE_GRAVITY_ATTRIBUTE);
if(gravityNode)
{
const char* gravityVal = ReadNodeContentDirect(gravityNode);
gravity.x = FUStringConversion::ToFloat(&gravityVal);
gravity.y = FUStringConversion::ToFloat(&gravityVal);
gravity.z = FUStringConversion::ToFloat(&gravityVal);
}
xmlNode* timestepNode = FindChildByType(child, DAE_TIME_STEP_ATTRIBUTE);
if(timestepNode)
{
timestep = FUStringConversion::ToFloat(ReadNodeContentDirect(timestepNode));
}
}
else if (IsEquivalent(child->name, DAE_EXTRA_ELEMENT))
{
// The extra information is loaded by the FCDEntity class.
}
}
}
return status;
}
// Write out a <physics_scene> element to a COLLADA xml document
xmlNode* FCDPhysicsSceneNode::WriteToXML(xmlNode* parentNode) const
{
xmlNode* physicsSceneNode = WriteToEntityXML(parentNode, DAE_PHYSICS_SCENE_ELEMENT);
if (physicsSceneNode == NULL) return physicsSceneNode;
WriteToNodeXML(physicsSceneNode);
return physicsSceneNode;
}
// Write out a <physics_scene> element to a COLLADA xml document
void FCDPhysicsSceneNode::WriteToNodeXML(xmlNode* node) const
{
// Write out the instantiation
for (FCDPhysicsModelInstanceList::const_iterator itI = instances.begin(); itI != instances.end(); ++itI)
{
FCDEntityInstance* instance = (*itI);
instance->WriteToXML(node);
}
// Write out the extra information
FCDEntity::WriteToExtraXML(node);
}

View File

@@ -0,0 +1,59 @@
/*
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
*/
#ifndef _FCD_PHYSICS_SCENE_NODE_
#define _FCD_PHYSICS_SCENE_NODE_
#include "FCDocument/FCDEntity.h"
class FCDocument;
class FCDEntityInstance;
class FCDExtra;
class FCDPhysicsModelInstance;
typedef vector<FCDPhysicsModelInstance*> FCDPhysicsModelInstanceList;
class FCOLLADA_EXPORT FCDPhysicsSceneNode : public FCDEntity
{
private:
FCDExtra* extra;
FMVector3 gravity;
float timestep;
FCDPhysicsModelInstanceList instances;
public:
FCDPhysicsSceneNode(FCDocument* document);
virtual ~FCDPhysicsSceneNode();
// Returns the entity type
virtual Type GetType() const { return PHYSICS_SCENE_NODE; }
FCDPhysicsModelInstanceList& GetInstances() { return instances; }
const FCDPhysicsModelInstanceList& GetInstances() const { return instances; }
size_t GetNumInstances() const { return instances.size(); };
// Visibility parameter
const FMVector3& GetGravity() const { return gravity; }
const float& GetTimestep() const { return timestep; }
// Parse a <physics_scene> node from a COLLADA document
virtual FUStatus LoadFromXML(xmlNode* sceneNode);
// Write out a <physics_scene> element to a COLLADA xml document
void WriteToNodeXML(xmlNode* node) const;
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
// Instantiating a scene node means ensuring that there is no cycles in the scene graph
void Instantiate(FCDPhysicsSceneNode* sceneNode);
};
#endif // _FCD_SCENE_NODE_

View File

@@ -0,0 +1,194 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDPhysicsShape.h"
#include "FCDocument/FCDocument.h"
#include "FCDocument/FCDTransform.h"
#include "FCDocument/FCDGeometryInstance.h"
#include "FCDocument/FCDPhysicsRigidBody.h"
#include "FCDocument/FCDPhysicsMaterial.h"
#include "FCDocument/FCDPhysicsAnalyticalGeometry.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDPhysicsShape::FCDPhysicsShape(FCDocument* document) : FCDEntity(document, "PhysicsShape")
{
hollow= true;
physicsMaterial = NULL;
ownsPhysicsMaterial = true;
ownsGeometryInstance = true;
geometry = NULL;
analGeom = NULL;
mass = 1.0f; //FIXME: should be derived from density x shape volume
density = 1.0f;
}
FCDPhysicsShape::~FCDPhysicsShape()
{
if(ownsPhysicsMaterial)
{
SAFE_DELETE(physicsMaterial);
}
else
{
physicsMaterial = NULL;
}
if(ownsGeometryInstance)
{
SAFE_DELETE(geometry);
}
else
{
geometry = NULL;
}
SAFE_DELETE(analGeom);
CLEAR_POINTER_VECTOR(transforms);
}
// Create a copy of this shape
// Note: geometries are just shallow-copied
FCDPhysicsShape* FCDPhysicsShape::Clone()
{
FCDPhysicsShape* clone = new FCDPhysicsShape(GetDocument());
FCDEntity::Clone(clone);
clone->SetMass(mass);
clone->SetDensity(density);
if(analGeom)
clone->SetAnalyticalGeometry(analGeom->Clone());
else
clone->SetAnalyticalGeometry(NULL);
clone->SetGeometryInstance(geometry); //FIXME: should do Clone?!
clone->SetGeometryInstanceOwnership(false);
if(physicsMaterial)
clone->SetPhysicsMaterial(physicsMaterial->Clone());
else
clone->SetPhysicsMaterial(NULL);
clone->SetOwnsPhysicsMaterial(true);
clone->SetHollow(hollow);
for(size_t i = 0; i < transforms.size(); ++i)
{
clone->AddTransform(transforms[i]->Clone(NULL));
}
return clone;
}
// Load from a XML node the given physicsShape
FUStatus FCDPhysicsShape::LoadFromXML(xmlNode* physicsShapeNode)
{
FUStatus status;
if (!IsEquivalent(physicsShapeNode->name, DAE_SHAPE_ELEMENT))
{
return status.Warning(FS("PhysicsShape library contains unknown element."), physicsShapeNode->line);
}
// Read in the first valid child element found
for (xmlNode* child = physicsShapeNode->children; child != NULL; child = child->next)
{
if (child->type != XML_ELEMENT_NODE) continue;
if(IsEquivalent(child->name, DAE_HOLLOW_ELEMENT))
{
hollow = FUStringConversion::ToBoolean(ReadNodeContentDirect(child));
}
else if(IsEquivalent(child->name, DAE_MASS_ELEMENT))
{
mass = FUStringConversion::ToFloat(ReadNodeContentDirect(child));
}
else if(IsEquivalent(child->name, DAE_DENSITY_ELEMENT))
{
density = FUStringConversion::ToFloat(ReadNodeContentDirect(child));
}
else if(IsEquivalent(child->name, DAE_PHYSICS_MATERIAL_ELEMENT))
{
if(!HasNodeProperty(child, DAE_URL_ATTRIBUTE))
{
//inline definition of physics_material
physicsMaterial = new FCDPhysicsMaterial(GetDocument());
physicsMaterial->LoadFromXML(child);
ownsPhysicsMaterial = true;
}
else
{
FUUri url = ReadNodeUrl(child);
if (url.prefix.empty())
{
physicsMaterial = GetDocument()->FindPhysicsMaterial(url.suffix);
ownsPhysicsMaterial = false;
}
}
}
else if(IsEquivalent(child->name, DAE_INSTANCE_GEOMETRY_ELEMENT))
{
FUUri url = ReadNodeUrl(child);
if (url.prefix.empty())
{
FCDGeometry* entity = GetDocument()->FindGeometry(url.suffix);
if (entity != NULL)
{
geometry = new FCDGeometryInstance(GetDocument(), (FCDEntity*)entity);
if(analGeom) SAFE_DELETE(analGeom);
status.AppendStatus(geometry->LoadFromXML(child));
continue;
}
}
status.Warning(FS("Unable to retrieve FCDGeometry instance for scene node: ") + TO_FSTRING(GetDaeId()), child->line);
}
#define PARSE_ANALYTICAL_SHAPE(className, nodeName) \
else if (IsEquivalent(child->name, nodeName)) { \
if(analGeom) SAFE_DELETE(analGeom); \
analGeom = new className(GetDocument()); \
if(geometry) SAFE_DELETE(geometry); \
status = analGeom->LoadFromXML(child);}\
if (!status) { status.Warning(fstring(FC("Invalid <") FC(nodeName) FC("> shape in node: ")) + TO_FSTRING(GetDaeId()), child->line); break; }
PARSE_ANALYTICAL_SHAPE(FCDPASBox, DAE_BOX_ELEMENT)
PARSE_ANALYTICAL_SHAPE(FCDPASPlane, DAE_PLANE_ELEMENT)
PARSE_ANALYTICAL_SHAPE(FCDPASSphere, DAE_SPHERE_ELEMENT)
PARSE_ANALYTICAL_SHAPE(FCDPASCylinder, DAE_CYLINDER_ELEMENT)
PARSE_ANALYTICAL_SHAPE(FCDPASCapsule, DAE_CAPSULE_ELEMENT)
PARSE_ANALYTICAL_SHAPE(FCDPASTaperedCapsule, DAE_TAPERED_CAPSULE_ELEMENT)
PARSE_ANALYTICAL_SHAPE(FCDPASTaperedCylinder, DAE_TAPERED_CYLINDER_ELEMENT)
#undef PARSE_ANALYTICAL_SHAPE
// Parse the physics shape transforms <rotate>, <scale>, <translate> are supported.
else if(IsEquivalent(child->name, DAE_ASSET_ELEMENT)) {}
else if(IsEquivalent(child->name, DAE_EXTRA_ELEMENT)) {}
else
{
FCDTransform* transform = FCDTFactory::CreateTransform(GetDocument(), NULL, child);
if (transform != NULL && (transform->GetType() != FCDTransform::TRANSLATION
|| transform->GetType() != FCDTransform::ROTATION || transform->GetType() != FCDTransform::SCALE))
{
SAFE_DELETE(transform);
}
else
{
transforms.push_back(transform);
status.AppendStatus(transform->LoadFromXML(child));
}
}
}
return status;
}
// Write out the <physicsShape> node
xmlNode* FCDPhysicsShape::WriteToXML(xmlNode* UNUSED(parentNode)) const
{
xmlNode* physicsShapeNode = NULL;
//TODO:
return physicsShapeNode;
}

View File

@@ -0,0 +1,76 @@
/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#ifndef _FCD_PHYSICS_SHAPE_H_
#define _FCD_PHYSICS_SHAPE_H_
#include "FCDocument/FCDEntity.h"
#include "FCDocument/FCDEntityInstance.h"
#include "FUtils/FUDaeEnum.h"
class FCDocument;
class FCDPhysicsRigidBody;
class FCDPhysicsRigidConstraint;
class FCDGeometryInstance;
class FCDPhysicsAnalyticalGeometry;
class FCDTransform;
typedef vector<FCDTransform*> FCDTransformList;
typedef vector<FCDPhysicsRigidBody*> FCDPhysicsRigidBodyList;
class FCOLLADA_EXPORT FCDPhysicsShape : public FCDEntity
{
private:
bool hollow;
FCDPhysicsMaterial* physicsMaterial;
bool ownsPhysicsMaterial;
//one of these two will define the rigid body
FCDGeometryInstance* geometry;
FCDPhysicsAnalyticalGeometry* analGeom; //pun not intended
bool ownsGeometryInstance;
float mass;
float density;
FCDTransformList transforms;
public:
FCDPhysicsShape(FCDocument* document);
virtual ~FCDPhysicsShape();
// Returns the entity type
virtual Type GetType() const { return PHYSICS_SHAPE; }
const float& GetMass() const {return mass;}
void SetMass(float _mass) {mass = _mass;}
const float& GetDensity() const {return density;}
void SetDensity(float _density) {density = _density;}
FCDPhysicsAnalyticalGeometry* GetAnalyticalGeometry() const {return analGeom;}
void SetAnalyticalGeometry(FCDPhysicsAnalyticalGeometry* _analGeom) {analGeom = _analGeom;}
FCDGeometryInstance* GetGeometryInstance() const {return geometry;}
void SetGeometryInstance(FCDGeometryInstance* _geometry) {geometry = _geometry;}
void SetGeometryInstanceOwnership(bool val) {ownsGeometryInstance = val;}
FCDPhysicsMaterial* GetPhysicsMaterial() const {return physicsMaterial;}
void SetPhysicsMaterial(FCDPhysicsMaterial* _physicsMaterial) {physicsMaterial = _physicsMaterial;}
bool ownsItsPhysicsMaterial() const {return ownsPhysicsMaterial;}
void SetOwnsPhysicsMaterial(bool _ownsPhysicsMaterial) {ownsPhysicsMaterial = _ownsPhysicsMaterial;}
bool isHollow() const {return hollow;}
void SetHollow(bool _hollow) {hollow = _hollow;}
const FCDTransformList& GetTransforms() const {return transforms;}
void AddTransform(FCDTransform* t) {transforms.push_back(t);}
// Create a copy of this shape
FCDPhysicsShape* Clone();
// Read in the <physics_shape> node of the COLLADA document
virtual FUStatus LoadFromXML(xmlNode* node);
// Write out the <physics_shape> node to the COLLADA xml tree
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
};
#endif // _FCD_PHYSICS_SHAPE_H_

Some files were not shown because too many files have changed in this diff Show More