moved files around
This commit is contained in:
544
Extras/FCollada/FCDocument/FCDAnimated.cpp
Normal file
544
Extras/FCollada/FCDocument/FCDAnimated.cpp
Normal 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;
|
||||
}
|
||||
488
Extras/FCollada/FCDocument/FCDAnimated.h
Normal file
488
Extras/FCollada/FCDocument/FCDAnimated.h
Normal 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_
|
||||
|
||||
224
Extras/FCollada/FCDocument/FCDAnimation.cpp
Normal file
224
Extras/FCollada/FCDocument/FCDAnimation.cpp
Normal 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;
|
||||
}
|
||||
163
Extras/FCollada/FCDocument/FCDAnimation.h
Normal file
163
Extras/FCollada/FCDocument/FCDAnimation.h
Normal 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_
|
||||
292
Extras/FCollada/FCDocument/FCDAnimationChannel.cpp
Normal file
292
Extras/FCollada/FCDocument/FCDAnimationChannel.cpp
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
134
Extras/FCollada/FCDocument/FCDAnimationChannel.h
Normal file
134
Extras/FCollada/FCDocument/FCDAnimationChannel.h
Normal 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_
|
||||
139
Extras/FCollada/FCDocument/FCDAnimationClip.cpp
Normal file
139
Extras/FCollada/FCDocument/FCDAnimationClip.cpp
Normal 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;
|
||||
}
|
||||
|
||||
46
Extras/FCollada/FCDocument/FCDAnimationClip.h
Normal file
46
Extras/FCollada/FCDocument/FCDAnimationClip.h
Normal 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_
|
||||
|
||||
295
Extras/FCollada/FCDocument/FCDAnimationCurve.cpp
Normal file
295
Extras/FCollada/FCDocument/FCDAnimationCurve.cpp
Normal 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;
|
||||
}
|
||||
262
Extras/FCollada/FCDocument/FCDAnimationCurve.h
Normal file
262
Extras/FCollada/FCDocument/FCDAnimationCurve.h
Normal 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_
|
||||
378
Extras/FCollada/FCDocument/FCDAnimationMultiCurve.cpp
Normal file
378
Extras/FCollada/FCDocument/FCDAnimationMultiCurve.cpp
Normal 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;
|
||||
}
|
||||
179
Extras/FCollada/FCDocument/FCDAnimationMultiCurve.h
Normal file
179
Extras/FCollada/FCDocument/FCDAnimationMultiCurve.h
Normal 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_
|
||||
207
Extras/FCollada/FCDocument/FCDAsset.cpp
Normal file
207
Extras/FCollada/FCDocument/FCDAsset.cpp
Normal 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;
|
||||
}
|
||||
109
Extras/FCollada/FCDocument/FCDAsset.h
Normal file
109
Extras/FCollada/FCDocument/FCDAsset.h
Normal 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_
|
||||
268
Extras/FCollada/FCDocument/FCDCamera.cpp
Normal file
268
Extras/FCollada/FCDocument/FCDCamera.cpp
Normal 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;
|
||||
}
|
||||
255
Extras/FCollada/FCDocument/FCDCamera.h
Normal file
255
Extras/FCollada/FCDocument/FCDCamera.h
Normal 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_
|
||||
|
||||
123
Extras/FCollada/FCDocument/FCDController.cpp
Normal file
123
Extras/FCollada/FCDocument/FCDController.cpp
Normal 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;
|
||||
}
|
||||
124
Extras/FCollada/FCDocument/FCDController.h
Normal file
124
Extras/FCollada/FCDocument/FCDController.h
Normal 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_
|
||||
|
||||
268
Extras/FCollada/FCDocument/FCDEffect.cpp
Normal file
268
Extras/FCollada/FCDocument/FCDEffect.cpp
Normal 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;
|
||||
}
|
||||
179
Extras/FCollada/FCDocument/FCDEffect.h
Normal file
179
Extras/FCollada/FCDocument/FCDEffect.h
Normal 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_
|
||||
88
Extras/FCollada/FCDocument/FCDEffectCode.cpp
Normal file
88
Extras/FCollada/FCDocument/FCDEffectCode.cpp
Normal 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;
|
||||
}
|
||||
118
Extras/FCollada/FCDocument/FCDEffectCode.h
Normal file
118
Extras/FCollada/FCDocument/FCDEffectCode.h
Normal 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_
|
||||
646
Extras/FCollada/FCDocument/FCDEffectParameter.cpp
Normal file
646
Extras/FCollada/FCDocument/FCDEffectParameter.cpp
Normal 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;
|
||||
}
|
||||
844
Extras/FCollada/FCDocument/FCDEffectParameter.h
Normal file
844
Extras/FCollada/FCDocument/FCDEffectParameter.h
Normal 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_
|
||||
|
||||
70
Extras/FCollada/FCDocument/FCDEffectParameterFactory.cpp
Normal file
70
Extras/FCollada/FCDocument/FCDEffectParameterFactory.cpp
Normal 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;
|
||||
}
|
||||
47
Extras/FCollada/FCDocument/FCDEffectParameterFactory.h
Normal file
47
Extras/FCollada/FCDocument/FCDEffectParameterFactory.h
Normal 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_
|
||||
124
Extras/FCollada/FCDocument/FCDEffectParameterList.cpp
Normal file
124
Extras/FCollada/FCDocument/FCDEffectParameterList.cpp
Normal 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;
|
||||
}
|
||||
93
Extras/FCollada/FCDocument/FCDEffectParameterList.h
Normal file
93
Extras/FCollada/FCDocument/FCDEffectParameterList.h
Normal 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_
|
||||
589
Extras/FCollada/FCDocument/FCDEffectParameterSurface.cpp
Normal file
589
Extras/FCollada/FCDocument/FCDEffectParameterSurface.cpp
Normal 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;
|
||||
}
|
||||
435
Extras/FCollada/FCDocument/FCDEffectParameterSurface.h
Normal file
435
Extras/FCollada/FCDocument/FCDEffectParameterSurface.h
Normal 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_
|
||||
194
Extras/FCollada/FCDocument/FCDEffectPass.cpp
Normal file
194
Extras/FCollada/FCDocument/FCDEffectPass.cpp
Normal 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;
|
||||
}
|
||||
140
Extras/FCollada/FCDocument/FCDEffectPass.h
Normal file
140
Extras/FCollada/FCDocument/FCDEffectPass.h
Normal 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
|
||||
148
Extras/FCollada/FCDocument/FCDEffectPassShader.cpp
Normal file
148
Extras/FCollada/FCDocument/FCDEffectPassShader.cpp
Normal 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;
|
||||
}
|
||||
169
Extras/FCollada/FCDocument/FCDEffectPassShader.h
Normal file
169
Extras/FCollada/FCDocument/FCDEffectPassShader.h
Normal 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_
|
||||
24
Extras/FCollada/FCDocument/FCDEffectProfile.cpp
Normal file
24
Extras/FCollada/FCDocument/FCDEffectProfile.cpp
Normal 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();
|
||||
}
|
||||
111
Extras/FCollada/FCDocument/FCDEffectProfile.h
Normal file
111
Extras/FCollada/FCDocument/FCDEffectProfile.h
Normal 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_
|
||||
282
Extras/FCollada/FCDocument/FCDEffectProfileFX.cpp
Normal file
282
Extras/FCollada/FCDocument/FCDEffectProfileFX.cpp
Normal 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;
|
||||
}
|
||||
219
Extras/FCollada/FCDocument/FCDEffectProfileFX.h
Normal file
219
Extras/FCollada/FCDocument/FCDEffectProfileFX.h
Normal 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_
|
||||
572
Extras/FCollada/FCDocument/FCDEffectStandard.cpp
Normal file
572
Extras/FCollada/FCDocument/FCDEffectStandard.cpp
Normal 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;
|
||||
}
|
||||
415
Extras/FCollada/FCDocument/FCDEffectStandard.h
Normal file
415
Extras/FCollada/FCDocument/FCDEffectStandard.h
Normal 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_
|
||||
|
||||
254
Extras/FCollada/FCDocument/FCDEffectTechnique.cpp
Normal file
254
Extras/FCollada/FCDocument/FCDEffectTechnique.cpp
Normal 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;
|
||||
}
|
||||
195
Extras/FCollada/FCDocument/FCDEffectTechnique.h
Normal file
195
Extras/FCollada/FCDocument/FCDEffectTechnique.h
Normal 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
|
||||
127
Extras/FCollada/FCDocument/FCDEntity.cpp
Normal file
127
Extras/FCollada/FCDocument/FCDEntity.cpp
Normal 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);
|
||||
}
|
||||
189
Extras/FCollada/FCDocument/FCDEntity.h
Normal file
189
Extras/FCollada/FCDocument/FCDEntity.h
Normal 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_
|
||||
|
||||
44
Extras/FCollada/FCDocument/FCDEntityInstance.h
Normal file
44
Extras/FCollada/FCDocument/FCDEntityInstance.h
Normal 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_
|
||||
37
Extras/FCollada/FCDocument/FCDExternalReference.h
Normal file
37
Extras/FCollada/FCDocument/FCDExternalReference.h
Normal 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_
|
||||
366
Extras/FCollada/FCDocument/FCDExtra.cpp
Normal file
366
Extras/FCollada/FCDocument/FCDExtra.cpp
Normal 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;
|
||||
}
|
||||
|
||||
357
Extras/FCollada/FCDocument/FCDExtra.h
Normal file
357
Extras/FCollada/FCDocument/FCDExtra.h
Normal 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_
|
||||
117
Extras/FCollada/FCDocument/FCDGeometry.cpp
Normal file
117
Extras/FCollada/FCDocument/FCDGeometry.cpp
Normal 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;
|
||||
}
|
||||
120
Extras/FCollada/FCDocument/FCDGeometry.h
Normal file
120
Extras/FCollada/FCDocument/FCDGeometry.h
Normal 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_
|
||||
168
Extras/FCollada/FCDocument/FCDGeometryInstance.cpp
Normal file
168
Extras/FCollada/FCDocument/FCDGeometryInstance.cpp
Normal 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;
|
||||
}
|
||||
46
Extras/FCollada/FCDocument/FCDGeometryInstance.h
Normal file
46
Extras/FCollada/FCDocument/FCDGeometryInstance.h
Normal 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_
|
||||
357
Extras/FCollada/FCDocument/FCDGeometryMesh.cpp
Normal file
357
Extras/FCollada/FCDocument/FCDGeometryMesh.cpp
Normal 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;
|
||||
}
|
||||
209
Extras/FCollada/FCDocument/FCDGeometryMesh.h
Normal file
209
Extras/FCollada/FCDocument/FCDGeometryMesh.h
Normal 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_
|
||||
811
Extras/FCollada/FCDocument/FCDGeometryPolygons.cpp
Normal file
811
Extras/FCollada/FCDocument/FCDGeometryPolygons.cpp
Normal 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;
|
||||
}
|
||||
340
Extras/FCollada/FCDocument/FCDGeometryPolygons.h
Normal file
340
Extras/FCollada/FCDocument/FCDGeometryPolygons.h
Normal 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_
|
||||
147
Extras/FCollada/FCDocument/FCDGeometrySource.cpp
Normal file
147
Extras/FCollada/FCDocument/FCDGeometrySource.cpp
Normal 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;
|
||||
}
|
||||
141
Extras/FCollada/FCDocument/FCDGeometrySource.h
Normal file
141
Extras/FCollada/FCDocument/FCDGeometrySource.h
Normal 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_
|
||||
163
Extras/FCollada/FCDocument/FCDGeometrySpline.cpp
Normal file
163
Extras/FCollada/FCDocument/FCDGeometrySpline.cpp
Normal 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;
|
||||
}
|
||||
122
Extras/FCollada/FCDocument/FCDGeometrySpline.h
Normal file
122
Extras/FCollada/FCDocument/FCDGeometrySpline.h
Normal 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_
|
||||
82
Extras/FCollada/FCDocument/FCDImage.cpp
Normal file
82
Extras/FCollada/FCDocument/FCDImage.cpp
Normal 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;
|
||||
}
|
||||
125
Extras/FCollada/FCDocument/FCDImage.h
Normal file
125
Extras/FCollada/FCDocument/FCDImage.h
Normal 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_
|
||||
112
Extras/FCollada/FCDocument/FCDLibrary.h
Normal file
112
Extras/FCollada/FCDocument/FCDLibrary.h
Normal 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_
|
||||
92
Extras/FCollada/FCDocument/FCDLibrary.hpp
Normal file
92
Extras/FCollada/FCDocument/FCDLibrary.hpp
Normal 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;
|
||||
}
|
||||
282
Extras/FCollada/FCDocument/FCDLight.cpp
Normal file
282
Extras/FCollada/FCDocument/FCDLight.cpp
Normal 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;
|
||||
}
|
||||
286
Extras/FCollada/FCDocument/FCDLight.h
Normal file
286
Extras/FCollada/FCDocument/FCDLight.h
Normal 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_
|
||||
|
||||
211
Extras/FCollada/FCDocument/FCDMaterial.cpp
Normal file
211
Extras/FCollada/FCDocument/FCDMaterial.cpp
Normal 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;
|
||||
}
|
||||
152
Extras/FCollada/FCDocument/FCDMaterial.h
Normal file
152
Extras/FCollada/FCDocument/FCDMaterial.h
Normal 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_
|
||||
158
Extras/FCollada/FCDocument/FCDMaterialInstance.cpp
Normal file
158
Extras/FCollada/FCDocument/FCDMaterialInstance.cpp
Normal 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;
|
||||
}
|
||||
61
Extras/FCollada/FCDocument/FCDMaterialInstance.h
Normal file
61
Extras/FCollada/FCDocument/FCDMaterialInstance.h
Normal 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_
|
||||
162
Extras/FCollada/FCDocument/FCDMaterialLibrary.cpp
Normal file
162
Extras/FCollada/FCDocument/FCDMaterialLibrary.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
138
Extras/FCollada/FCDocument/FCDMaterialLibrary.h
Normal file
138
Extras/FCollada/FCDocument/FCDMaterialLibrary.h
Normal 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_
|
||||
|
||||
355
Extras/FCollada/FCDocument/FCDMorphController.cpp
Normal file
355
Extras/FCollada/FCDocument/FCDMorphController.cpp
Normal 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);
|
||||
}
|
||||
202
Extras/FCollada/FCDocument/FCDMorphController.h
Normal file
202
Extras/FCollada/FCDocument/FCDMorphController.h
Normal 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_
|
||||
|
||||
93
Extras/FCollada/FCDocument/FCDObject.cpp
Normal file
93
Extras/FCollada/FCDocument/FCDObject.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
107
Extras/FCollada/FCDocument/FCDObject.h
Normal file
107
Extras/FCollada/FCDocument/FCDObject.h
Normal 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_
|
||||
369
Extras/FCollada/FCDocument/FCDPhysicsAnalyticalGeometry.cpp
Normal file
369
Extras/FCollada/FCDocument/FCDPhysicsAnalyticalGeometry.cpp
Normal 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;
|
||||
}
|
||||
152
Extras/FCollada/FCDocument/FCDPhysicsAnalyticalGeometry.h
Normal file
152
Extras/FCollada/FCDocument/FCDPhysicsAnalyticalGeometry.h
Normal 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_
|
||||
88
Extras/FCollada/FCDocument/FCDPhysicsMaterial.cpp
Normal file
88
Extras/FCollada/FCDocument/FCDPhysicsMaterial.cpp
Normal 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;
|
||||
}
|
||||
43
Extras/FCollada/FCDocument/FCDPhysicsMaterial.h
Normal file
43
Extras/FCollada/FCDocument/FCDPhysicsMaterial.h
Normal 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_
|
||||
134
Extras/FCollada/FCDocument/FCDPhysicsModel.cpp
Normal file
134
Extras/FCollada/FCDocument/FCDPhysicsModel.cpp
Normal 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;
|
||||
}
|
||||
52
Extras/FCollada/FCDocument/FCDPhysicsModel.h
Normal file
52
Extras/FCollada/FCDocument/FCDPhysicsModel.h
Normal 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_
|
||||
91
Extras/FCollada/FCDocument/FCDPhysicsModelInstance.cpp
Normal file
91
Extras/FCollada/FCDocument/FCDPhysicsModelInstance.cpp
Normal 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;
|
||||
}
|
||||
36
Extras/FCollada/FCDocument/FCDPhysicsModelInstance.h
Normal file
36
Extras/FCollada/FCDocument/FCDPhysicsModelInstance.h
Normal 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_
|
||||
45
Extras/FCollada/FCDocument/FCDPhysicsParameter.h
Normal file
45
Extras/FCollada/FCDocument/FCDPhysicsParameter.h
Normal 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_
|
||||
77
Extras/FCollada/FCDocument/FCDPhysicsParameter.hpp
Normal file
77
Extras/FCollada/FCDocument/FCDPhysicsParameter.hpp
Normal 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;
|
||||
}
|
||||
18
Extras/FCollada/FCDocument/FCDPhysicsParameterGeneric.cpp
Normal file
18
Extras/FCollada/FCDocument/FCDPhysicsParameterGeneric.cpp
Normal 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()
|
||||
{
|
||||
}
|
||||
|
||||
41
Extras/FCollada/FCDocument/FCDPhysicsParameterGeneric.h
Normal file
41
Extras/FCollada/FCDocument/FCDPhysicsParameterGeneric.h
Normal 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_
|
||||
253
Extras/FCollada/FCDocument/FCDPhysicsRigidBody.cpp
Normal file
253
Extras/FCollada/FCDocument/FCDPhysicsRigidBody.cpp
Normal 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;
|
||||
}
|
||||
64
Extras/FCollada/FCDocument/FCDPhysicsRigidBody.h
Normal file
64
Extras/FCollada/FCDocument/FCDPhysicsRigidBody.h
Normal 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_
|
||||
198
Extras/FCollada/FCDocument/FCDPhysicsRigidBodyInstance.cpp
Normal file
198
Extras/FCollada/FCDocument/FCDPhysicsRigidBodyInstance.cpp
Normal 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;
|
||||
}
|
||||
52
Extras/FCollada/FCDocument/FCDPhysicsRigidBodyInstance.h
Normal file
52
Extras/FCollada/FCDocument/FCDPhysicsRigidBodyInstance.h
Normal 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_
|
||||
273
Extras/FCollada/FCDocument/FCDPhysicsRigidConstraint.cpp
Normal file
273
Extras/FCollada/FCDocument/FCDPhysicsRigidConstraint.cpp
Normal 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;
|
||||
}
|
||||
85
Extras/FCollada/FCDocument/FCDPhysicsRigidConstraint.h
Normal file
85
Extras/FCollada/FCDocument/FCDPhysicsRigidConstraint.h
Normal 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_
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_
|
||||
112
Extras/FCollada/FCDocument/FCDPhysicsSceneNode.cpp
Normal file
112
Extras/FCollada/FCDocument/FCDPhysicsSceneNode.cpp
Normal 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);
|
||||
}
|
||||
59
Extras/FCollada/FCDocument/FCDPhysicsSceneNode.h
Normal file
59
Extras/FCollada/FCDocument/FCDPhysicsSceneNode.h
Normal 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_
|
||||
194
Extras/FCollada/FCDocument/FCDPhysicsShape.cpp
Normal file
194
Extras/FCollada/FCDocument/FCDPhysicsShape.cpp
Normal 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;
|
||||
}
|
||||
76
Extras/FCollada/FCDocument/FCDPhysicsShape.h
Normal file
76
Extras/FCollada/FCDocument/FCDPhysicsShape.h
Normal 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
Reference in New Issue
Block a user