Files
bullet3/Extras/FCollada/FCDocument/FCDExtra.cpp
2006-05-25 19:18:29 +00:00

367 lines
9.7 KiB
C++

/*
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;
}