1 /*
2 	Copyright (C) 2005-2007 Feeling Software Inc.
3 	Portions of the code are:
4 	Copyright (C) 2005-2007 Sony Computer Entertainment America
5 
6 	MIT License: http://www.opensource.org/licenses/mit-license.php
7 */
8 
9 #include "StdAfx.h"
10 #include "FCDocument/FCDocument.h"
11 #include "FCDocument/FCDAnimated.h"
12 #include "FCDocument/FCDExtra.h"
13 #include "FColladaPlugin.h"
14 
15 
16 namespace FCollada { extern FColladaPluginManager* pluginManager; }
17 
18 //
19 // FCDExtra
20 //
21 
22 ImplementObjectType(FCDExtra);
23 ImplementParameterObject(FCDExtra, FCDEType, types, new FCDEType(parent->GetDocument(), parent, emptyCharString));
24 
FCDExtra(FCDocument * document,FUObject * _parent)25 FCDExtra::FCDExtra(FCDocument* document, FUObject* _parent)
26 :	FCDObject(document)
27 ,	parent(_parent)
28 ,	InitializeParameterNoArg(types)
29 {
30 	// Create the default extra type.
31 	types.push_back(new FCDEType(document, this, emptyCharString));
32 	document->RegisterExtraTree(this);
33 }
34 
~FCDExtra()35 FCDExtra::~FCDExtra()
36 {
37 	GetDocument()->UnregisterExtraTree(this);
38 }
39 
40 // Adds a type of the given name (or return the existing type with this name).
AddType(const char * name)41 FCDEType* FCDExtra::AddType(const char* name)
42 {
43 	FCDEType* type = FindType(name);
44 	if (type == NULL)
45 	{
46 		type = new FCDEType(GetDocument(), this, emptyCharString);
47 		types.push_back(type);
48 		type->SetName(name);
49 		SetNewChildFlag();
50 	}
51 	return type;
52 }
53 
54 // Search for a profile-specific type
FindType(const char * name) const55 const FCDEType* FCDExtra::FindType(const char* name) const
56 {
57 	for (const FCDEType** itT = types.begin(); itT != types.end(); ++itT)
58 	{
59 		if (IsEquivalent((*itT)->GetName(), name)) return *itT;
60 	}
61 	return NULL;
62 }
63 
HasContent() const64 bool FCDExtra::HasContent() const
65 {
66 	if (types.empty()) return false;
67 	for (const FCDEType** itT = types.begin(); itT != types.end(); ++itT)
68 	{
69 		size_t techniqueCount = (*itT)->GetTechniqueCount();
70 		for (size_t i = 0; i < techniqueCount; ++i)
71 		{
72 			const FCDETechnique* technique = (*itT)->GetTechnique(i);
73 			if (technique->GetChildNodeCount() > 0) return true;
74 		}
75 	}
76 	return false;
77 }
78 
Clone(FCDExtra * clone) const79 FCDExtra* FCDExtra::Clone(FCDExtra* clone) const
80 {
81 	if (clone == NULL) clone = new FCDExtra(const_cast<FCDocument*>(GetDocument()), NULL);
82 
83 	// Create all the types
84 	clone->types.reserve(types.size());
85 	for (const FCDEType** itT = types.begin(); itT != types.end(); ++itT)
86 	{
87 		FCDEType* cloneT = clone->AddType((*itT)->GetName());
88 		(*itT)->Clone(cloneT);
89 	}
90 	return clone;
91 }
92 
93 //
94 // FCDEType
95 //
96 
97 ImplementObjectType(FCDEType);
98 ImplementParameterObject(FCDEType, FCDETechnique, techniques, new FCDETechnique(parent->GetDocument(), parent, emptyCharString));
99 
FCDEType(FCDocument * document,FCDExtra * _parent,const char * _name)100 FCDEType::FCDEType(FCDocument* document, FCDExtra* _parent, const char* _name)
101 :	FCDObject(document)
102 ,	parent(_parent)
103 ,	InitializeParameter(name, _name)
104 ,	InitializeParameterNoArg(techniques)
105 {
106 }
107 
~FCDEType()108 FCDEType::~FCDEType()
109 {
110 }
111 
112 // Adds a technique of the given profile (or return the existing technique with this profile).
AddTechnique(const char * profile)113 FCDETechnique* FCDEType::AddTechnique(const char* profile)
114 {
115 	FCDETechnique* technique = FindTechnique(profile);
116 	if (technique == NULL)
117 	{
118 		technique = new FCDETechnique(GetDocument(), this, profile);
119 		techniques.push_back(technique);
120 		SetNewChildFlag();
121 	}
122 	return technique;
123 }
124 
125 // Search for a profile-specific technique
FindTechnique(const char * profile) const126 const FCDETechnique* FCDEType::FindTechnique(const char* profile) const
127 {
128 	for (const FCDETechnique** itT = techniques.begin(); itT != techniques.end(); ++itT)
129 	{
130 		if (IsEquivalent((*itT)->GetProfile(), profile)) return *itT;
131 	}
132 	return NULL;
133 }
134 
135 // Search for a root node with a specific element name
FindRootNode(const char * name) const136 const FCDENode* FCDEType::FindRootNode(const char* name) const
137 {
138 	const FCDENode* rootNode = NULL;
139 	for (const FCDETechnique** itT = techniques.begin(); itT != techniques.end(); ++itT)
140 	{
141 		rootNode = (*itT)->FindChildNode(name);
142 		if (rootNode != NULL) break;
143 	}
144 	return rootNode;
145 }
146 
Clone(FCDEType * clone) const147 FCDEType* FCDEType::Clone(FCDEType* clone) const
148 {
149 	// If no clone is given: create one
150 	if (clone == NULL)
151 	{
152 		clone = new FCDEType(const_cast<FCDocument*>(GetDocument()), NULL, name->c_str());
153 	}
154 
155 	clone->techniques.reserve(techniques.size());
156 	for (const FCDETechnique** itT = techniques.begin(); itT != techniques.end(); ++itT)
157 	{
158 		FCDETechnique* cloneT = clone->AddTechnique((*itT)->GetProfile());
159 		(*itT)->Clone(cloneT);
160 	}
161 	return clone;
162 }
163 
164 //
165 // FCDENode
166 //
167 
168 ImplementObjectType(FCDENode);
169 ImplementParameterObject(FCDENode, FCDENode, children, new FCDENode(parent->GetDocument(), parent));
170 ImplementParameterObjectNoArg(FCDENode, FCDEAttribute, attributes);
171 ImplementParameterObject(FCDENode, FCDAnimatedCustom, animated, new FCDAnimatedCustom(parent->GetDocument()));
172 
FCDENode(FCDocument * document,FCDENode * _parent)173 FCDENode::FCDENode(FCDocument* document, FCDENode* _parent)
174 :	FCDObject(document), parent(_parent)
175 ,	InitializeParameterNoArg(name)
176 ,	InitializeParameterNoArg(content)
177 ,	InitializeParameterNoArg(children)
178 ,	InitializeParameterNoArg(attributes)
179 ,	InitializeParameterNoArg(animated)
180 {
181 	animated = new FCDAnimatedCustom(this);
182 }
183 
~FCDENode()184 FCDENode::~FCDENode()
185 {
186 	parent = NULL;
187 }
188 
SetContent(const fchar * _content)189 void FCDENode::SetContent(const fchar* _content)
190 {
191 	// As COLLADA doesn't allow for mixed content, release all the children.
192 	while (!children.empty())
193 	{
194 		children.back()->Release();
195 	}
196 
197 	content = _content;
198 	SetDirtyFlag();
199 }
200 
SetAnimated(FCDAnimatedCustom * animatedCustom)201 void FCDENode::SetAnimated(FCDAnimatedCustom* animatedCustom)
202 {
203 	SAFE_RELEASE(animated);
204 	animated = animatedCustom;
205 }
206 
207 // Search for a children with a specific name
FindChildNode(const char * name) const208 const FCDENode* FCDENode::FindChildNode(const char* name) const
209 {
210 	for (const FCDENode** itN = children.begin(); itN != children.end(); ++itN)
211 	{
212 		if (IsEquivalent((*itN)->GetName(), name)) return (*itN);
213 	}
214 	return NULL;
215 }
216 
FindChildrenNodes(const char * name,FCDENodeList & nodes) const217 void FCDENode::FindChildrenNodes(const char* name, FCDENodeList& nodes) const
218 {
219 	for (const FCDENode** itN = children.begin(); itN != children.end(); ++itN)
220 	{
221 		if (IsEquivalent((*itN)->GetName(), name)) nodes.push_back(const_cast<FCDENode*>(*itN));
222 	}
223 }
224 
FindParameter(const char * name) const225 const FCDENode* FCDENode::FindParameter(const char* name) const
226 {
227 	for (const FCDENode** itN = children.begin(); itN != children.end(); ++itN)
228 	{
229 		const FCDENode* node = (*itN);
230 		if (IsEquivalent(node->GetName(), name)) return node;
231 	}
232 	return NULL;
233 }
234 
FindParameters(FCDENodeList & nodes,StringList & names)235 void FCDENode::FindParameters(FCDENodeList& nodes, StringList& names)
236 {
237 	for (const FCDENode** itN = (const FCDENode**) children.begin(); itN != children.end(); ++itN)
238 	{
239 		const FCDENode* node = (*itN);
240 		if (node->GetChildNodeCount() == 0)
241 		{
242 			nodes.push_back(const_cast<FCDENode*>(node));
243 			names.push_back(node->GetName());
244 		}
245 	}
246 }
247 
SetName(fm::string & _name)248 void FCDENode::SetName(fm::string& _name)
249 {
250 	name = _name;
251 	CleanName(name);
252 	SetDirtyFlag();
253 }
254 
CleanName(fm::string & n)255 void FCDENode::CleanName(fm::string& n)
256 {
257 	size_t length = n.length();
258 	if (length == 0) return;
259 
260 	// First character must be alphabetic or the underscore.
261 	if (n[0] != '_' && !(n[0] >= 'a' && n[0] <= 'z') && !(n[0] >= 'A' && n[0] <= 'Z'))
262 	{
263 		n[0] = '_';
264 	}
265 
266 	// Other characters must be alpha-numeric or the underscore.
267 	for (size_t i = 1; i < length; ++i)
268 	{
269 		char& c = n[i];
270 		if (c != '_' && !(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') && !(c >= '0' && c <= '9'))
271 		{
272 			c = '_';
273 		}
274 	}
275 }
276 
GetContent() const277 const fchar* FCDENode::GetContent() const
278 {
279 	return content->c_str();
280 }
281 
282 // Adds a new attribute to this extra tree node.
AddAttribute(fm::string & _name,const fchar * _value)283 FCDEAttribute* FCDENode::AddAttribute(fm::string& _name, const fchar* _value)
284 {
285 	CleanName(_name);
286 	FCDEAttribute* attribute = FindAttribute(_name.c_str());
287 	if (attribute == NULL)
288 	{
289 		attribute = new FCDEAttribute();
290 		attributes.push_back(attribute);
291 		attribute->SetName(_name);
292 	}
293 
294 	attribute->SetValue(_value);
295 	SetNewChildFlag();
296 	return attribute;
297 }
298 
299 // Search for an attribute with a specific name
FindAttribute(const char * name) const300 const FCDEAttribute* FCDENode::FindAttribute(const char* name) const
301 {
302 	for (const FCDEAttribute** itA = attributes.begin(); itA != attributes.end(); ++itA)
303 	{
304 		if (IsEquivalent((*itA)->GetName(), name)) return (*itA);
305 	}
306 	return NULL;
307 }
308 
ReadAttribute(const char * name) const309 const fstring& FCDENode::ReadAttribute(const char* name) const
310 {
311 	const FCDEAttribute* attribute = FindAttribute(name);
312 	return (attribute != NULL) ? attribute->GetValue() : emptyFString;
313 }
314 
AddParameter(const char * name,const fchar * value)315 FCDENode* FCDENode::AddParameter(const char* name, const fchar* value)
316 {
317 	FCDENode* parameter = AddChildNode();
318 	parameter->SetName(name);
319 	parameter->SetContent(value);
320 	SetNewChildFlag();
321 	return parameter;
322 }
323 
Clone(FCDENode * clone) const324 FCDENode* FCDENode::Clone(FCDENode* clone) const
325 {
326 	if (clone == NULL) return NULL;
327 
328 	clone->name = name;
329 	clone->content = content;
330 
331 	clone->attributes.reserve(attributes.size());
332 	for (const FCDEAttribute** itA = attributes.begin(); itA != attributes.end(); ++itA)
333 	{
334 		clone->AddAttribute((*itA)->GetName(), (*itA)->GetValue());
335 	}
336 
337 	clone->children.reserve(children.size());
338 	for (const FCDENode** itC = children.begin(); itC != children.end(); ++itC)
339 	{
340 		FCDENode* clonedChild = clone->AddChildNode();
341 		(*itC)->Clone(clonedChild);
342 	}
343 
344 	// TODO: Clone the animated custom..
345 
346 	return clone;
347 }
348 
AddChildNode()349 FCDENode* FCDENode::AddChildNode()
350 {
351 	FCDENode* node = new FCDENode(GetDocument(), this);
352 	children.push_back(node);
353 	SetNewChildFlag();
354 	return node;
355 }
356 
AddChildNode(const char * name)357 FCDENode* FCDENode::AddChildNode(const char* name)
358 {
359 	FCDENode* node = new FCDENode(GetDocument(), this);
360 	children.push_back(node);
361 	node->SetName(name);
362 	SetNewChildFlag();
363 	return node;
364 }
365 
366 //
367 // FCDETechnique
368 //
369 
370 ImplementObjectType(FCDETechnique);
371 ImplementParameterObjectNoCtr(FCDETechnique, FUObject, pluginOverride);
372 
FCDETechnique(FCDocument * document,FCDEType * _parent,const char * _profile)373 FCDETechnique::FCDETechnique(FCDocument* document, FCDEType* _parent, const char* _profile)
374 :	FCDENode(document, NULL), parent(_parent)
375 ,	InitializeParameterNoArg(pluginOverride)
376 ,	InitializeParameter(profile, _profile)
377 {
378 }
379 
~FCDETechnique()380 FCDETechnique::~FCDETechnique() {}
381 
Clone(FCDENode * clone) const382 FCDENode* FCDETechnique::Clone(FCDENode* clone) const
383 {
384 	if (clone == NULL)
385 	{
386 		clone = new FCDETechnique(const_cast<FCDocument*>(GetDocument()), NULL, profile->c_str());
387 	}
388 	else if (clone->GetObjectType().Includes(FCDETechnique::GetClassType()))
389 	{
390 		((FCDETechnique*) clone)->profile = profile;
391 	}
392 
393 	FCDENode::Clone(clone);
394 	return clone;
395 }
396 
397 //
398 // FCDEAttribute
399 //
400 
FCDEAttribute()401 FCDEAttribute::FCDEAttribute()
402 :	FUParameterizable()
403 ,	InitializeParameterNoArg(name)
404 ,	InitializeParameterNoArg(value)
405 {
406 }
407 
FCDEAttribute(const char * _name,const fchar * _value)408 FCDEAttribute::FCDEAttribute(const char* _name, const fchar* _value)
409 :	FUParameterizable()
410 ,	InitializeParameter(name, _name)
411 ,	InitializeParameter(value, _value)
412 {
413 }
414