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(¶meters->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(¶meters->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(¶meters->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(¶meters->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(¶meters->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