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 "FArchiveXML.h"
11 #include "FCDocument/FCDAnimated.h"
12 #include "FCDocument/FCDocument.h"
13 #include "FCDocument/FCDEntityInstance.h"
14 #include "FCDocument/FCDEntityReference.h"
15 #include "FCDocument/FCDPhysicsForceFieldInstance.h"
16 #include "FCDocument/FCDGeometryInstance.h"
17 #include "FCDocument/FCDPhysicsModelInstance.h"
18 #include "FCDocument/FCDPhysicsRigidBodyParameters.h"
19 #include "FCDocument/FCDPhysicsAnalyticalGeometry.h"
20 #include "FCDocument/FCDPhysicsMaterial.h"
21 #include "FCDocument/FCDPhysicsModel.h"
22 #include "FCDocument/FCDPhysicsRigidBody.h"
23 #include "FCDocument/FCDPhysicsRigidConstraint.h"
24 #include "FCDocument/FCDPhysicsScene.h"
25 #include "FCDocument/FCDPhysicsShape.h"
26 
LoadPhysicsRigidBodyParameters(FCDPhysicsRigidBodyParameters * parameters,xmlNode * techniqueNode,FCDPhysicsRigidBodyParameters * defaultParameters)27 bool FArchiveXML::LoadPhysicsRigidBodyParameters(FCDPhysicsRigidBodyParameters* parameters, xmlNode* techniqueNode, FCDPhysicsRigidBodyParameters* defaultParameters)
28 {
29 	bool status = true;
30 
31 	xmlNode* param = FindChildByType(techniqueNode, DAE_DYNAMIC_ELEMENT);
32 	if (param)
33 	{
34 		parameters->SetDynamic(FUStringConversion::ToBoolean(ReadNodeContentDirect(param)));
35 		FArchiveXML::LoadAnimatable(&parameters->GetDynamic(), param);
36 	}
37 	else if (defaultParameters != NULL)
38 	{
39 		parameters->SetDynamic(defaultParameters->GetDynamic() > 0.5f);
40 		if (defaultParameters->GetDynamic().IsAnimated())
41 		{
42 			defaultParameters->GetDynamic().GetAnimated()->Clone(parameters->GetDynamic().GetAnimated());
43 		}
44 	}
45 
46 	xmlNode* massFrame;
47 	massFrame = FindChildByType(techniqueNode, DAE_MASS_FRAME_ELEMENT);
48 	if (massFrame)
49 	{
50 		param = FindChildByType(massFrame, DAE_TRANSLATE_ELEMENT);
51 		if (param)
52 		{
53 			parameters->SetMassFrameTranslate(FUStringConversion::ToVector3(ReadNodeContentDirect(param)));
54 			FArchiveXML::LoadAnimatable(&parameters->GetMassFrameTranslate(), param);
55 		}
56 		else if (defaultParameters != NULL)
57 		{
58 			parameters->SetMassFrameTranslate(defaultParameters->GetMassFrameTranslate());
59 			if (defaultParameters->GetMassFrameTranslate().IsAnimated())
60 			{
61 				defaultParameters->GetMassFrameTranslate().GetAnimated()->Clone(parameters->GetMassFrameTranslate().GetAnimated());
62 			}
63 		}
64 		else
65 		{
66 			// no movement
67 			parameters->SetMassFrameTranslate(FMVector3::Zero);
68 		}
69 
70 		param = FindChildByType(massFrame, DAE_ROTATE_ELEMENT);
71 		if (param)
72 		{
73 			FMVector4 temp = FUStringConversion::ToVector4(ReadNodeContentDirect(param));
74 			parameters->SetMassFrameOrientation(FMAngleAxis(FMVector3(temp.x, temp.y, temp.z), temp.w));
75 			LoadAnimatable(&parameters->GetMassFrameOrientation(), param);
76 		}
77 		else if (defaultParameters != NULL)
78 		{
79 			parameters->SetMassFrameOrientation(defaultParameters->GetMassFrameOrientation());
80 			if (defaultParameters->GetMassFrameOrientation().IsAnimated())
81 			{
82 				defaultParameters->GetMassFrameOrientation().GetAnimated()->Clone(parameters->GetMassFrameOrientation().GetAnimated());
83 			}
84 		}
85 		else
86 		{
87 			// no movement
88 			parameters->SetMassFrameOrientation(FMAngleAxis(FMVector3::XAxis, 0.0f));
89 		}
90 	}
91 	else if (defaultParameters != NULL)
92 	{
93 		parameters->SetMassFrameTranslate(defaultParameters->GetMassFrameTranslate());
94 		parameters->SetMassFrameOrientation(defaultParameters->GetMassFrameOrientation());
95 		if (defaultParameters->GetMassFrameTranslate().IsAnimated())
96 		{
97 			defaultParameters->GetMassFrameTranslate().GetAnimated()->Clone(parameters->GetMassFrameTranslate().GetAnimated());
98 		}
99 		if (defaultParameters->GetMassFrameOrientation().IsAnimated())
100 		{
101 			defaultParameters->GetMassFrameOrientation().GetAnimated()->Clone(parameters->GetMassFrameOrientation().GetAnimated());
102 		}
103 	}
104 	else
105 	{
106 		// no movement
107 		parameters->SetMassFrameTranslate(FMVector3::Zero);
108 		parameters->SetMassFrameOrientation(FMAngleAxis(FMVector3::XAxis, 0.0f));
109 	}
110 
111 	xmlNodeList shapeNodes;
112 	FindChildrenByType(techniqueNode, DAE_SHAPE_ELEMENT, shapeNodes);
113 	if (shapeNodes.empty())
114 	{
115 		FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_SHAPE_NODE_MISSING, techniqueNode->line);
116 	}
117 	for (xmlNodeList::iterator itS = shapeNodes.begin(); itS != shapeNodes.end(); ++itS)
118 	{
119 		FCDPhysicsShape* shape = parameters->AddPhysicsShape();
120 		status &= (FArchiveXML::LoadPhysicsShape(shape, *itS));
121 	}
122 	// shapes are not taken from the default parameters
123 
124 	param = FindChildByType(techniqueNode, DAE_PHYSICS_MATERIAL_ELEMENT);
125 	if (param != NULL)
126 	{
127 		FCDPhysicsMaterial* material = parameters->AddOwnPhysicsMaterial();
128 		FArchiveXML::LoadPhysicsMaterial(material, param);
129 	}
130 	else
131 	{
132 		param = FindChildByType(techniqueNode, DAE_INSTANCE_PHYSICS_MATERIAL_ELEMENT);
133 		if (param != NULL)
134 		{
135 			FCDEntityInstance* physicsMaterialInstance = FCDEntityInstanceFactory::CreateInstance(parameters->GetDocument(), NULL, FCDEntity::PHYSICS_MATERIAL);
136 			parameters->SetInstanceMaterial(physicsMaterialInstance);
137 			FArchiveXML::LoadSwitch(physicsMaterialInstance, &physicsMaterialInstance->GetObjectType(), param);
138 			FCDPhysicsMaterial* material = (FCDPhysicsMaterial*) physicsMaterialInstance->GetEntity();
139 			if (material == NULL)
140 			{
141 				FUError::Error(FUError::ERROR_LEVEL, FUError::WARNING_MISSING_URI_TARGET, param->line);
142 			}
143 			parameters->SetPhysicsMaterial(material);
144 		}
145 		else
146 		{
147 			FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_PHYS_MAT_DEF_MISSING, techniqueNode->line);
148 		}
149 	}
150 	// material is not taken fromt he default parameters
151 
152 	param = FindChildByType(techniqueNode, DAE_MASS_ELEMENT);
153 	if (param)
154 	{
155 		parameters->SetMass(FUStringConversion::ToFloat(ReadNodeContentDirect(param)));
156 		parameters->SetDensityMoreAccurate(false);
157 		parameters->SetDensity(0.0f);
158 		FArchiveXML::LoadAnimatable(&parameters->GetMass(), param);
159 	}
160 	else if (defaultParameters != NULL)
161 	{
162 		parameters->SetMass(defaultParameters->GetMass());
163 		parameters->SetDensity(defaultParameters->GetDensity());
164 		parameters->SetDensityMoreAccurate(defaultParameters->IsDensityMoreAccurate());
165 		if (defaultParameters->GetMass().IsAnimated())
166 		{
167 			defaultParameters->GetMass().GetAnimated()->Clone(parameters->GetMass().GetAnimated());
168 		}
169 	}
170 	else
171 	{
172 		/* Default value for mass is density x total shape volume, but
173 		   since our shape's mass is already calculated with respect to the
174 		   volume, we can just read it from there. If the user specified a
175 		   mass, then this overrides the calculation of density x volume,
176 		   as expected. */
177 		parameters->SetMass(0.0f);
178 		float totalDensity = 0.0f;
179 		parameters->SetDensityMoreAccurate(false);
180 		for (size_t i = 0; i < parameters->GetPhysicsShapeCount(); ++i)
181 		{
182 			FCDPhysicsShape* shape = parameters->GetPhysicsShape(i);
183 			parameters->SetMass(parameters->GetMass() + shape->GetMass());
184 			totalDensity += shape->GetDensity();
185 			parameters->SetDensityMoreAccurate(parameters->IsDensityMoreAccurate() || shape->IsDensityMoreAccurate()); // common case: 1 shape, density = 1.0f
186 		}
187 		parameters->SetDensity(totalDensity / parameters->GetPhysicsShapeCount());
188 	}
189 
190 
191 	param = FindChildByType(techniqueNode, DAE_INERTIA_ELEMENT);
192 	if (param)
193 	{
194 		parameters->SetInertia(FUStringConversion::ToVector3(ReadNodeContentDirect(param)));
195 		parameters->SetInertiaAccurate(true);
196 		FArchiveXML::LoadAnimatable(&parameters->GetInertia(), param);
197 	}
198 	else if (defaultParameters != NULL)
199 	{
200 		parameters->SetInertia(defaultParameters->GetInertia());
201 		parameters->SetInertiaAccurate(defaultParameters->IsInertiaAccurate());
202 		if (defaultParameters->GetInertia().IsAnimated())
203 		{
204 			defaultParameters->GetInertia().GetAnimated()->Clone(parameters->GetInertia().GetAnimated());
205 		}
206 	}
207 	else
208 	{
209 		/* FIXME: Approximation: sphere shape, with mass distributed
210 		   equally across the volume and center of mass is at the center of
211 		   the sphere. Real moments of inertia call for complex
212 		   integration. Sphere it is simply I = k * m * r^2 on all axes. */
213 		float volume = 0.0f;
214 		for (size_t i = 0; i < parameters->GetPhysicsShapeCount(); ++i)
215 		{
216 			volume += parameters->GetPhysicsShape(i)->CalculateVolume();
217 		}
218 
219 		float radiusCubed = 0.75f * volume / (float)FMath::Pi;
220 		float I = 0.4f * parameters->GetMass() * pow(radiusCubed, 2.0f / 3.0f);
221 		parameters->SetInertia(FMVector3(I, I, I));
222 		parameters->SetInertiaAccurate(false);
223 	}
224 
225 	return status;
226 }
227 
AttachModelInstancesFCDPhysicsModel(FCDPhysicsModel * physicsModel)228 bool FArchiveXML::AttachModelInstancesFCDPhysicsModel(FCDPhysicsModel* physicsModel)
229 {
230 	bool status = true;
231 
232 	FCDPhysicsModelDataMap::iterator it = FArchiveXML::documentLinkDataMap[physicsModel->GetDocument()].physicsModelDataMap.find(physicsModel);
233 	FUAssert(it != FArchiveXML::documentLinkDataMap[physicsModel->GetDocument()].physicsModelDataMap.end(),);
234 	FCDPhysicsModelData& data = it->second;
235 
236 	for (ModelInstanceNameNodeMap::iterator it = data.modelInstancesMap.begin(); it != data.modelInstancesMap.end(); ++it)
237 	{
238 		FCDPhysicsModelInstance* instance = physicsModel->AddPhysicsModelInstance();
239 		status &= FArchiveXML::LoadPhysicsModelInstance(instance, it->first);
240 	}
241 	data.modelInstancesMap.clear();
242 	return status;
243 }
244 
LoadPhysicsShape(FCDObject * object,xmlNode * physicsShapeNode)245 bool FArchiveXML::LoadPhysicsShape(FCDObject* object, xmlNode* physicsShapeNode)
246 {
247 	FCDPhysicsShape* physicsShape = (FCDPhysicsShape*)object;
248 
249 	bool status = true;
250 	if (!IsEquivalent(physicsShapeNode->name, DAE_SHAPE_ELEMENT))
251 	{
252 		FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_UNKNOW_PS_LIB_ELEMENT, physicsShapeNode->line);
253 		return status;
254 	}
255 
256 	// Read in the first valid child element found
257 	for (xmlNode* child = physicsShapeNode->children; child != NULL; child = child->next)
258 	{
259 		if (child->type != XML_ELEMENT_NODE) continue;
260 
261 		if (IsEquivalent(child->name, DAE_HOLLOW_ELEMENT))
262 		{
263 			physicsShape->SetHollow(FUStringConversion::ToBoolean(ReadNodeContentDirect(child)));
264 		}
265 		else if (IsEquivalent(child->name, DAE_MASS_ELEMENT))
266 		{
267 			physicsShape->SetMass(FUStringConversion::ToFloat(ReadNodeContentDirect(child)));
268 			physicsShape->SetDensityMoreAccurate(false);
269 		}
270 		else if (IsEquivalent(child->name, DAE_DENSITY_ELEMENT))
271 		{
272 			physicsShape->SetDensity(FUStringConversion::ToFloat(ReadNodeContentDirect(child)));
273 			physicsShape->SetDensityMoreAccurate(physicsShape->GetMassPointer() == NULL); // mass before density in COLLADA 1.4.1
274 		}
275 		else if (IsEquivalent(child->name, DAE_PHYSICS_MATERIAL_ELEMENT))
276 		{
277 			FCDPhysicsMaterial* material = physicsShape->AddOwnPhysicsMaterial();
278 			FArchiveXML::LoadPhysicsMaterial(material, child);
279 		}
280 		else if (IsEquivalent(child->name,
281 				DAE_INSTANCE_PHYSICS_MATERIAL_ELEMENT))
282 		{
283 			physicsShape->SetInstanceMaterial(FCDEntityInstanceFactory::CreateInstance(physicsShape->GetDocument(), NULL, FCDEntity::PHYSICS_MATERIAL));
284 			FArchiveXML::LoadSwitch(physicsShape->GetInstanceMaterial(),
285 										&physicsShape->GetInstanceMaterial()->GetObjectType(),
286 										child);
287 
288 			if (!HasNodeProperty(child, DAE_URL_ATTRIBUTE))
289 			{
290 				//inline definition of physics_material
291 				FCDPhysicsMaterial* material = physicsShape->AddOwnPhysicsMaterial();
292 				FArchiveXML::LoadPhysicsMaterial(material, child);
293 				physicsShape->GetInstanceMaterial()->SetEntity(material);
294 			}
295 		}
296 		else if (IsEquivalent(child->name, DAE_INSTANCE_GEOMETRY_ELEMENT))
297 		{
298 			FUUri url = ReadNodeUrl(child);
299 			if (!url.IsFile())
300 			{
301 				FCDGeometry* entity = physicsShape->GetDocument()->FindGeometry(TO_STRING(url.GetFragment()));
302 				if (entity != NULL)
303 				{
304 					physicsShape->SetAnalyticalGeometry(NULL);
305 					physicsShape->SetGeometryInstance((FCDGeometryInstance*)FCDEntityInstanceFactory::CreateInstance(physicsShape->GetDocument(), NULL, FCDEntity::GEOMETRY));
306 					physicsShape->GetGeometryInstance()->SetEntity((FCDEntity*)entity);
307 					status &= (FArchiveXML::LoadGeometryInstance(physicsShape->GetGeometryInstance(), child));
308 					continue;
309 				}
310 			}
311 			FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_FCDGEOMETRY_INST_MISSING, child->line);
312 		}
313 
314 #define PARSE_ANALYTICAL_SHAPE(type, nodeName) \
315 		else if (IsEquivalent(child->name, nodeName)) { \
316 		FCDPhysicsAnalyticalGeometry* analytical = physicsShape->CreateAnalyticalGeometry(FCDPhysicsAnalyticalGeometry::type); \
317 		status = FArchiveXML::LoadPhysicsAnalyticalGeometry(analytical, child); \
318 			if (!status) { \
319 				FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_INVALID_SHAPE_NODE, child->line); break; \
320 			} }
321 
322 		PARSE_ANALYTICAL_SHAPE(BOX, DAE_BOX_ELEMENT)
323 		PARSE_ANALYTICAL_SHAPE(PLANE, DAE_PLANE_ELEMENT)
324 		PARSE_ANALYTICAL_SHAPE(SPHERE, DAE_SPHERE_ELEMENT)
325 		PARSE_ANALYTICAL_SHAPE(CYLINDER, DAE_CYLINDER_ELEMENT)
326 		PARSE_ANALYTICAL_SHAPE(CAPSULE, DAE_CAPSULE_ELEMENT)
327 		PARSE_ANALYTICAL_SHAPE(TAPERED_CAPSULE, DAE_TAPERED_CAPSULE_ELEMENT)
328 		PARSE_ANALYTICAL_SHAPE(TAPERED_CYLINDER, DAE_TAPERED_CYLINDER_ELEMENT)
329 #undef PARSE_ANALYTICAL_SHAPE
330 
331 
332 		// Parse the physics shape transforms <rotate>, <translate> are supported.
333 		else if (IsEquivalent(child->name, DAE_ASSET_ELEMENT)) {}
334 		else if (IsEquivalent(child->name, DAE_EXTRA_ELEMENT)) {}
335 		else
336 		{
337 			uint32 transformType = FArchiveXML::GetTransformType(child);
338 			if (transformType == FCDTransform::TRANSLATION || transformType == FCDTransform::ROTATION)
339 			{
340 				FCDTransform* transform = physicsShape->AddTransform((FCDTransform::Type) transformType);
341 				status &= (FArchiveXML::LoadSwitch(transform, &transform->GetObjectType(), child));
342 			}
343 		}
344 	}
345 
346 	if ((physicsShape->GetMassPointer() == NULL) && (physicsShape->GetDensityPointer() == NULL))
347 	{
348 		physicsShape->SetDensity(1.0f);
349 		physicsShape->SetDensityMoreAccurate(true);
350 	}
351 
352 	// default value if only one is defined.
353 	if ((physicsShape->GetMassPointer() == NULL) && (physicsShape->GetDensityPointer() != NULL))
354 	{
355 		physicsShape->SetMass(physicsShape->GetDensity() * physicsShape->CalculateVolume());
356 	}
357 	else if ((physicsShape->GetMassPointer() != NULL) && (physicsShape->GetDensityPointer() == NULL))
358 	{
359 		physicsShape->SetDensity(physicsShape->GetMass() / physicsShape->CalculateVolume());
360 	}
361 
362 	physicsShape->SetDirtyFlag();
363 	return status;
364 }
365 
LoadPhysicsAnalyticalGeometry(FCDObject * object,xmlNode * node)366 bool FArchiveXML::LoadPhysicsAnalyticalGeometry(FCDObject* object, xmlNode* node)
367 {
368 	return FArchiveXML::LoadSwitch(object, &object->GetObjectType(), node);
369 }
370 
LoadPASBox(FCDObject * object,xmlNode * node)371 bool FArchiveXML::LoadPASBox(FCDObject* object, xmlNode* node)
372 {
373 	FCDPASBox* pASBox = (FCDPASBox*)object;
374 
375 	bool status = true;
376 
377 	if (!IsEquivalent(node->name, DAE_BOX_ELEMENT))
378 	{
379 		FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_INVALID_BOX_TYPE, node->line);
380 		return status;
381 	}
382 
383 	for (xmlNode* child = node->children; child != NULL; child = child->next)
384 	{
385 		if (child->type != XML_ELEMENT_NODE) continue;
386 
387 		if (IsEquivalent(child->name, DAE_HALF_EXTENTS_ELEMENT))
388 		{
389 			const char* halfExt = ReadNodeContentDirect(child);
390 			pASBox->halfExtents.x = FUStringConversion::ToFloat(&halfExt);
391 			pASBox->halfExtents.y = FUStringConversion::ToFloat(&halfExt);
392 			pASBox->halfExtents.z = FUStringConversion::ToFloat(&halfExt);
393 		}
394 	}
395 
396 	pASBox->SetDirtyFlag();
397 	return status;
398 }
399 
LoadPASCapsule(FCDObject * object,xmlNode * node)400 bool FArchiveXML::LoadPASCapsule(FCDObject* object, xmlNode* node)
401 {
402 	FCDPASCapsule* pASCapsule = (FCDPASCapsule*)object;
403 
404 	bool status = true;
405 
406 	if (!IsEquivalent(node->name, DAE_CAPSULE_ELEMENT))
407 	{
408 		FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_INVALID_CAPSULE_TYPE, node->line);
409 		return status;
410 	}
411 
412 	for (xmlNode* child = node->children; child != NULL; child = child->next)
413 	{
414 		if (child->type != XML_ELEMENT_NODE) continue;
415 
416 		if (IsEquivalent(child->name, DAE_HEIGHT_ELEMENT))
417 		{
418 			pASCapsule->height = FUStringConversion::ToFloat(ReadNodeContentDirect(child));
419 		}
420 		else if (IsEquivalent(child->name, DAE_RADIUS_ELEMENT))
421 		{
422 			const char* stringRadius = ReadNodeContentDirect(child);
423 			pASCapsule->radius.x = FUStringConversion::ToFloat(&stringRadius);
424 			pASCapsule->radius.y = FUStringConversion::ToFloat(&stringRadius);
425 		}
426 	}
427 
428 	pASCapsule->SetDirtyFlag();
429 	return status;
430 }
431 
LoadPASTaperedCapsule(FCDObject * object,xmlNode * node)432 bool FArchiveXML::LoadPASTaperedCapsule(FCDObject* object, xmlNode* node)
433 {
434 	FCDPASTaperedCapsule* pASTaperedCapsule = (FCDPASTaperedCapsule*)object;
435 
436 	bool status = true;
437 
438 	if (!IsEquivalent(node->name, DAE_TAPERED_CAPSULE_ELEMENT))
439 	{
440 		FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_INVALID_TCAPSULE_TYPE, node->line);
441 		return status;
442 	}
443 
444 	for (xmlNode* child = node->children; child != NULL; child = child->next)
445 	{
446 		if (child->type != XML_ELEMENT_NODE) continue;
447 
448 		if (IsEquivalent(child->name, DAE_HEIGHT_ELEMENT))
449 		{
450 			const char* h = ReadNodeContentDirect(child);
451 			pASTaperedCapsule->height = FUStringConversion::ToFloat(&h);
452 		}
453 		else if (IsEquivalent(child->name, DAE_RADIUS1_ELEMENT))
454 		{
455 			const char* stringRadius = ReadNodeContentDirect(child);
456 			pASTaperedCapsule->radius.x = FUStringConversion::ToFloat(&stringRadius);
457 			pASTaperedCapsule->radius.y = FUStringConversion::ToFloat(&stringRadius);
458 		}
459 		else if (IsEquivalent(child->name, DAE_RADIUS2_ELEMENT))
460 		{
461 			const char* stringRadius = ReadNodeContentDirect(child);
462 			pASTaperedCapsule->radius2.x = FUStringConversion::ToFloat(&stringRadius);
463 			pASTaperedCapsule->radius2.y = FUStringConversion::ToFloat(&stringRadius);
464 		}
465 	}
466 
467 	pASTaperedCapsule->SetDirtyFlag();
468 	return status;
469 }
470 
LoadPASCylinder(FCDObject * object,xmlNode * node)471 bool FArchiveXML::LoadPASCylinder(FCDObject* object, xmlNode* node)
472 {
473 	FCDPASCylinder* pASCylinder = (FCDPASCylinder*)object;
474 
475 	bool status = true;
476 
477 	if (!IsEquivalent(node->name, DAE_CYLINDER_ELEMENT))
478 	{
479 		FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_INVALID_SPHERE_TYPE, node->line);
480 		return status;
481 	}
482 
483 	for (xmlNode* child = node->children; child != NULL; child = child->next)
484 	{
485 		if (child->type != XML_ELEMENT_NODE) continue;
486 
487 		if (IsEquivalent(child->name, DAE_HEIGHT_ELEMENT))
488 		{
489 			pASCylinder->height = FUStringConversion::ToFloat(ReadNodeContentDirect(child));
490 		}
491 		else if (IsEquivalent(child->name, DAE_RADIUS_ELEMENT))
492 		{
493 			const char* stringRadius = ReadNodeContentDirect(child);
494 			pASCylinder->radius.x = FUStringConversion::ToFloat(&stringRadius);
495 			pASCylinder->radius.y = FUStringConversion::ToFloat(&stringRadius);
496 		}
497 	}
498 
499 	pASCylinder->SetDirtyFlag();
500 	return status;
501 }
502 
LoadPASTaperedCylinder(FCDObject * object,xmlNode * node)503 bool FArchiveXML::LoadPASTaperedCylinder(FCDObject* object, xmlNode* node)
504 {
505 	FCDPASTaperedCylinder* pASTaperedCylinder = (FCDPASTaperedCylinder*)object;
506 
507 	bool status = true;
508 
509 	if (!IsEquivalent(node->name, DAE_TAPERED_CYLINDER_ELEMENT))
510 	{
511 		FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_INVALID_TCYLINDER_TYPE, node->line);
512 		return status;
513 	}
514 
515 	for (xmlNode* child = node->children; child != NULL; child = child->next)
516 	{
517 		if (child->type != XML_ELEMENT_NODE) continue;
518 
519 		if (IsEquivalent(child->name, DAE_HEIGHT_ELEMENT))
520 		{
521 			const char* h = ReadNodeContentDirect(child);
522 			pASTaperedCylinder->height = FUStringConversion::ToFloat(&h);
523 		}
524 		else if (IsEquivalent(child->name, DAE_RADIUS1_ELEMENT))
525 		{
526 			const char* stringRadius = ReadNodeContentDirect(child);
527 			pASTaperedCylinder->radius.x = FUStringConversion::ToFloat(&stringRadius);
528 			pASTaperedCylinder->radius.y = FUStringConversion::ToFloat(&stringRadius);
529 		}
530 		else if (IsEquivalent(child->name, DAE_RADIUS2_ELEMENT))
531 		{
532 			const char* stringRadius = ReadNodeContentDirect(child);
533 			pASTaperedCylinder->radius2.x = FUStringConversion::ToFloat(&stringRadius);
534 			pASTaperedCylinder->radius2.y = FUStringConversion::ToFloat(&stringRadius);
535 		}
536 	}
537 
538 	pASTaperedCylinder->SetDirtyFlag();
539 	return status;
540 }
541 
LoadPASPlane(FCDObject * object,xmlNode * node)542 bool FArchiveXML::LoadPASPlane(FCDObject* object, xmlNode* node)
543 {
544 	FCDPASPlane* pASPlane = (FCDPASPlane*)object;
545 
546 	bool status = true;
547 
548 	if (!IsEquivalent(node->name, DAE_PLANE_ELEMENT))
549 	{
550 		FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_INVALID_PLANE_TYPE, node->line);
551 		return status;
552 	}
553 
554 	for (xmlNode* child = node->children; child != NULL; child = child->next)
555 	{
556 		if (child->type != XML_ELEMENT_NODE) continue;
557 
558 		if (IsEquivalent(child->name, DAE_EQUATION_ELEMENT))
559 		{
560 			const char* eq = ReadNodeContentDirect(child);
561 			pASPlane->normal.x = FUStringConversion::ToFloat(&eq);
562 			pASPlane->normal.y = FUStringConversion::ToFloat(&eq);
563 			pASPlane->normal.z = FUStringConversion::ToFloat(&eq);
564 			pASPlane->d = FUStringConversion::ToFloat(&eq);
565 		}
566 	}
567 
568 	pASPlane->SetDirtyFlag();
569 	return status;
570 }
571 
LoadPASSphere(FCDObject * object,xmlNode * node)572 bool FArchiveXML::LoadPASSphere(FCDObject* object, xmlNode* node)
573 {
574 	FCDPASSphere* pASSphere = (FCDPASSphere*)object;
575 
576 	bool status = true;
577 
578 	if (!IsEquivalent(node->name, DAE_SPHERE_ELEMENT))
579 	{
580 		FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_INVALID_SPHERE_TYPE, node->line);
581 		return status;
582 	}
583 
584 	for (xmlNode* child = node->children; child != NULL; child = child->next)
585 	{
586 		if (child->type != XML_ELEMENT_NODE) continue;
587 
588 		if (IsEquivalent(child->name, DAE_RADIUS_ELEMENT))
589 		{
590 			pASSphere->radius = FUStringConversion::ToFloat(ReadNodeContentDirect(child));
591 		}
592 	}
593 
594 	pASSphere->SetDirtyFlag();
595 	return status;
596 }
597 
LoadPhysicsMaterial(FCDObject * object,xmlNode * physicsMaterialNode)598 bool FArchiveXML::LoadPhysicsMaterial(FCDObject* object, xmlNode* physicsMaterialNode)
599 {
600 	if (!FArchiveXML::LoadEntity(object, physicsMaterialNode)) return false;
601 
602 	bool status = true;
603 	FCDPhysicsMaterial* physicsMaterial = (FCDPhysicsMaterial*)object;
604 	if (!IsEquivalent(physicsMaterialNode->name, DAE_PHYSICS_MATERIAL_ELEMENT))
605 	{
606 		FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_UNKNOWN_PHYS_MAT_LIB_ELEMENT, physicsMaterialNode->line);
607 		return status;
608 	}
609 
610 	// Read in the <technique_common> element
611 	xmlNode* commonTechniqueNode = FindChildByType(physicsMaterialNode, DAE_TECHNIQUE_COMMON_ELEMENT);
612 	if (commonTechniqueNode == NULL)
613 	{
614 		FUError::Error(FUError::ERROR_LEVEL, FUError::ERROR_COMMON_TECHNIQUE_MISSING, physicsMaterialNode->line);
615 	}
616 
617 	xmlNode* paramNode = FindChildByType(commonTechniqueNode, DAE_PHYSICS_STATIC_FRICTION);
618 	if (paramNode != NULL)
619 	{
620 		const char* content = ReadNodeContentDirect(paramNode);
621 		physicsMaterial->SetStaticFriction(FUStringConversion::ToFloat(content));
622 	}
623 
624 	paramNode = FindChildByType(commonTechniqueNode, DAE_PHYSICS_DYNAMIC_FRICTION);
625 	if (paramNode != NULL)
626 	{
627 		const char* content = ReadNodeContentDirect(paramNode);
628 		physicsMaterial->SetDynamicFriction(FUStringConversion::ToFloat(content));
629 	}
630 
631 	paramNode = FindChildByType(commonTechniqueNode, DAE_PHYSICS_RESTITUTION);
632 	if (paramNode != NULL)
633 	{
634 		const char* content = ReadNodeContentDirect(paramNode);
635 		physicsMaterial->SetRestitution(FUStringConversion::ToFloat(content));
636 	}
637 
638 	physicsMaterial->SetDirtyFlag();
639 	return status;
640 }
641 
LoadPhysicsModel(FCDObject * object,xmlNode * physicsModelNode)642 bool FArchiveXML::LoadPhysicsModel(FCDObject* object, xmlNode* physicsModelNode)
643 {
644 	if (!FArchiveXML::LoadEntity(object, physicsModelNode)) return false;
645 
646 	bool status = true;
647 	FCDPhysicsModel* physicsModel = (FCDPhysicsModel*)object;
648 	FCDPhysicsModelData& data = FArchiveXML::documentLinkDataMap[physicsModel->GetDocument()].physicsModelDataMap[physicsModel];
649 	if (!IsEquivalent(physicsModelNode->name, DAE_PHYSICS_MODEL_ELEMENT))
650 	{
651 		FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_UNKNOWN_PHYS_LIB_ELEMENT, physicsModelNode->line);
652 		return status;
653 	}
654 
655 	// Read in the first valid child element found
656 	for (xmlNode* child = physicsModelNode->children; child != NULL; child = child->next)
657 	{
658 		if (child->type != XML_ELEMENT_NODE) continue;
659 
660 		if (IsEquivalent(child->name, DAE_RIGID_BODY_ELEMENT))
661 		{
662 			FCDPhysicsRigidBody* rigidBody = physicsModel->AddRigidBody();
663 			status &= (FArchiveXML::LoadPhysicsRigidBody(rigidBody, child));
664 		}
665 		else if (IsEquivalent(child->name, DAE_RIGID_CONSTRAINT_ELEMENT))
666 		{
667 			FCDPhysicsRigidConstraint* rigidConstraint = physicsModel->AddRigidConstraint();
668 			status &= (FArchiveXML::LoadPhysicsRigidConstraint(rigidConstraint, child));
669 		}
670 		else if (IsEquivalent(child->name, DAE_INSTANCE_PHYSICS_MODEL_ELEMENT))
671 		{
672 			data.modelInstancesMap.insert(child, ReadNodeUrl(child));
673 		}
674 	}
675 
676 	physicsModel->SetDirtyFlag();
677 	return status;
678 }
679 
LoadPhysicsRigidBody(FCDObject * object,xmlNode * physicsRigidBodyNode)680 bool FArchiveXML::LoadPhysicsRigidBody(FCDObject* object, xmlNode* physicsRigidBodyNode)
681 {
682 	if (!FArchiveXML::LoadEntity(object, physicsRigidBodyNode)) return false;
683 
684 	bool status = true;
685 	FCDPhysicsRigidBody* physicsRigidBody = (FCDPhysicsRigidBody*)object;
686 	if (!IsEquivalent(physicsRigidBodyNode->name, DAE_RIGID_BODY_ELEMENT))
687 	{
688 		FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_UNKNOWN_PRB_LIB_ELEMENT, physicsRigidBodyNode->line);
689 		return status;
690 	}
691 
692 	physicsRigidBody->SetSubId(FUDaeParser::ReadNodeSid(physicsRigidBodyNode));
693 
694 	xmlNode* techniqueNode = FindChildByType(physicsRigidBodyNode,
695 			DAE_TECHNIQUE_COMMON_ELEMENT);
696 	if (techniqueNode != NULL)
697 	{
698 		FArchiveXML::LoadPhysicsRigidBodyParameters(physicsRigidBody->GetParameters(), techniqueNode);
699 	}
700 	else
701 	{
702 		FUError::Error(FUError::ERROR_LEVEL, FUError::ERROR_COMMON_TECHNIQUE_MISSING,
703 				physicsRigidBodyNode->line);
704 	}
705 
706 	return status;
707 }
708 
LoadPhysicsRigidConstraint(FCDObject * object,xmlNode * physicsRigidConstraintNode)709 bool FArchiveXML::LoadPhysicsRigidConstraint(FCDObject* object, xmlNode* physicsRigidConstraintNode)
710 {
711 	if (!FArchiveXML::LoadEntity(object, physicsRigidConstraintNode)) return false;
712 
713 	bool status = true;
714 	FCDPhysicsRigidConstraint* physicsRigidConstraint = (FCDPhysicsRigidConstraint*)object;
715 	if (!IsEquivalent(physicsRigidConstraintNode->name, DAE_RIGID_CONSTRAINT_ELEMENT))
716 	{
717 		FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_UNKNOWN_RGC_LIB_ELEMENT, physicsRigidConstraintNode->line);
718 		return status;
719 	}
720 
721 	physicsRigidConstraint->SetSubId(FUDaeParser::ReadNodeSid(physicsRigidConstraintNode));
722 
723 #define PARSE_TRANSFORM(node, className, nodeName, transforms) { \
724 	xmlNodeList transformNodes; \
725 	FindChildrenByType(node, nodeName, transformNodes); \
726 	for (xmlNodeList::iterator itT = transformNodes.begin(); itT != transformNodes.end(); ++itT) \
727 	{ \
728 		if (IsEquivalent((*itT)->name, nodeName)) { \
729 			className* transform = new className(physicsRigidConstraint->GetDocument(), NULL); \
730 			transforms.push_back(transform); \
731 			status = FArchiveXML::LoadSwitch(transform, &transform->GetObjectType(), *itT); \
732 			if (!status) { \
733 				FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_INVALID_NODE_TRANSFORM, (*itT)->line);} \
734 		} \
735 	}  }
736 
737 
738 
739 	//Reference-frame body
740 	xmlNode* referenceBodyNode = FindChildByType(physicsRigidConstraintNode, DAE_REF_ATTACHMENT_ELEMENT);
741 	if (referenceBodyNode == NULL)
742 	{
743 		FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_RF_NODE_MISSING, physicsRigidConstraintNode->line);
744 	}
745 	fm::string strRigidBody = ReadNodeProperty(referenceBodyNode, DAE_RIGID_BODY_ELEMENT);
746 	physicsRigidConstraint->SetReferenceRigidBody(physicsRigidConstraint->GetParent()->FindRigidBodyFromSid(strRigidBody));
747 	if (physicsRigidConstraint->GetReferenceRigidBody() == NULL)
748 	{
749 		physicsRigidConstraint->SetReferenceNode(physicsRigidConstraint->GetDocument()->FindSceneNode(strRigidBody));
750 		if ((physicsRigidConstraint->GetReferenceNode() == NULL) && (referenceBodyNode != NULL))
751 		{
752 			FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_RF_REF_NODE_MISSING, referenceBodyNode->line);
753 		}
754 	}
755 	// Parse the node's transforms: <rotate>, <translate>
756 	PARSE_TRANSFORM(referenceBodyNode, FCDTRotation, DAE_ROTATE_ELEMENT, physicsRigidConstraint->GetTransformsRef())
757 	PARSE_TRANSFORM(referenceBodyNode, FCDTTranslation, DAE_TRANSLATE_ELEMENT, physicsRigidConstraint->GetTransformsRef())
758 
759 	// target body
760 	xmlNode* bodyNode = FindChildByType(physicsRigidConstraintNode, DAE_ATTACHMENT_ELEMENT);
761 	if (bodyNode == NULL)
762 	{
763 		FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_TARGET_BS_NODE_MISSING, physicsRigidConstraintNode->line);
764 	}
765 	strRigidBody = ReadNodeProperty(bodyNode, DAE_RIGID_BODY_ELEMENT);
766 	physicsRigidConstraint->SetTargetRigidBody(physicsRigidConstraint->GetParent()->FindRigidBodyFromSid(strRigidBody));
767 	if (physicsRigidConstraint->GetTargetRigidBody() == NULL)
768 	{
769 		physicsRigidConstraint->SetTargetNode(physicsRigidConstraint->GetDocument()->FindSceneNode(strRigidBody));
770 		if ((physicsRigidConstraint->GetTargetNode() == NULL) && (bodyNode != NULL))
771 		{
772 			FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_TARGE_BS_REF_NODE_MISSING, bodyNode->line);
773 		}
774 	}
775 	// Parse the node's transforms: <rotate>, <scale>, <translate>
776 	PARSE_TRANSFORM(bodyNode, FCDTRotation, DAE_ROTATE_ELEMENT, physicsRigidConstraint->GetTransformsTar())
777 	PARSE_TRANSFORM(bodyNode, FCDTTranslation, DAE_TRANSLATE_ELEMENT, physicsRigidConstraint->GetTransformsTar())
778 
779 #undef PARSE_TRANSFORM
780 
781 	//technique_common
782 	xmlNode* techniqueNode = FindChildByType(physicsRigidConstraintNode, DAE_TECHNIQUE_COMMON_ELEMENT);
783 	if (techniqueNode == NULL)
784 	{
785 		//return status.Fail(FS("Technique node not specified in rigid_constraint ") + TO_FSTRING(GetDaeId()), physicsRigidConstraintNode->line);
786 		FUError::Error(FUError::ERROR_LEVEL, FUError::ERROR_TECHNIQUE_NODE_MISSING, physicsRigidConstraintNode->line);
787 		return status;
788 	}
789 
790 	xmlNode* enabledNode = FindChildByType(techniqueNode, DAE_ENABLED_ELEMENT);
791 	if (enabledNode != NULL)
792 	{
793 		physicsRigidConstraint->SetEnabled(FUStringConversion::ToBoolean(ReadNodeContentDirect(enabledNode)));
794 		FArchiveXML::LoadAnimatable(&physicsRigidConstraint->GetEnabled(), enabledNode);
795 	}
796 	xmlNode* interpenetrateNode = FindChildByType(techniqueNode, DAE_INTERPENETRATE_ELEMENT);
797 	if (interpenetrateNode != NULL)
798 	{
799 		physicsRigidConstraint->SetInterpenetrate(FUStringConversion::ToBoolean(ReadNodeContentDirect(interpenetrateNode)));
800 		FArchiveXML::LoadAnimatable(&physicsRigidConstraint->GetInterpenetrate(), interpenetrateNode);
801 	}
802 
803 	xmlNode* limitsNode = FindChildByType(techniqueNode, DAE_LIMITS_ELEMENT);
804 	if (limitsNode != NULL)
805 	{
806 		xmlNode* linearNode = FindChildByType(limitsNode, DAE_LINEAR_ELEMENT);
807 		if (linearNode != NULL)
808 		{
809 			xmlNode* linearMinNode = FindChildByType(linearNode, DAE_MIN_ELEMENT);
810 			if (linearMinNode != NULL)
811 			{
812 				const char* min = ReadNodeContentDirect(linearMinNode);
813 				physicsRigidConstraint->SetLimitsLinearMin(FUStringConversion::ToVector3(min));
814 			}
815 			xmlNode* linearMaxNode = FindChildByType(linearNode, DAE_MAX_ELEMENT);
816 			if (linearMaxNode != NULL)
817 			{
818 				const char* max = ReadNodeContentDirect(linearMaxNode);
819 				physicsRigidConstraint->SetLimitsLinearMax(FUStringConversion::ToVector3(max));
820 			}
821 		}
822 
823 		xmlNode* sctNode = FindChildByType(limitsNode, DAE_SWING_CONE_AND_TWIST_ELEMENT);
824 		if (sctNode != NULL)
825 		{
826 			xmlNode* sctMinNode = FindChildByType(sctNode, DAE_MIN_ELEMENT);
827 			if (sctMinNode != NULL)
828 			{
829 				const char* min = ReadNodeContentDirect(sctMinNode);
830 				physicsRigidConstraint->SetLimitsSCTMin(FUStringConversion::ToVector3(min));
831 			}
832 			xmlNode* sctMaxNode = FindChildByType(sctNode, DAE_MAX_ELEMENT);
833 			if (sctMaxNode != NULL)
834 			{
835 				const char* max = ReadNodeContentDirect(sctMaxNode);
836 				physicsRigidConstraint->SetLimitsSCTMax(FUStringConversion::ToVector3(max));
837 			}
838 		}
839 	}
840 
841 	xmlNode* spring = FindChildByType(physicsRigidConstraintNode, DAE_SPRING_ELEMENT);
842 	if (spring)
843 	{
844 		xmlNode* linearSpring = FindChildByType(spring, DAE_LINEAR_ELEMENT);
845 		if (linearSpring)
846 		{
847 			xmlNode* param = FindChildByType(linearSpring, DAE_DAMPING_ELEMENT);
848 			if (param) physicsRigidConstraint->SetSpringLinearDamping(FUStringConversion::ToFloat(ReadNodeContentDirect(param)));
849 			param = FindChildByType(linearSpring, DAE_STIFFNESS_ELEMENT);
850 			if (param) physicsRigidConstraint->SetSpringLinearStiffness(FUStringConversion::ToFloat(ReadNodeContentDirect(param)));
851 			param = FindChildByType(linearSpring, DAE_TARGET_VALUE_ELEMENT);
852 			if (!param) param = FindChildByType(linearSpring, DAE_REST_LENGTH_ELEMENT1_3); // COLLADA 1.3 backward compatibility
853 			if (param) physicsRigidConstraint->SetSpringLinearTargetValue(FUStringConversion::ToFloat(ReadNodeContentDirect(param)));
854 		}
855 
856 		xmlNode* angularSpring = FindChildByType(spring, DAE_ANGULAR_ELEMENT);
857 		if (angularSpring)
858 		{
859 			xmlNode* param = FindChildByType(angularSpring, DAE_DAMPING_ELEMENT);
860 			if (param) physicsRigidConstraint->SetSpringAngularDamping(FUStringConversion::ToFloat(ReadNodeContentDirect(param)));
861 			param = FindChildByType(angularSpring, DAE_STIFFNESS_ELEMENT);
862 			if (param) physicsRigidConstraint->SetSpringAngularStiffness(FUStringConversion::ToFloat(ReadNodeContentDirect(param)));
863 			param = FindChildByType(angularSpring, DAE_TARGET_VALUE_ELEMENT);
864 			if (!param) param = FindChildByType(angularSpring, DAE_REST_LENGTH_ELEMENT1_3); // COLLADA 1.3 backward compatibility
865 			if (param) physicsRigidConstraint->SetSpringAngularTargetValue(FUStringConversion::ToFloat(ReadNodeContentDirect(param)));
866 		}
867 	}
868 
869 	physicsRigidConstraint->SetDirtyFlag();
870 	return status;
871 }
872 
LoadPhysicsScene(FCDObject * object,xmlNode * sceneNode)873 bool FArchiveXML::LoadPhysicsScene(FCDObject* object, xmlNode* sceneNode)
874 {
875 	if (!FArchiveXML::LoadEntity(object, sceneNode)) return false;
876 
877 	bool status = true;
878 	FCDPhysicsScene* physicsScene = (FCDPhysicsScene*)object;
879 	if (IsEquivalent(sceneNode->name, DAE_PHYSICS_SCENE_ELEMENT))
880 	{
881 		for (xmlNode* child = sceneNode->children; child != NULL; child = child->next)
882 		{
883 			if (child->type != XML_ELEMENT_NODE) continue;
884 
885 			// Look for instantiation elements
886 			if (IsEquivalent(child->name, DAE_INSTANCE_PHYSICS_MODEL_ELEMENT))
887 			{
888 				FCDPhysicsModelInstance* instance = physicsScene->AddPhysicsModelInstance(NULL);
889 				status &= (FArchiveXML::LoadPhysicsModelInstance(instance, child));
890 				continue;
891 			}
892 			else if (IsEquivalent(child->name, DAE_TECHNIQUE_COMMON_ELEMENT))
893 			{
894 				xmlNode* gravityNode = FindChildByType(child, DAE_GRAVITY_ATTRIBUTE);
895 				if (gravityNode)
896 				{
897 					const char* gravityVal = ReadNodeContentDirect(gravityNode);
898 					FMVector3 gravity;
899 					gravity.x = FUStringConversion::ToFloat(&gravityVal);
900 					gravity.y = FUStringConversion::ToFloat(&gravityVal);
901 					gravity.z = FUStringConversion::ToFloat(&gravityVal);
902 					physicsScene->SetGravity(gravity);
903 				}
904 				xmlNode* timestepNode = FindChildByType(child, DAE_TIME_STEP_ATTRIBUTE);
905 				if (timestepNode)
906 				{
907 					physicsScene->SetTimestep(FUStringConversion::ToFloat(ReadNodeContentDirect(timestepNode)));
908 				}
909 			}
910 			else if (IsEquivalent(child->name,
911 					DAE_INSTANCE_FORCE_FIELD_ELEMENT))
912 			{
913 				FCDPhysicsForceFieldInstance* instance = physicsScene->AddForceFieldInstance(NULL);
914 				status &= (FArchiveXML::LoadPhysicsForceFieldInstance(instance, child));
915 			}
916 			else if (IsEquivalent(child->name, DAE_EXTRA_ELEMENT))
917 			{
918 				// The extra information is loaded by the FCDEntity class.
919 			}
920 		}
921 	}
922 
923 	physicsScene->SetDirtyFlag();
924 	return status;
925 }
926 
927