1 /*
2     Copyright (c) 2015 Starbreeze
3 
4 	This file is part of COLLADAMaya.
5 
6     Portions of the code are:
7     Copyright (c) 2005-2007 Feeling Software Inc.
8     Copyright (c) 2005-2007 Sony Computer Entertainment America
9     Copyright (c) 2004-2005 Alias Systems Corp.
10 
11     Licensed under the MIT Open Source License,
12     for details please see LICENSE file or the website
13     http://www.opensource.org/licenses/mit-license.php
14 */
15 
16 #include "COLLADAMayaStableHeaders.h"
17 
18 #include "COLLADAMayaAttributeParser.h"
19 #include "COLLADAMayaDagHelper.h"
20 #include "COLLADAMayaExportOptions.h"
21 #include "COLLADAMayaGeometryExporter.h"
22 #include "COLLADAMayaPhysXExporter.h"
23 #include "COLLADAMayaRotateHelper.h"
24 #include "COLLADAMayaSceneGraph.h"
25 #include "COLLADAMayaSyntax.h"
26 #include "COLLADAMayaVisualSceneExporter.h"
27 #include "COLLADASWConstants.h"
28 #include "Math/COLLADABUMathUtils.h"
29 
30 #include <libxml/tree.h>
31 #include <maya/MAngle.h>
32 #include <maya/MDistance.h>
33 #include <maya/MFnAttribute.h>
34 #define MNoPluginEntry
35 #define MNoVersionString
36 #include <maya/MFnPlugin.h>
37 #include <maya/MFnTransform.h>
38 #include <maya/MString.h>
39 #include <maya/MTime.h>
40 
infinite()41 double infinite()
42 {
43     union ieee754 {
44         int64_t i;
45         double d;
46     };
47     ieee754 inf;
48     inf.i = 0x7FF0000000000000;
49     return inf.d;
50 }
51 
isInf(double d)52 bool isInf(double d)
53 {
54     return
55         d == infinite() ||
56         d == -infinite();
57 }
58 
59 using namespace COLLADASW;
60 
61 // Note:
62 // Maya matrix: row major vectors, T1 x T2 x T3...
63 // DAE matrix/transforms: column major vectors, ...T3 x T2 x T1
64 // -> reverse order
65 
66 namespace COLLADAMaya
67 {
uiToInternal(const MVector & v)68 	MVector uiToInternal(const MVector & v)
69 	{
70 		return MVector(
71 			MDistance::uiToInternal(v.x),
72 			MDistance::uiToInternal(v.y),
73 			MDistance::uiToInternal(v.z));
74 	}
75 
PxTransformToMMatrix(const MVector & t,const MQuaternion & r)76 	MMatrix PxTransformToMMatrix(const MVector & t, const MQuaternion & r)
77 	{
78 		MTransformationMatrix tm;
79 		tm.setRotationQuaternion(r.x, r.y, r.z, r.w);
80 		tm.setTranslation(uiToInternal(t), MSpace::kTransform);
81 		return tm.asMatrix();
82 	}
83 
84 	const bool withPrefix = true;
85 	const bool withoutPrefix = false;
86 
87     // Helper class used to open and auto close an element.
88     class Element
89     {
90     public:
Element(PhysXExporter & exporter,const String & name,bool elementForm=withoutPrefix)91         Element(PhysXExporter& exporter, const String & name, bool elementForm = withoutPrefix)
92             : mPhysXExporter(exporter)
93         {
94 			if (elementForm == withoutPrefix)
95 			{
96 				mPhysXExporter.getStreamWriter().openElement(name, String());
97 			}
98 			else
99 			{
100 				mPhysXExporter.getStreamWriter().openElement(name, CSWC::CSW_PREFIX_PX);
101 			}
102         }
103 
~Element()104         virtual ~Element()
105         {
106             mPhysXExporter.getStreamWriter().closeElement();
107         }
108 
109     protected:
getStreamWriter()110         StreamWriter& getStreamWriter()
111         {
112             return mPhysXExporter.getStreamWriter();
113         }
114 
getDocumentExporter()115         DocumentExporter& getDocumentExporter()
116         {
117             return mPhysXExporter.getDocumentExporter();
118         }
119 
getPhysXExporter()120         PhysXExporter& getPhysXExporter()
121         {
122             return mPhysXExporter;
123         }
124 
125     private:
126         PhysXExporter& mPhysXExporter;
127     };
128 
129     class AttributeExporter : public AttributeParser
130     {
131     public:
AttributeExporter(PhysXExporter & exporter,const std::set<MString,MStringComp> & attributes)132         AttributeExporter(PhysXExporter& exporter, const std::set<MString, MStringComp> & attributes)
133             : mPhysXExporter(exporter)
134             , mAttributes(attributes)
135         {}
136 
137     protected:
onBeforePlug(MPlug & plug)138 		virtual bool onBeforePlug(MPlug & plug) override
139 		{
140 			MStatus status;
141 
142 			MObject attr = plug.attribute(&status);
143 			if (!status) return false;
144 
145             MFnAttribute fnAttr(attr, &status);
146             if (!status) return false;
147 
148             MString attrName = fnAttr.name(&status);
149             if (!status) return false;
150 
151             std::set<MString, MStringComp>::const_iterator it = mAttributes.find(attrName);
152             if (it == mAttributes.end()) {
153                 return false;
154             }
155 
156             return true;
157         }
158 
onBoolean(MPlug & plug,const MString & name,bool value)159         virtual void onBoolean(MPlug & plug, const MString & name, bool value) override
160         {
161             String nameStr(name.asChar());
162             Element e(mPhysXExporter, nameStr);
163             mPhysXExporter.getStreamWriter().appendValues(value);
164         }
165 
onByte(MPlug & plug,const MString & name,char value)166         virtual void onByte(MPlug & plug, const MString & name, char value) override
167         {
168             String nameStr(name.asChar());
169 			const size_t size = 5;
170 			char text[size];
171 			snprintf(text, size, "0x%X", value);
172             Element e(mPhysXExporter, nameStr);
173             mPhysXExporter.getStreamWriter().appendValues(text);
174         }
175 
onChar(MPlug & plug,const MString & name,char value)176         virtual void onChar(MPlug & plug, const MString & name, char value) override
177         {
178             String nameStr(name.asChar());
179             char text[] = { value, '\0' };
180             Element e(mPhysXExporter, nameStr);
181             mPhysXExporter.getStreamWriter().appendValues(text);
182         }
183 
onShort(MPlug & plug,const MString & name,short value)184         virtual void onShort(MPlug & plug, const MString & name, short value) override
185         {
186             String nameStr(name.asChar());
187             Element e(mPhysXExporter, nameStr);
188             mPhysXExporter.getStreamWriter().appendValues(value);
189         }
190 
onShort2(MPlug & plug,const MString & name,short value[2])191         virtual void onShort2(MPlug & plug, const MString & name, short value[2]) override
192         {
193             String nameStr(name.asChar());
194             int values[3] = { value[0], value[1] };
195             Element e(mPhysXExporter, nameStr);
196             mPhysXExporter.getStreamWriter().appendValues(values, 2);
197         }
198 
onShort3(MPlug & plug,const MString & name,short value[3])199         virtual void onShort3(MPlug & plug, const MString & name, short value[3]) override
200         {
201 
202             String nameStr(name.asChar());
203             int values[3] = { value[0], value[1], value[2] };
204             Element e(mPhysXExporter, nameStr);
205             mPhysXExporter.getStreamWriter().appendValues(values, 3);
206         }
207 
onInteger(MPlug & plug,const MString & name,int value)208         virtual void onInteger(MPlug & plug, const MString & name, int value) override
209         {
210             String nameStr(name.asChar());
211             Element e(mPhysXExporter, nameStr);
212             mPhysXExporter.getStreamWriter().appendValues(value);
213         }
214 
onInteger2(MPlug & plug,const MString & name,int value[2])215         virtual void onInteger2(MPlug & plug, const MString & name, int value[2]) override
216         {
217             String nameStr(name.asChar());
218             Element e(mPhysXExporter, nameStr);
219             mPhysXExporter.getStreamWriter().appendValues(value, 2);
220         }
221 
onInteger3(MPlug & plug,const MString & name,int value[3])222         virtual void onInteger3(MPlug & plug, const MString & name, int value[3]) override
223         {
224             String nameStr(name.asChar());
225             Element e(mPhysXExporter, nameStr);
226             mPhysXExporter.getStreamWriter().appendValues(value, 3);
227         }
228 
onFloat(MPlug & plug,const MString & name,float value)229         virtual void onFloat(MPlug & plug, const MString & name, float value) override
230         {
231             String nameStr(name.asChar());
232             Element e(mPhysXExporter, nameStr);
233             mPhysXExporter.getStreamWriter().appendValues(value);
234         }
235 
onFloat2(MPlug & plug,const MString & name,float value[2])236         virtual void onFloat2(MPlug & plug, const MString & name, float value[2]) override
237         {
238             String nameStr(name.asChar());
239             Element e(mPhysXExporter, nameStr);
240             mPhysXExporter.getStreamWriter().appendValues(value, 2);
241         }
242 
onFloat3(MPlug & plug,const MString & name,float value[3])243         virtual void onFloat3(MPlug & plug, const MString & name, float value[3]) override
244         {
245             String nameStr(name.asChar());
246             Element e(mPhysXExporter, nameStr);
247             mPhysXExporter.getStreamWriter().appendValues(value, 3);
248         }
249 
onDouble(MPlug & plug,const MString & name,double value)250         virtual void onDouble(MPlug & plug, const MString & name, double value) override
251         {
252             String nameStr(name.asChar());
253             Element e(mPhysXExporter, nameStr);
254             mPhysXExporter.getStreamWriter().appendValues(value);
255         }
256 
onDouble2(MPlug & plug,const MString & name,double value[2])257         virtual void onDouble2(MPlug & plug, const MString & name, double value[2]) override
258         {
259             String nameStr(name.asChar());
260             Element e(mPhysXExporter, nameStr);
261             mPhysXExporter.getStreamWriter().appendValues(value, 2);
262         }
263 
onDouble3(MPlug & plug,const MString & name,double value[3])264         virtual void onDouble3(MPlug & plug, const MString & name, double value[3]) override
265         {
266             String nameStr(name.asChar());
267             Element e(mPhysXExporter, nameStr);
268             mPhysXExporter.getStreamWriter().appendValues(value, 3);
269         }
270 
onDouble4(MPlug & plug,const MString & name,double value[4])271         virtual void onDouble4(MPlug & plug, const MString & name, double value[4]) override
272         {
273             String nameStr(name.asChar());
274             Element e(mPhysXExporter, nameStr);
275             mPhysXExporter.getStreamWriter().appendValues(value, 4);
276         }
277 
onString(MPlug & plug,const MString & name,const MString & value)278         virtual void onString(MPlug & plug, const MString & name, const MString & value) override
279         {
280             String nameStr(name.asChar());
281             Element e(mPhysXExporter, nameStr);
282             mPhysXExporter.getStreamWriter().appendText(value.asChar());
283         }
284 
onEnum(MPlug & plug,const MString & name,int enumValue,const MString & enumName)285         virtual void onEnum(MPlug & plug, const MString & name, int enumValue, const MString & enumName) override
286         {
287             String nameStr(name.asChar());
288             Element e(mPhysXExporter, nameStr);
289             mPhysXExporter.getStreamWriter().appendText(enumName.asChar());
290         }
291 
onMesh(MPlug & plug,const MString & name,MObject & meshObject)292         virtual void onMesh(MPlug & plug, const MString & name, MObject & meshObject) override
293         {
294             String nameStr(name.asChar());
295             URI meshURI;
296             mPhysXExporter.getMeshURI(meshObject, meshURI);
297             Element e(mPhysXExporter, nameStr);
298             mPhysXExporter.getStreamWriter().appendURIAttribute(CSWC::CSW_ATTRIBUTE_URL, meshURI);
299         }
300 
onAngle(MPlug & plug,const MString & name,const MAngle & angle)301         virtual void onAngle(MPlug & plug, const MString & name, const MAngle & angle) override
302         {
303             String nameStr(name.asChar());
304             Element e(mPhysXExporter, nameStr);
305             mPhysXExporter.getStreamWriter().appendValues(
306                 angle.asDegrees());
307         }
308 
onAngle2(MPlug & plug,const MString & name,const MAngle angle[2])309         virtual void onAngle2(MPlug & plug, const MString & name, const MAngle angle[2]) override
310         {
311             String nameStr(name.asChar());
312             Element e(mPhysXExporter, nameStr);
313             mPhysXExporter.getStreamWriter().appendValues(
314                 angle[0].asDegrees(),
315                 angle[1].asDegrees());
316         }
317 
onAngle3(MPlug & plug,const MString & name,const MAngle angle[3])318         virtual void onAngle3(MPlug & plug, const MString & name, const MAngle angle[3]) override
319         {
320             String nameStr(name.asChar());
321             Element e(mPhysXExporter, nameStr);
322             mPhysXExporter.getStreamWriter().appendValues(
323                 angle[0].asDegrees(),
324                 angle[1].asDegrees(),
325                 angle[2].asDegrees());
326         }
327 
onAngle4(MPlug & plug,const MString & name,const MAngle angle[4])328         virtual void onAngle4(MPlug & plug, const MString & name, const MAngle angle[4]) override
329         {
330             String nameStr(name.asChar());
331             Element e(mPhysXExporter, nameStr);
332             mPhysXExporter.getStreamWriter().appendValues(
333                 angle[0].asDegrees(),
334                 angle[1].asDegrees(),
335                 angle[2].asDegrees(),
336                 angle[3].asDegrees());
337         }
338 
onDistance(MPlug & plug,const MString & name,const MDistance & distance)339         virtual void onDistance(MPlug & plug, const MString & name, const MDistance & distance) override
340         {
341             String nameStr(name.asChar());
342             Element e(mPhysXExporter, nameStr);
343             mPhysXExporter.getStreamWriter().appendValues(
344                 MDistance::internalToUI(distance.asCentimeters()));
345         }
346 
onDistance2(MPlug & plug,const MString & name,const MDistance distance[2])347         virtual void onDistance2(MPlug & plug, const MString & name, const MDistance distance[2]) override
348         {
349             String nameStr(name.asChar());
350             Element e(mPhysXExporter, nameStr);
351             mPhysXExporter.getStreamWriter().appendValues(
352                 MDistance::internalToUI(distance[0].asCentimeters()),
353                 MDistance::internalToUI(distance[1].asCentimeters()));
354         }
355 
onDistance3(MPlug & plug,const MString & name,const MDistance distance[3])356         virtual void onDistance3(MPlug & plug, const MString & name, const MDistance distance[3]) override
357         {
358             String nameStr(name.asChar());
359             Element e(mPhysXExporter, nameStr);
360             mPhysXExporter.getStreamWriter().appendValues(
361                 MDistance::internalToUI(distance[0].asCentimeters()),
362                 MDistance::internalToUI(distance[1].asCentimeters()),
363                 MDistance::internalToUI(distance[2].asCentimeters()));
364         }
365 
onDistance4(MPlug & plug,const MString & name,const MDistance distance[4])366         virtual void onDistance4(MPlug & plug, const MString & name, const MDistance distance[4]) override
367         {
368             String nameStr(name.asChar());
369             Element e(mPhysXExporter, nameStr);
370             mPhysXExporter.getStreamWriter().appendValues(
371                 MDistance::internalToUI(distance[0].asCentimeters()),
372                 MDistance::internalToUI(distance[1].asCentimeters()),
373                 MDistance::internalToUI(distance[2].asCentimeters()),
374                 MDistance::internalToUI(distance[3].asCentimeters()));
375         }
376 
onTime(MPlug & plug,const MString & name,MTime & time)377         virtual void onTime(MPlug & plug, const MString & name, MTime & time) override
378         {
379             String nameStr(name.asChar());
380             Element e(mPhysXExporter, nameStr);
381             mPhysXExporter.getStreamWriter().appendValues(time.as(MTime::kSeconds));
382         }
383 
384     private:
385         PhysXExporter& mPhysXExporter;
386         const std::set<MString, MStringComp>& mAttributes;
387         int mAttributeLevel;
388     };
389 
GetType(const MObject & shape,MString & type)390     void PhysXShape::GetType(const MObject & shape, MString & type)
391     {
392         int dummy = 0;
393         DagHelper::getPlugValue(shape, ATTR_SHAPE_TYPE, dummy, type);
394     }
395 
GetInMesh(const MObject & shape,MObject & mesh)396     void PhysXShape::GetInMesh(const MObject & shape, MObject & mesh)
397     {
398         DagHelper::getPlugValue(shape, ATTR_IN_MESH, mesh);
399     }
400 
GetConnectedInMesh(const MObject & shape,MObject & mesh)401     void PhysXShape::GetConnectedInMesh(const MObject & shape, MObject & mesh)
402     {
403         PhysXExporter::GetPluggedObject(shape, ATTR_IN_MESH, mesh);
404     }
405 
findPxMaterial(const MObject & rigidBody) const406     const PhysXXML::PxMaterial* PhysXExporter::findPxMaterial(const MObject & rigidBody) const
407     {
408 		std::map<MObject, const PhysXXML::PxMaterial*>::const_iterator it = mRigidBodyToPxMaterialMap.find(rigidBody);
409 		if (it != mRigidBodyToPxMaterialMap.end())
410 		{
411 			return it->second;
412 		}
413 		return NULL;
414     }
415 
findPxMaterial(uint64_t ref) const416 	const PhysXXML::PxMaterial* PhysXExporter::findPxMaterial(uint64_t ref) const
417     {
418         return mPhysXDoc->findMaterial(ref);
419     }
420 
findPxMaterial(const PhysXXML::PxRigidBody & rigidBody) const421 	const PhysXXML::PxMaterial* PhysXExporter::findPxMaterial(const PhysXXML::PxRigidBody & rigidBody) const
422 	{
423 		if (rigidBody.shapes.shapes.size() > 0)
424 		{
425 			return findPxMaterial(rigidBody.shapes.shapes[0].materials.materialRef.materialRef);
426 		}
427 		return NULL;
428 	}
429 
findPxShape(const MObject & shape) const430 	const PhysXXML::PxShape* PhysXExporter::findPxShape(const MObject & shape) const
431 	{
432 		std::map<MObject, const PhysXXML::PxShape*>::const_iterator it = mShapeToPxShapeMap.find(shape);
433 		if (it != mShapeToPxShapeMap.end())
434 		{
435 			return it->second;
436 		}
437 		return NULL;
438 	}
439 
findPxRigidBody(const MObject & rigidBody) const440 	const PhysXXML::PxRigidBody* PhysXExporter::findPxRigidBody(const MObject & rigidBody) const
441 	{
442 		std::map<MObject, const PhysXXML::PxRigidBody*>::const_iterator it = mRigidBodyToPxRigidBodyMap.find(rigidBody);
443 		if (it != mRigidBodyToPxRigidBodyMap.end())
444 		{
445 			return it->second;
446 		}
447 		return NULL;
448 	}
449 
findPxRigidBody(const String & name) const450 	const PhysXXML::PxRigidBody* PhysXExporter::findPxRigidBody(const String & name) const
451 	{
452 		return mPhysXDoc->findRigidBody(name);
453 	}
454 
findPxRigidBody(uint64_t id) const455 	const PhysXXML::PxRigidBody* PhysXExporter::findPxRigidBody(uint64_t id) const
456 	{
457 		return mPhysXDoc->findRigidBody(id);
458 	}
459 
findPxD6Joint(const MObject & rigidConstraint) const460     const PhysXXML::PxD6Joint* PhysXExporter::findPxD6Joint(const MObject & rigidConstraint) const
461     {
462 		std::map<MObject, const PhysXXML::PxD6Joint*>::const_iterator it = mConstraintToPxD6JointMap.find(rigidConstraint);
463 		if (it != mConstraintToPxD6JointMap.end())
464 		{
465 			return it->second;
466 		}
467 		return NULL;
468     }
469 
findMObject(const PhysXXML::PxRigidBody & rigidBody) const470 	const MObject & PhysXExporter::findMObject(const PhysXXML::PxRigidBody & rigidBody) const
471 	{
472 		std::map<const PhysXXML::PxRigidBody*, MObject>::const_iterator it = mPxRigidBodyToRigidBodyMap.find(&rigidBody);
473 		if (it != mPxRigidBodyToRigidBodyMap.end())
474 		{
475 			return it->second;
476 		}
477 		return MObject::kNullObj;
478 	}
479 
findMObject(const PhysXXML::PxShape & shape) const480 	const MObject & PhysXExporter::findMObject(const PhysXXML::PxShape & shape) const
481 	{
482 		std::map<const PhysXXML::PxShape*, MObject>::const_iterator it = mPxShapeToShapeMap.find(&shape);
483 		if (it != mPxShapeToShapeMap.end())
484 		{
485 			return it->second;
486 		}
487 		return MObject::kNullObj;
488 	}
489 
findMObject(const PhysXXML::PxD6Joint & joint) const490 	const MObject & PhysXExporter::findMObject(const PhysXXML::PxD6Joint & joint) const
491 	{
492 		std::map<const PhysXXML::PxD6Joint*, MObject>::const_iterator it = mPxD6JointToConstraintMap.find(&joint);
493 		if (it != mPxD6JointToConstraintMap.end())
494 		{
495 			return it->second;
496 		}
497 		return MObject::kNullObj;
498 	}
499 
getNodeRigidBody(const MObject & node) const500 	const MObject & PhysXExporter::getNodeRigidBody(const MObject& node) const
501 	{
502 		std::map<MObject, MObject>::const_iterator it = mTargetToRigidBodyMap.find(node);
503 		if (it != mTargetToRigidBodyMap.end())
504 		{
505 			return it->second;
506 		}
507 		return MObject::kNullObj;
508 	}
509 
getShapeLocalPose(const MObject & shape,MMatrix & localPose) const510     void PhysXExporter::getShapeLocalPose(/*const MObject& rigidBody, */const MObject& shape, MMatrix& localPose) const
511     {
512         const PhysXXML::PxShape* pxShape = findPxShape(/*rigidBody, */shape);
513         if (!pxShape)
514             return;
515 		localPose = PxTransformToMMatrix(pxShape->localPose.translation, pxShape->localPose.rotation);
516     }
517 
getShapeVertices(const MObject & shape,std::vector<PhysXXML::Point> & vertices,MString & meshId)518 	bool PhysXExporter::getShapeVertices(const MObject& shape, std::vector<PhysXXML::Point> & vertices, MString & meshId)
519     {
520 		const PhysXXML::PxShape* pxShape = findPxShape(shape);
521         if (pxShape == NULL) return false;
522 
523 		if (pxShape->geometry.type == PhysXXML::Geometry::ConvexMesh)
524         {
525 			if (PhysXXML::PxConvexMesh* convexMesh = mPhysXDoc->findConvexMesh(pxShape->geometry.convexMeshGeometry.convexMesh.convexMesh))
526             {
527                 vertices = convexMesh->points.points;
528                 std::stringstream s;
529                 s << "_" << convexMesh->id.id;
530                 meshId = s.str().c_str();
531                 return true;
532             }
533         }
534 		else if (pxShape->geometry.type == PhysXXML::Geometry::TriangleMesh)
535         {
536 			if (PhysXXML::PxTriangleMesh* triangleMesh = mPhysXDoc->findTriangleMesh(pxShape->geometry.triangleMeshGeometry.triangleMesh.triangleMesh))
537             {
538                 vertices = triangleMesh->points.points;
539                 std::stringstream s;
540                 s << "_" << triangleMesh->id.id;
541                 meshId = s.str().c_str();
542                 return true;
543             }
544         }
545         return false;
546     }
547 
getShapeTriangles(const MObject & shape,std::vector<PhysXXML::Triangle> & triangles)548 	bool PhysXExporter::getShapeTriangles(const MObject& shape, std::vector<PhysXXML::Triangle> & triangles)
549     {
550 		const PhysXXML::PxShape* pxShape = findPxShape(shape);
551         if (pxShape == NULL) return false;
552 
553 		if (pxShape->geometry.type == PhysXXML::Geometry::TriangleMesh)
554         {
555 			if (PhysXXML::PxTriangleMesh* triangleMesh = mPhysXDoc->findTriangleMesh(pxShape->geometry.triangleMeshGeometry.triangleMesh.triangleMesh))
556             {
557                 triangles = triangleMesh->triangles.triangles;
558                 return true;
559             }
560         }
561         return false;
562     }
563 
getRigidBodyGlobalPose(const MObject & rigidBody,MMatrix & globalPose)564     void PhysXExporter::getRigidBodyGlobalPose(const MObject& rigidBody, MMatrix& globalPose)
565     {
566 		if (const PhysXXML::PxRigidBody* pxRigidBody = findPxRigidBody(rigidBody))
567 		{
568 			globalPose = PxTransformToMMatrix(pxRigidBody->globalPose.translation, pxRigidBody->globalPose.rotation);
569 		}
570     }
571 
getRigidSolver() const572     const MObject & PhysXExporter::getRigidSolver() const
573     {
574 		return mRigidSolver;
575     }
576 
577     class Dynamic : public Element
578     {
579     public:
Dynamic(PhysXExporter & exporter,bool value)580         Dynamic(PhysXExporter& exporter, bool value)
581             : Element(exporter, CSWC::CSW_ELEMENT_RIGID_BODY_DYNAMIC)
582         {
583             getStreamWriter().appendValues(value);
584         }
585     };
586 
587     class Mass : public Element
588     {
589     public:
Mass(PhysXExporter & exporter,double mass)590         Mass(PhysXExporter& exporter, double mass)
591             : Element(exporter, CSWC::CSW_ELEMENT_RIGID_BODY_MASS)
592         {
593             getStreamWriter().appendValues(mass);
594         }
595     };
596 
597     class MassFrame : public Element
598     {
599     public:
MassFrame(PhysXExporter & exporter,const MVector & t,const MQuaternion & r,const String & tSid="",const String & rSid="")600 		MassFrame(PhysXExporter& exporter, const MVector & t, const MQuaternion & r, const String & tSid = "", const String & rSid = "")
601             : Element(exporter, CSWC::CSW_ELEMENT_RIGID_BODY_MASS_FRAME)
602         {
603 			getPhysXExporter().exportTranslationWithoutConversion(t, tSid);
604 			getPhysXExporter().exportRotation(r.asEulerRotation(), rSid);
605         }
606 
AreDefaultValues(PhysXExporter & exporter,const MVector & t,const MQuaternion & r)607 		static bool AreDefaultValues(PhysXExporter & exporter, const MVector & t, const MQuaternion & r)
608 		{
609 			bool zero_translation =
610 				COLLADABU::Math::Utils::equalsZero(t.x, exporter.getDocumentExporter().getTolerance()) &&
611 				COLLADABU::Math::Utils::equalsZero(t.y, exporter.getDocumentExporter().getTolerance()) &&
612 				COLLADABU::Math::Utils::equalsZero(t.z, exporter.getDocumentExporter().getTolerance());
613 
614 			RotateHelper rotation(r.asEulerRotation());
615 			bool zero_rotation = rotation.isIdentity(exporter.getDocumentExporter().getTolerance());
616 
617 			return zero_translation && zero_rotation;
618 		}
619     };
620 
621     class Inertia : public Element
622     {
623     public:
Inertia(PhysXExporter & exporter,const MVector & inertia)624         Inertia(PhysXExporter& exporter, const MVector & inertia)
625             : Element(exporter, CSWC::CSW_ELEMENT_RIGID_BODY_INERTIA)
626         {
627             getStreamWriter().appendValues(inertia.x, inertia.y, inertia.z);
628         }
629     };
630 
631     class Restitution : public Element
632     {
633     public:
Restitution(PhysXExporter & exporter,double restitution)634         Restitution(PhysXExporter& exporter, double restitution)
635             : Element(exporter, CSWC::CSW_ELEMENT_RESTITUTION)
636         {
637             getStreamWriter().appendValues(restitution);
638         }
639 
DefaultValue()640 		static double DefaultValue()
641 		{
642 			return 0.0;
643 		}
644     };
645 
646     class DynamicFriction : public Element
647     {
648     public:
DynamicFriction(PhysXExporter & exporter,double dynamicFriction)649         DynamicFriction(PhysXExporter& exporter, double dynamicFriction)
650             : Element(exporter, CSWC::CSW_ELEMENT_DYNAMIC_FRICTION)
651         {
652             getStreamWriter().appendValues(dynamicFriction);
653         }
654 
DefaultValue()655 		static double DefaultValue()
656 		{
657 			return 0.0;
658 		}
659     };
660 
661     class StaticFriction : public Element
662     {
663     public:
StaticFriction(PhysXExporter & exporter,double staticFriction)664         StaticFriction(PhysXExporter& exporter, double staticFriction)
665             : Element(exporter, CSWC::CSW_ELEMENT_STATIC_FRICTION)
666         {
667             getStreamWriter().appendValues(staticFriction);
668         }
669 
DefaultValue()670 		static double DefaultValue()
671 		{
672 			return 0.0;
673 		}
674     };
675 
676 	class FrictionCombineMode : public Element
677 	{
678 	public:
FrictionCombineMode(PhysXExporter & exporter,const PhysXXML::CombineMode::FlagEnum & combineMode)679 		FrictionCombineMode(PhysXExporter & exporter, const PhysXXML::CombineMode::FlagEnum & combineMode)
680 			: Element(exporter, CSWC::CSW_ELEMENT_FRICTION_COMBINE_MODE, withPrefix)
681 		{
682 			getStreamWriter().appendValues(PhysXExporter::CombineModeToCOLLADA(combineMode));
683 		}
684 
DefaultValue()685 		static PhysXXML::CombineMode::FlagEnum DefaultValue()
686 		{
687 			return PhysXXML::CombineMode::Average;
688 		}
689 	};
690 
691 	class RestitutionCombineMode : public Element
692 	{
693 	public:
RestitutionCombineMode(PhysXExporter & exporter,const PhysXXML::CombineMode::FlagEnum & combineMode)694 		RestitutionCombineMode(PhysXExporter & exporter, const PhysXXML::CombineMode::FlagEnum & combineMode)
695 			: Element(exporter, CSWC::CSW_ELEMENT_RESTITUTION_COMBINE_MODE, withPrefix)
696 		{
697 			getStreamWriter().appendValues(PhysXExporter::CombineModeToCOLLADA(combineMode));
698 		}
699 
DefaultValue()700 		static PhysXXML::CombineMode::FlagEnum DefaultValue()
701 		{
702 			return PhysXXML::CombineMode::Average;
703 		}
704 	};
705 
706 	class PxMaterial : public Element
707 	{
708 	public:
PxMaterial(PhysXExporter & exporter,const PhysXXML::PxMaterial & mat)709 		PxMaterial(PhysXExporter & exporter, const PhysXXML::PxMaterial & mat)
710 			: Element(exporter, CSWC::CSW_ELEMENT_PX_MATERIAL, withPrefix)
711 		{
712 			exportFrictionCombineMode(mat);
713 			exportRestitutionCombineMode(mat);
714 		}
715 
HasDefaultValues(const PhysXXML::PxMaterial & mat)716 		static bool HasDefaultValues(const PhysXXML::PxMaterial & mat)
717 		{
718 			return
719 				mat.frictionCombineMode.frictionCombineMode == FrictionCombineMode::DefaultValue() &&
720 				mat.restitutionCombineMode.restitutionCombineMode == RestitutionCombineMode::DefaultValue();
721 		}
722 
723 	private:
exportFrictionCombineMode(const PhysXXML::PxMaterial & mat)724 		void exportFrictionCombineMode(const PhysXXML::PxMaterial & mat)
725 		{
726 			if (mat.frictionCombineMode.frictionCombineMode != FrictionCombineMode::DefaultValue())
727 			{
728 				FrictionCombineMode e(getPhysXExporter(), mat.frictionCombineMode.frictionCombineMode);
729 			}
730 		}
731 
exportRestitutionCombineMode(const PhysXXML::PxMaterial & mat)732 		void exportRestitutionCombineMode(const PhysXXML::PxMaterial & mat)
733 		{
734 			if (mat.restitutionCombineMode.restitutionCombineMode != RestitutionCombineMode::DefaultValue())
735 			{
736 				RestitutionCombineMode e(getPhysXExporter(), mat.restitutionCombineMode.restitutionCombineMode);
737 			}
738 		}
739 	};
740 
741     class PhysicsMaterialTechnique : public Element
742     {
743     public:
PhysicsMaterialTechnique(PhysXExporter & exporter,const PhysXXML::PxMaterial & material,const String & profile)744 		PhysicsMaterialTechnique(PhysXExporter& exporter, const PhysXXML::PxMaterial & material, const String& profile)
745             : Element(exporter, CSWC::CSW_ELEMENT_TECHNIQUE)
746         {
747             getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_PROFILE, profile);
748 			getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_XMLNS + ":" + CSWC::CSW_PREFIX_PX, PhysXExporter::GetXMLNS());
749 			getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_XSI_SCHEMALOCATION, PhysXExporter::GetXSISchemaLocation());
750 			if (profile == PhysXExporter::GetPhysXProfile())
751 			{
752 				exportPxMaterial(material);
753 			}
754         }
755 
HasDefaultValues(const PhysXXML::PxMaterial & mat,const String & profile)756 		static bool HasDefaultValues(const PhysXXML::PxMaterial & mat, const String & profile)
757 		{
758 			if (profile == PhysXExporter::GetPhysXProfile())
759 			{
760 				return PxMaterial::HasDefaultValues(mat);
761 			}
762 			return false;
763 		}
764 
765 	private:
exportPxMaterial(const PhysXXML::PxMaterial & mat)766 		void exportPxMaterial(const PhysXXML::PxMaterial & mat)
767 		{
768 			if (!PxMaterial::HasDefaultValues(mat))
769 			{
770 				PxMaterial e(getPhysXExporter(), mat);
771 			}
772 		}
773     };
774 
775     class PhysicsMaterialExtra : public Element
776     {
777     public:
PhysicsMaterialExtra(PhysXExporter & exporter,const PhysXXML::PxMaterial & material)778 		PhysicsMaterialExtra(PhysXExporter& exporter, const PhysXXML::PxMaterial & material)
779             : Element(exporter, CSWC::CSW_ELEMENT_EXTRA)
780         {
781 			exportTechnique(material, PhysXExporter::GetPhysXProfile());
782         }
783 
HasDefaultValues(const PhysXXML::PxMaterial & mat)784 		static bool HasDefaultValues(const PhysXXML::PxMaterial & mat)
785 		{
786 			return PhysicsMaterialTechnique::HasDefaultValues(mat, PhysXExporter::GetPhysXProfile());
787 		}
788 
789     private:
exportTechnique(const PhysXXML::PxMaterial & material,const String & profile)790 		void exportTechnique(const PhysXXML::PxMaterial & material, const String & profile)
791 		{
792 			if (!PhysicsMaterialTechnique::HasDefaultValues(material, profile))
793 			{
794 				PhysicsMaterialTechnique e(getPhysXExporter(), material, profile);
795 			}
796 		}
797 
deprecated_exportTechnique(const PhysXXML::PxMaterial & material,const String & profile)798 		void deprecated_exportTechnique(const PhysXXML::PxMaterial & material, const String& profile)
799         {
800 			if (!PhysicsMaterialTechnique::HasDefaultValues(material, profile))
801 			{
802 				PhysicsMaterialTechnique e(getPhysXExporter(), material, profile);
803 			}
804         }
805     };
806 
807     class PhysicsMaterialTechniqueCommon : public Element
808     {
809     public:
PhysicsMaterialTechniqueCommon(PhysXExporter & exporter,const PhysXXML::PxMaterial & material)810 		PhysicsMaterialTechniqueCommon(PhysXExporter& exporter, const PhysXXML::PxMaterial & material)
811             : Element(exporter, CSWC::CSW_ELEMENT_TECHNIQUE_COMMON)
812         {
813 			exportDynamicFriction(material);
814             exportRestitution(material);
815             exportStaticFriction(material);
816         }
817 
818     private:
exportRestitution(const PhysXXML::PxMaterial & material)819 		void exportRestitution(const PhysXXML::PxMaterial & material)
820         {
821 			if (material.restitution.restitution != Restitution::DefaultValue())
822 			{
823 				Restitution e(getPhysXExporter(), material.restitution.restitution);
824 			}
825         }
826 
exportDynamicFriction(const PhysXXML::PxMaterial & material)827 		void exportDynamicFriction(const PhysXXML::PxMaterial & material)
828         {
829 			if (material.dynamicFriction.dynamicFriction != DynamicFriction::DefaultValue())
830 			{
831 				DynamicFriction e(getPhysXExporter(), material.dynamicFriction.dynamicFriction);
832 			}
833         }
834 
exportStaticFriction(const PhysXXML::PxMaterial & material)835 		void exportStaticFriction(const PhysXXML::PxMaterial & material)
836         {
837 			if (material.staticFriction.staticFriction != StaticFriction::DefaultValue())
838 			{
839 				StaticFriction e(getPhysXExporter(), material.staticFriction.staticFriction);
840 			}
841         }
842     };
843 
844     class PhysicsMaterial : public Element
845     {
846     public:
PhysicsMaterial(PhysXExporter & exporter,const PhysXXML::PxMaterial & material,const String & id)847 		PhysicsMaterial(PhysXExporter& exporter, const PhysXXML::PxMaterial & material, const String & id)
848             : Element(exporter, CSWC::CSW_ELEMENT_PHYSICS_MATERIAL)
849         {
850             getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_ID, id);
851 
852 			exportTechniqueCommon(material);
853 			exportExtra(material);
854         }
855 
856     private:
exportTechniqueCommon(const PhysXXML::PxMaterial & material)857 		void exportTechniqueCommon(const PhysXXML::PxMaterial & material)
858         {
859             PhysicsMaterialTechniqueCommon e(getPhysXExporter(), material);
860         }
861 
exportExtra(const PhysXXML::PxMaterial & material)862 		void exportExtra(const PhysXXML::PxMaterial & material)
863         {
864 			if (!PhysicsMaterialExtra::HasDefaultValues(material))
865 			{
866 				PhysicsMaterialExtra e(getPhysXExporter(), material);
867 			}
868         }
869     };
870 
871     class Hollow : public Element
872     {
873     public:
Hollow(PhysXExporter & exporter,bool hollow)874         Hollow(PhysXExporter& exporter, bool hollow)
875             : Element(exporter, CSWC::CSW_ELEMENT_HOLLOW)
876         {
877             getStreamWriter().appendValues(hollow);
878         }
879     };
880 
881     class HalfExtents : public Element
882     {
883     public:
HalfExtents(PhysXExporter & exporter,const MVector & halfExtents)884         HalfExtents(PhysXExporter& exporter, const MVector & halfExtents)
885             : Element(exporter, CSWC::CSW_ELEMENT_RIGID_BODY_SHAPE_BOX_EXTENTS)
886         {
887             getStreamWriter().appendValues(halfExtents.x, halfExtents.y, halfExtents.z);
888         }
889     };
890 
891     class ShapeBox : public Element
892     {
893     public:
ShapeBox(PhysXExporter & exporter,const PhysXXML::PxShape & shape)894 		ShapeBox(PhysXExporter& exporter, const PhysXXML::PxShape & shape)
895             : Element(exporter, CSWC::CSW_ELEMENT_RIGID_BODY_SHAPE_BOX)
896         {
897             exportHalfExtents(shape);
898         }
899 
900     private:
exportHalfExtents(const PhysXXML::PxShape & shape)901 		void exportHalfExtents(const PhysXXML::PxShape & shape)
902         {
903 			HalfExtents e(getPhysXExporter(), shape.geometry.boxGeometry.halfExtents.halfExtents);
904         }
905     };
906 
907     class CapsuleRadius : public Element
908     {
909     public:
CapsuleRadius(PhysXExporter & exporter,double radiusX,double radiusZ)910         CapsuleRadius(PhysXExporter& exporter, double radiusX, double radiusZ)
911             : Element(exporter, CSWC::CSW_ELEMENT_RIGID_BODY_SHAPE_CAPSULE_RADIUS)
912         {
913             getStreamWriter().appendValues(radiusX, radiusZ);
914         }
915     };
916 
917     class SphereRadius : public Element
918     {
919     public:
SphereRadius(PhysXExporter & exporter,double radius)920         SphereRadius(PhysXExporter& exporter, double radius)
921             : Element(exporter, CSWC::CSW_ELEMENT_RIGID_BODY_SHAPE_CAPSULE_RADIUS)
922         {
923             getStreamWriter().appendValues(radius);
924         }
925     };
926 
927     class ShapeSphere : public Element
928     {
929     public:
ShapeSphere(PhysXExporter & exporter,const PhysXXML::PxShape & shape)930 		ShapeSphere(PhysXExporter& exporter, const PhysXXML::PxShape & shape)
931             : Element(exporter, CSWC::CSW_ELEMENT_RIGID_BODY_SHAPE_SPHERE)
932         {
933             exportRadius(shape);
934         }
935 
936     private:
exportRadius(const PhysXXML::PxShape & shape)937 		void exportRadius(const PhysXXML::PxShape & shape)
938         {
939 			SphereRadius e(getPhysXExporter(), shape.geometry.sphereGeometry.radius.radius);
940         }
941     };
942 
943     class Height : public Element
944     {
945     public:
Height(PhysXExporter & exporter,double height)946         Height(PhysXExporter& exporter, double height)
947             : Element(exporter, CSWC::CSW_ELEMENT_RIGID_BODY_SHAPE_CAPSULE_HEIGHT)
948         {
949             getStreamWriter().appendValues(height);
950         }
951     };
952 
953     class ShapeCapsule : public Element
954     {
955     public:
ShapeCapsule(PhysXExporter & exporter,const PhysXXML::PxShape & shape)956 		ShapeCapsule(PhysXExporter& exporter, const PhysXXML::PxShape & shape)
957             : Element(exporter, CSWC::CSW_ELEMENT_RIGID_BODY_SHAPE_CAPSULE)
958         {
959 			exportHeight(shape);
960 			exportRadius(shape);
961         }
962 
963     private:
exportRadius(const PhysXXML::PxShape & shape)964 		void exportRadius(const PhysXXML::PxShape & shape)
965         {
966             CapsuleRadius e(getPhysXExporter(), shape.geometry.capsuleGeometry.radius.radius, shape.geometry.capsuleGeometry.radius.radius);
967         }
968 
exportHeight(const PhysXXML::PxShape & shape)969 		void exportHeight(const PhysXXML::PxShape & shape)
970         {
971 			Height e(getPhysXExporter(), shape.geometry.capsuleGeometry.halfHeight.halfHeight * 2.0);
972         }
973     };
974 
975 	class Equation : public Element
976 	{
977 	public:
Equation(PhysXExporter & exporter,double a,double b,double c,double d)978 		Equation(PhysXExporter& exporter, double a, double b, double c, double d)
979 			: Element(exporter, CSWC::CSW_ELEMENT_RIGID_BODY_SHAPE_PLANE_EQUATION)
980 		{
981 			getStreamWriter().appendValues(a, b, c, d);
982 		}
983 	};
984 
985 	class ShapePlane : public Element
986 	{
987 	public:
ShapePlane(PhysXExporter & exporter,double a,double b,double c,double d)988 		ShapePlane(PhysXExporter& exporter, double a, double b, double c, double d)
989 			: Element(exporter, CSWC::CSW_ELEMENT_RIGID_BODY_SHAPE_PLANE)
990 		{
991 			exportEquation(a, b, c, d);
992 		}
993 
994 	private:
exportEquation(double a,double b,double c,double d)995 		void exportEquation(double a, double b, double c, double d)
996 		{
997 			Equation e(getPhysXExporter(), a, b, c, d);
998 		}
999 	};
1000 
1001     class InstanceGeometry : public Element
1002     {
1003     public:
InstanceGeometry(PhysXExporter & exporter,const URI & geometryURI)1004         InstanceGeometry(PhysXExporter& exporter, const URI & geometryURI)
1005             : Element(exporter, CSWC::CSW_ELEMENT_INSTANCE_GEOMETRY)
1006         {
1007             getStreamWriter().appendURIAttribute(CSWC::CSW_ATTRIBUTE_URL, geometryURI);
1008         }
1009     };
1010 
1011     class Density : public Element
1012     {
1013     public:
Density(PhysXExporter & exporter,double density)1014         Density(PhysXExporter& exporter, double density)
1015             : Element(exporter, CSWC::CSW_ELEMENT_DENSITY)
1016         {
1017             getStreamWriter().appendValues(density);
1018         }
1019     };
1020 
1021     class LocalPose : public Element
1022     {
1023     public:
LocalPose(PhysXExporter & exporter,const MQuaternion & rotation,const MVector & translation)1024         LocalPose(PhysXExporter& exporter, const MQuaternion& rotation, const MVector& translation)
1025             : Element(exporter, CSWC::CSW_ELEMENT_LOCAL_POSE, withPrefix)
1026         {
1027             double localPose[] = { rotation.x, rotation.y, rotation.z, rotation.w, translation.x, translation.y, translation.z };
1028             getStreamWriter().appendValues(localPose, sizeof(localPose) / sizeof(localPose[0]));
1029         }
1030     };
1031 
1032 	class SimulationFilterData : public Element
1033 	{
1034 	public:
SimulationFilterData(PhysXExporter & exporter,int f0,int f1,int f2,int f3)1035 		SimulationFilterData(PhysXExporter & exporter, int f0, int f1, int f2, int f3)
1036 			: Element(exporter, CSWC::CSW_ELEMENT_SIMULATION_FILTER_DATA, withPrefix)
1037 		{
1038 			getStreamWriter().appendValues(f0, f1, f2, f3);
1039 		}
1040 
AreDefaultValues(int f0,int f1,int f2,int f3)1041 		static bool AreDefaultValues(int f0, int f1, int f2, int f3)
1042 		{
1043 			return f0 == 0 && f1 == 0 && f2 == 0 && f3 == 0;
1044 		}
1045 	};
1046 
1047 	class QueryFilterData : public Element
1048 	{
1049 	public:
QueryFilterData(PhysXExporter & exporter,int f0,int f1,int f2,int f3)1050 		QueryFilterData(PhysXExporter & exporter, int f0, int f1, int f2, int f3)
1051 			: Element(exporter, CSWC::CSW_ELEMENT_QUERY_FILTER_DATA, withPrefix)
1052 		{
1053 			getStreamWriter().appendValues(f0, f1, f2, f3);
1054 		}
1055 
AreDefaultValues(int f0,int f1,int f2,int f3)1056 		static bool AreDefaultValues(int f0, int f1, int f2, int f3)
1057 		{
1058 			return f0 == 0 && f1 == 0 && f2 == 0 && f3 == 0;
1059 		}
1060 	};
1061 
1062 	class ContactOffset : public Element
1063 	{
1064 	public:
ContactOffset(PhysXExporter & exporter,double contactOffset)1065 		ContactOffset(PhysXExporter & exporter, double contactOffset)
1066 			: Element(exporter, CSWC::CSW_ELEMENT_CONTACT_OFFSET, withPrefix)
1067 		{
1068 			getStreamWriter().appendValues(contactOffset);
1069 		}
1070 
DefaultValue()1071 		static double DefaultValue()
1072 		{
1073 			return 0.02;
1074 		}
1075 	};
1076 
1077 	class RestOffset : public Element
1078 	{
1079 	public:
RestOffset(PhysXExporter & exporter,double restOffset)1080 		RestOffset(PhysXExporter & exporter, double restOffset)
1081 			: Element(exporter, CSWC::CSW_ELEMENT_REST_OFFSET, withPrefix)
1082 		{
1083 			getStreamWriter().appendValues(restOffset);
1084 		}
1085 
DefaultValue()1086 		static double DefaultValue()
1087 		{
1088 			return 0.0;
1089 		}
1090 	};
1091 
1092 	class ShapeFlags : public Element
1093 	{
1094 	public:
ShapeFlags(PhysXExporter & exporter,const Flags<PhysXXML::ShapeFlags::FlagEnum> & flags)1095 		ShapeFlags(PhysXExporter & exporter, const Flags<PhysXXML::ShapeFlags::FlagEnum> & flags)
1096 			: Element(exporter, CSWC::CSW_ELEMENT_SHAPE_FLAGS, withPrefix)
1097 		{
1098 			getStreamWriter().appendText(PhysXExporter::ShapeFlagsToCOLLADA(flags));
1099 		}
1100 
DefaultValue()1101 		static Flags<PhysXXML::ShapeFlags::FlagEnum> DefaultValue()
1102 		{
1103 			return Flags<PhysXXML::ShapeFlags::FlagEnum>(
1104 				PhysXXML::ShapeFlags::Visualization |
1105 				PhysXXML::ShapeFlags::SimulationShape |
1106 				PhysXXML::ShapeFlags::SceneQueryShape);
1107 		}
1108 	};
1109 
1110 	class DebugName : public Element
1111 	{
1112 	public:
DebugName(PhysXExporter & exporter,const String & name)1113 		DebugName(PhysXExporter & exporter, const String & name)
1114 			: Element(exporter, CSWC::CSW_ELEMENT_NAME, withPrefix)
1115 		{
1116 			getStreamWriter().appendText(name);
1117 		}
1118 
DefaultValue()1119 		static String DefaultValue()
1120 		{
1121 			return "";
1122 		}
1123 	};
1124 
1125 	class PxShape : public Element
1126 	{
1127 	public:
PxShape(PhysXExporter & exporter,const PhysXXML::PxShape & shape)1128 		PxShape(PhysXExporter& exporter, const PhysXXML::PxShape & shape)
1129 			: Element(exporter, CSWC::CSW_ELEMENT_PX_SHAPE, withPrefix)
1130 		{
1131 			exportLocalPose(shape);
1132 			exportSimulationFilterData(shape);
1133 			exportQueryFilterData(shape);
1134 			exportContactOffset(shape);
1135 			exportRestOffset(shape);
1136 			exportShapeFlags(shape);
1137 			exportName(shape);
1138 		}
1139 
HasDefaultValues(const PhysXXML::PxShape & shape)1140 		static bool HasDefaultValues(const PhysXXML::PxShape & shape)
1141 		{
1142 			// Always export local pose
1143 			return false;
1144 		}
1145 
1146 	private:
exportLocalPose(const PhysXXML::PxShape & shape)1147 		void exportLocalPose(const PhysXXML::PxShape & shape)
1148 		{
1149 			LocalPose e(getPhysXExporter(), shape.localPose.rotation, shape.localPose.translation);
1150 		}
1151 
exportSimulationFilterData(const PhysXXML::PxShape & shape)1152 		void exportSimulationFilterData(const PhysXXML::PxShape & shape)
1153 		{
1154 			if (!SimulationFilterData::AreDefaultValues(
1155 				shape.simulationFilterData.filter0,
1156 				shape.simulationFilterData.filter1,
1157 				shape.simulationFilterData.filter2,
1158 				shape.simulationFilterData.filter3))
1159 			{
1160 				SimulationFilterData e(
1161 					getPhysXExporter(),
1162 					shape.simulationFilterData.filter0,
1163 					shape.simulationFilterData.filter1,
1164 					shape.simulationFilterData.filter2,
1165 					shape.simulationFilterData.filter3
1166 					);
1167 			}
1168 		}
1169 
exportQueryFilterData(const PhysXXML::PxShape & shape)1170 		void exportQueryFilterData(const PhysXXML::PxShape & shape)
1171 		{
1172 			if (!QueryFilterData::AreDefaultValues(
1173 				shape.queryFilterData.filter0,
1174 				shape.queryFilterData.filter1,
1175 				shape.queryFilterData.filter2,
1176 				shape.queryFilterData.filter3))
1177 			{
1178 				QueryFilterData e(
1179 					getPhysXExporter(),
1180 					shape.queryFilterData.filter0,
1181 					shape.queryFilterData.filter1,
1182 					shape.queryFilterData.filter2,
1183 					shape.queryFilterData.filter3
1184 					);
1185 			}
1186 		}
1187 
exportContactOffset(const PhysXXML::PxShape & shape)1188 		void exportContactOffset(const PhysXXML::PxShape & shape)
1189 		{
1190 			if (shape.contactOffset.contactOffset != ContactOffset::DefaultValue())
1191 			{
1192 				ContactOffset e(getPhysXExporter(), shape.contactOffset.contactOffset);
1193 			}
1194 		}
1195 
exportRestOffset(const PhysXXML::PxShape & shape)1196 		void exportRestOffset(const PhysXXML::PxShape & shape)
1197 		{
1198 			if (shape.restOffset.restOffset != RestOffset::DefaultValue())
1199 			{
1200 				RestOffset e(getPhysXExporter(), shape.restOffset.restOffset);
1201 			}
1202 		}
1203 
exportShapeFlags(const PhysXXML::PxShape & shape)1204 		void exportShapeFlags(const PhysXXML::PxShape & shape)
1205 		{
1206 			if (shape.flags.flags != ShapeFlags::DefaultValue())
1207 			{
1208 				ShapeFlags e(getPhysXExporter(), shape.flags.flags);
1209 			}
1210 		}
1211 
exportName(const PhysXXML::PxShape & shape)1212 		void exportName(const PhysXXML::PxShape & shape)
1213 		{
1214 			if (shape.name.name != DebugName::DefaultValue())
1215 			{
1216 				DebugName e(getPhysXExporter(), shape.name.name);
1217 			}
1218 		}
1219 	};
1220 
1221     class ShapeTechnique : public Element
1222     {
1223     public:
ShapeTechnique(PhysXExporter & exporter,const MObject & shape,const PhysXXML::PxShape & pxShape,const String & profile)1224 		ShapeTechnique(PhysXExporter& exporter, const MObject& shape, const PhysXXML::PxShape & pxShape, const String & profile)
1225             : Element(exporter, CSWC::CSW_ELEMENT_TECHNIQUE)
1226         {
1227             getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_PROFILE, profile);
1228 			getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_XMLNS + ":" + CSWC::CSW_PREFIX_PX, PhysXExporter::GetXMLNS());
1229 			getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_XSI_SCHEMALOCATION, PhysXExporter::GetXSISchemaLocation());
1230             if (profile == PROFILE_MAYA) {
1231                 exporter.exportExtraAttributes(shape);
1232             }
1233 			else if (profile == PhysXExporter::GetPhysXProfile()) {
1234 				exportPxShape(pxShape);
1235 			}
1236         }
1237 
HasDefaultValues(const MObject & shape,const PhysXXML::PxShape & pxShape,const String & profile)1238 		static bool HasDefaultValues(const MObject & shape, const PhysXXML::PxShape & pxShape, const String & profile)
1239 		{
1240 			if (profile == PhysXExporter::GetPhysXProfile())
1241 			{
1242 				return PxShape::HasDefaultValues(pxShape);
1243 			}
1244 			else if (profile == PROFILE_MAYA)
1245 			{
1246 				return !PhysXExporter::HasExtraAttributes(shape);
1247 			}
1248 			return true;
1249 		}
1250 
1251     private:
exportPxShape(const PhysXXML::PxShape & shape)1252 		void exportPxShape(const PhysXXML::PxShape & shape)
1253 		{
1254 			if (!PxShape::HasDefaultValues(shape))
1255 			{
1256 				PxShape e(getPhysXExporter(), shape);
1257 			}
1258 		}
1259 
1260     private:
1261         static std::set<MString, MStringComp> mAttributes;
1262     };
1263     std::set<MString, MStringComp> ShapeTechnique::mAttributes;
1264 
1265     class ShapeExtra : public Element
1266     {
1267     public:
ShapeExtra(PhysXExporter & exporter,const MObject & shape,const PhysXXML::PxShape & pxShape)1268 		ShapeExtra(PhysXExporter& exporter, const MObject& shape, const PhysXXML::PxShape & pxShape)
1269             : Element(exporter, CSWC::CSW_ELEMENT_EXTRA)
1270         {
1271 			if (PhysXExporter::HasExtraAttributes(shape)) {
1272 				exportProfile(shape, pxShape, PROFILE_MAYA);
1273 			}
1274 
1275 			exportProfile(shape, pxShape, PhysXExporter::GetPhysXProfile());
1276         }
1277 
HasDefaultValues(const MObject & shape,const PhysXXML::PxShape & pxShape)1278 		static bool HasDefaultValues(const MObject & shape, const PhysXXML::PxShape & pxShape)
1279 		{
1280 			return
1281 				ShapeTechnique::HasDefaultValues(shape, pxShape, PROFILE_MAYA) &&
1282 				ShapeTechnique::HasDefaultValues(shape, pxShape, PhysXExporter::GetPhysXProfile());
1283 		}
1284 
1285     private:
exportProfile(const MObject & shape,const PhysXXML::PxShape & pxShape,const String & profile)1286 		void exportProfile(const MObject& shape, const PhysXXML::PxShape & pxShape, const String& profile)
1287         {
1288 			if (!ShapeTechnique::HasDefaultValues(shape, pxShape, profile))
1289 			{
1290 				ShapeTechnique e(getPhysXExporter(), shape, pxShape, profile);
1291 			}
1292         }
1293     };
1294 
1295     class Shape : public Element
1296     {
1297     public:
Shape(PhysXExporter & exporter,const MObject & rigidBody,const PhysXXML::PxRigidBody & pxRigidBody,const MObject & shape,const PhysXXML::PxShape & pxShape)1298 		Shape(PhysXExporter& exporter,
1299 			const MObject & rigidBody,
1300 			const PhysXXML::PxRigidBody & pxRigidBody,
1301 			const MObject & shape,
1302 			const PhysXXML::PxShape & pxShape)
1303             : Element(exporter, CSWC::CSW_ELEMENT_RIGID_BODY_SHAPE)
1304         {
1305 			exportHollow(shape);
1306 
1307 			int dummy = 0;
1308 			MString useMassOrDensity;
1309 			DagHelper::getPlugValue(shape, ATTR_USE_MASS_OR_DENSITY, dummy, useMassOrDensity);
1310 			if (useMassOrDensity == USE_MASS_OR_DENSITY_MASS)
1311 			{
1312 				exportMass(shape);
1313 			}
1314 			else //if (useMassOrDensity == USE_MASS_OR_DENSITY_DENSITY)
1315 			{
1316 				exportDensity(shape);
1317 			}
1318 
1319 			//no <physics_material> exported for shapes. Use rigid body's one.
1320 
1321 			switch (pxShape.geometry.type)
1322 			{
1323 			case PhysXXML::Geometry::Box:				exportBox(pxShape);						break;
1324 			case PhysXXML::Geometry::Sphere:			exportSphere(pxShape);					break;
1325 			case PhysXXML::Geometry::Capsule:			exportCapsule(pxShape);					break;
1326 			case PhysXXML::Geometry::ConvexMesh:		exportConvexHull(rigidBody, shape);		break;
1327 			case PhysXXML::Geometry::TriangleMesh:      exportTriangleMesh(rigidBody, shape);	break;
1328 			case PhysXXML::Geometry::Plane:             exportPlane(pxShape);					break;
1329 			}
1330 
1331 			exportRotateTranslate(rigidBody, pxRigidBody, shape, pxShape);
1332 			exportExtra(shape, pxShape);
1333         }
1334 
1335     private:
exportHollow(const MObject & shape)1336 		void exportHollow(const MObject & shape)
1337         {
1338             //Hollow hollow(getPhysXExporter(), false);
1339         }
1340 
exportMass(const MObject & shape)1341         void exportMass(const MObject & shape)
1342         {
1343             double mass = 0.0;
1344             DagHelper::getPlugValue(shape, ATTR_MASS, mass);
1345             Mass e(getPhysXExporter(), mass);
1346         }
1347 
exportDensity(const MObject & shape)1348         void exportDensity(const MObject & shape)
1349         {
1350             double density = 0.0;
1351             DagHelper::getPlugValue(shape, ATTR_DENSITY, density);
1352 			// g/cm3 to kg/m3
1353             Density e(getPhysXExporter(), density * 1000.0);
1354         }
1355 
exportBox(const PhysXXML::PxShape & shape)1356 		void exportBox(const PhysXXML::PxShape & shape)
1357         {
1358             ShapeBox e(getPhysXExporter(), shape);
1359         }
1360 
exportSphere(const PhysXXML::PxShape & shape)1361 		void exportSphere(const PhysXXML::PxShape & shape)
1362         {
1363 			ShapeSphere e(getPhysXExporter(), shape);
1364         }
1365 
exportCapsule(const PhysXXML::PxShape & shape)1366 		void exportCapsule(const PhysXXML::PxShape & shape)
1367         {
1368 			ShapeCapsule e(getPhysXExporter(), shape);
1369         }
1370 
exportConvexHull(const MObject & rigidBody,const MObject & shape)1371 		void exportConvexHull(const MObject & rigidBody, const MObject & shape)
1372         {
1373             // TODO PhysX: apply "inflate" attribute to convex hull geometry.
1374             // Note: apply inflation like done for box shape. See ShapeBox::exportHalfExtents().
1375             // However "inflate" attribute is limited to [0; 0.839] for some unknown reason.
1376 			exportInstanceGeometry(rigidBody, shape, "_");
1377         }
1378 
exportTriangleMesh(const MObject & rigidBody,const MObject & shape)1379 		void exportTriangleMesh(const MObject & rigidBody, const MObject & shape)
1380         {
1381 			exportInstanceGeometry(rigidBody, shape);
1382         }
1383 
exportPlane(const PhysXXML::PxShape & shape)1384 		void exportPlane(const PhysXXML::PxShape & shape)
1385 		{
1386 			// Plane equation. PhysX plane normal is along X axis. Normal and distance are calculated from shape transform.
1387 			double a = 1.0;
1388 			double b = 0.0;
1389 			double c = 0.0;
1390 			double d = 0.0;
1391 
1392 			ShapePlane e(getPhysXExporter(), a, b, c, d);
1393 		}
1394 
exportInstanceGeometry(const MObject & rigidBody,const MObject & shape,const String & URISuffix="")1395 		void exportInstanceGeometry(const MObject & rigidBody, const MObject & shape, const String & URISuffix = "")
1396         {
1397             // Get geometry URI
1398             MObject meshObject;
1399             PhysXShape::GetConnectedInMesh(shape, meshObject);
1400 
1401             if (meshObject.isNull() || !ExportOptions::exportPolygonMeshes())
1402             {
1403                 // If connected mesh doesn't exist anymore then we use the PhysX shape internal geometry
1404                 // This should rarely happen but this is possible...
1405                 // Also use shape internal geometry if we don't export polygon meshes.
1406                 meshObject = shape;
1407             }
1408 
1409             URI geometryURI;
1410             getPhysXExporter().getMeshURI(meshObject, geometryURI);
1411             if (URISuffix.length() > 0) {
1412                 geometryURI.setFragment(geometryURI.getFragment() + URISuffix);
1413             }
1414             InstanceGeometry e(getPhysXExporter(), geometryURI);
1415         }
1416 
exportRotateTranslate(const MObject & rigidBody,const PhysXXML::PxRigidBody & pxRigidBody,const MObject & shape,const PhysXXML::PxShape & pxShape)1417 		void exportRotateTranslate(
1418 			const MObject& rigidBody,
1419 			const PhysXXML::PxRigidBody & pxRigidBody,
1420 			const MObject & shape,
1421 			const PhysXXML::PxShape & pxShape)
1422         {
1423             // Get shape local pose.
1424 			MMatrix localPose = PxTransformToMMatrix(pxShape.localPose.translation, pxShape.localPose.rotation);
1425 
1426             // Rigid body world pose
1427 			MMatrix globalPose = PxTransformToMMatrix(pxRigidBody.globalPose.translation, pxRigidBody.globalPose.rotation);
1428 
1429 			// Target world pose
1430 			MMatrix targetGlobalPose = PhysXExporter::GetRigidBodyTargetTM(rigidBody);
1431 
1432             MMatrix DAEShapeLocalPose = localPose * globalPose * targetGlobalPose.inverse();
1433 
1434             int dummy = 0;
1435             MString shapeType;
1436             DagHelper::getPlugValue(shape, ATTR_SHAPE_TYPE, dummy, shapeType);
1437             if (shapeType == SHAPE_TYPE_CAPSULE) {
1438                 // PhysX capsules are X axis oriented. COLLADA capsules are Y axis oriented.
1439                 MTransformationMatrix rotation;
1440                 rotation.rotateBy(MEulerRotation(0.0, 0.0, -M_PI / 2.0, MEulerRotation::kXYZ), MSpace::kTransform);
1441                 MMatrix rotationMatrix = rotation.asMatrix();
1442                 DAEShapeLocalPose = DAEShapeLocalPose * rotationMatrix;
1443             }
1444 
1445             MTransformationMatrix transform(DAEShapeLocalPose);
1446 
1447             MVector translation = transform.getTranslation(MSpace::kTransform);
1448             MVector rotatePivotTranslation = transform.rotatePivotTranslation(MSpace::kTransform);
1449             MPoint rotatePivot = transform.rotatePivot(MSpace::kTransform);
1450             MEulerRotation rotation = transform.eulerRotation();
1451             rotation.order = static_cast<MEulerRotation::RotationOrder>(static_cast<int>(transform.rotationOrder()) - MTransformationMatrix::kXYZ + MEulerRotation::kXYZ);
1452 
1453             getPhysXExporter().exportTranslation(translation, ATTR_TRANSLATE);
1454             getPhysXExporter().exportTranslation(rotatePivotTranslation, ATTR_ROTATE_PIVOT_TRANSLATION);
1455             getPhysXExporter().exportTranslation(rotatePivot, ATTR_ROTATE_PIVOT);
1456             getPhysXExporter().exportRotation(rotation, ATTR_ROTATE);
1457             getPhysXExporter().exportTranslation(rotatePivot * -1, ATTR_ROTATE_PIVOT_INVERSE);
1458         }
1459 
exportExtra(const MObject & shape,const PhysXXML::PxShape & pxShape)1460 		void exportExtra(const MObject & shape, const PhysXXML::PxShape & pxShape)
1461         {
1462 			if (!ShapeExtra::HasDefaultValues(shape, pxShape))
1463 			{
1464 				ShapeExtra e(getPhysXExporter(), shape, pxShape);
1465 			}
1466         }
1467     };
1468 
1469     class Enabled : public Element
1470     {
1471     public:
Enabled(PhysXExporter & exporter,bool enabled)1472         Enabled(PhysXExporter& exporter, bool enabled)
1473             : Element(exporter, CSWC::CSW_ELEMENT_ENABLED)
1474         {
1475             getStreamWriter().appendValues(enabled);
1476         }
1477     };
1478 
1479     class Interpenetrate : public Element
1480     {
1481     public:
Interpenetrate(PhysXExporter & exporter,bool interpenetrate)1482         Interpenetrate(PhysXExporter& exporter, bool interpenetrate)
1483             : Element(exporter, CSWC::CSW_ELEMENT_INTERPENETRATE)
1484         {
1485             getStreamWriter().appendValues(interpenetrate);
1486         }
1487 
DefaultValue()1488 		static bool DefaultValue()
1489 		{
1490 			return false;
1491 		}
1492     };
1493 
1494     class Min : public Element
1495     {
1496     public:
Min(PhysXExporter & exporter,const MVector & min)1497         Min(PhysXExporter& exporter, const MVector & min)
1498             : Element(exporter, CSWC::CSW_ELEMENT_MIN)
1499         {
1500             for (uint i = 0; i < 3; ++i)
1501             {
1502                 if (isInf(min(i))) {
1503                     getStreamWriter().appendValues("-INF");
1504                 }
1505                 else {
1506                     getStreamWriter().appendValues(min(i));
1507                 }
1508             }
1509         }
1510 
DefaultValue()1511 		static const MVector & DefaultValue()
1512 		{
1513 			return MVector::zero;
1514 		}
1515     };
1516 
1517     class Max : public Element
1518     {
1519     public:
Max(PhysXExporter & exporter,const MVector & max)1520         Max(PhysXExporter& exporter, const MVector & max)
1521             : Element(exporter, CSWC::CSW_ELEMENT_MAX)
1522         {
1523             for (uint i = 0; i < 3; ++i)
1524             {
1525                 if (isInf(max(i))) {
1526                     getStreamWriter().appendValues("INF");
1527                 }
1528                 else {
1529                     getStreamWriter().appendValues(max(i));
1530                 }
1531             }
1532         }
1533 
DefaultValue()1534 		static const MVector & DefaultValue()
1535 		{
1536 			return MVector::zero;
1537 		}
1538     };
1539 
1540     class SwingConeAndTwist : public Element
1541     {
1542     public:
SwingConeAndTwist(PhysXExporter & exporter,const MVector & min,const MVector & max)1543 		SwingConeAndTwist(PhysXExporter& exporter,
1544 			const MVector & min,
1545 			const MVector & max)
1546             : Element(exporter, CSWC::CSW_ELEMENT_SWING_CONE_AND_TWIST)
1547         {
1548             exportMin(min);
1549             exportMax(max);
1550         }
1551 
AreDefaultValues(const MVector & min,const MVector & max)1552 		static bool AreDefaultValues(const MVector & min, const MVector & max)
1553 		{
1554 			return min == Min::DefaultValue() &&
1555 				max == Max::DefaultValue();
1556 		}
1557 
1558     private:
exportMin(const MVector & min)1559 		void exportMin(const MVector & min)
1560         {
1561             if (min != Min::DefaultValue())
1562             {
1563                 Min e(getPhysXExporter(), min);
1564             }
1565         }
1566 
exportMax(const MVector & max)1567 		void exportMax(const MVector & max)
1568         {
1569 			if (max != Max::DefaultValue())
1570             {
1571                 Max e(getPhysXExporter(), max);
1572             }
1573         }
1574     };
1575 
1576     class LimitsLinear : public Element
1577     {
1578     public:
LimitsLinear(PhysXExporter & exporter,const MVector & min,const MVector & max)1579         LimitsLinear(PhysXExporter& exporter,
1580             const MVector & min,
1581             const MVector & max)
1582             : Element(exporter, CSWC::CSW_ELEMENT_LINEAR)
1583         {
1584             exportMin(min);
1585             exportMax(max);
1586         }
1587 
AreDefaultValues(const MVector & min,const MVector & max)1588 		static bool AreDefaultValues(const MVector & min, const MVector & max)
1589 		{
1590 			return min == Min::DefaultValue() && max == Max::DefaultValue();
1591 		}
1592 
1593     private:
exportMin(const MVector & min)1594         void exportMin(const MVector & min)
1595         {
1596 			if (min != Min::DefaultValue())
1597             {
1598                 Min e(getPhysXExporter(), min);
1599             }
1600         }
1601 
exportMax(const MVector & max)1602         void exportMax(const MVector & max)
1603         {
1604             if (max != Max::DefaultValue())
1605             {
1606                 Max e(getPhysXExporter(), max);
1607             }
1608         }
1609     };
1610 
1611     class Limits : public Element
1612     {
1613     public:
Limits(PhysXExporter & exporter,const MVector & swingConeAndTwistMin,const MVector & swingConeAndTwistMax,const MVector & linearMin,const MVector & linearMax)1614         Limits(PhysXExporter& exporter,
1615             const MVector & swingConeAndTwistMin,
1616             const MVector & swingConeAndTwistMax,
1617             const MVector & linearMin,
1618             const MVector & linearMax)
1619             : Element(exporter, CSWC::CSW_ELEMENT_LIMITS)
1620         {
1621 			exportSwingConeAndTwist(swingConeAndTwistMin, swingConeAndTwistMax);
1622 			exportLinear(linearMin, linearMax);
1623         }
1624 
AreDefaultValues(const MVector & swingConeAndTwistMin,const MVector & swingConeAndTwistMax,const MVector & linearMin,const MVector & linearMax)1625 		static bool AreDefaultValues(
1626 			const MVector & swingConeAndTwistMin,
1627 			const MVector & swingConeAndTwistMax,
1628 			const MVector & linearMin,
1629 			const MVector & linearMax)
1630 		{
1631 			return SwingConeAndTwist::AreDefaultValues(swingConeAndTwistMin, swingConeAndTwistMax) &&
1632 				LimitsLinear::AreDefaultValues(linearMin, linearMax);
1633 		}
1634 
1635     private:
exportSwingConeAndTwist(const MVector & min,const MVector & max)1636 		void exportSwingConeAndTwist(
1637 			const MVector & min,
1638             const MVector & max)
1639         {
1640 			if (!SwingConeAndTwist::AreDefaultValues(min, max))
1641             {
1642                 SwingConeAndTwist e(getPhysXExporter(), min, max);
1643             }
1644         }
1645 
exportLinear(const MVector & min,const MVector & max)1646 		void exportLinear(
1647 			const MVector & min,
1648             const MVector & max)
1649         {
1650 			if (!LimitsLinear::AreDefaultValues(min, max))
1651             {
1652                 LimitsLinear e(getPhysXExporter(), min, max);
1653             }
1654         }
1655     };
1656 
1657     class Stiffness : public Element
1658     {
1659     public:
Stiffness(PhysXExporter & exporter,double stiffness,bool elementForm,const String & sid="")1660         Stiffness(PhysXExporter& exporter, double stiffness, bool elementForm, const String & sid = "")
1661             : Element(exporter, CSWC::CSW_ELEMENT_STIFFNESS, elementForm)
1662         {
1663             if (!sid.empty()) {
1664                 getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_SID, sid);
1665             }
1666             getStreamWriter().appendValues(stiffness);
1667         }
1668 
DefaultValue()1669 		static double DefaultValue()
1670 		{
1671 			return 1.0;
1672 		}
1673     };
1674 
1675     class Damping : public Element
1676     {
1677     public:
Damping(PhysXExporter & exporter,double damping,bool elementForm,const String & sid="")1678         Damping(PhysXExporter& exporter, double damping, bool elementForm, const String & sid = "")
1679             : Element(exporter, CSWC::CSW_ELEMENT_DAMPING, elementForm)
1680         {
1681             if (!sid.empty()) {
1682                 getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_SID, sid);
1683             }
1684             getStreamWriter().appendValues(damping);
1685         }
1686 
DefaultValue()1687 		static double DefaultValue()
1688 		{
1689 			return 0.0;
1690 		}
1691     };
1692 
1693     class TargetValue : public Element
1694     {
1695     public:
TargetValue(PhysXExporter & exporter,double targetValue,const String & sid="")1696         TargetValue(PhysXExporter& exporter, double targetValue, const String & sid = "")
1697             : Element(exporter, CSWC::CSW_ELEMENT_TARGET_VALUE)
1698         {
1699             if (!sid.empty()) {
1700                 getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_SID, sid);
1701             }
1702             getStreamWriter().appendValues(targetValue);
1703         }
1704 
DefaultValue()1705 		static double DefaultValue()
1706 		{
1707 			return 0.0;
1708 		}
1709     };
1710 
1711     class SpringLinear : public Element
1712     {
1713     public:
SpringLinear(PhysXExporter & exporter,double stiffness,double damping,double targetValue)1714         SpringLinear(PhysXExporter& exporter,
1715             double stiffness,
1716             double damping,
1717             double targetValue)
1718             : Element(exporter, CSWC::CSW_ELEMENT_LINEAR)
1719         {
1720             exportStiffness(stiffness);
1721             exportDamping(damping);
1722             exportTargetValue(targetValue);
1723         }
1724 
AreDefaultValues(double stiffness,double damping,double targetValue)1725 		static bool AreDefaultValues(double stiffness, double damping, double targetValue)
1726 		{
1727 			return stiffness == Stiffness::DefaultValue() &&
1728 				damping == Damping::DefaultValue() &&
1729 				targetValue == TargetValue::DefaultValue();
1730 		}
1731 
1732     private:
exportStiffness(double stiffness)1733         void exportStiffness(double stiffness)
1734         {
1735             if (stiffness != Stiffness::DefaultValue())
1736             {
1737                 Stiffness e(getPhysXExporter(), stiffness, withoutPrefix);
1738             }
1739         }
1740 
exportDamping(double damping)1741         void exportDamping(double damping)
1742         {
1743             if (damping != Damping::DefaultValue())
1744             {
1745                 Damping e(getPhysXExporter(), damping, withoutPrefix);
1746             }
1747         }
1748 
exportTargetValue(double targetValue)1749         void exportTargetValue(double targetValue)
1750         {
1751             if (targetValue != TargetValue::DefaultValue())
1752             {
1753                 TargetValue e(getPhysXExporter(), targetValue);
1754             }
1755         }
1756     };
1757 
1758     class Angular : public Element
1759     {
1760     public:
Angular(PhysXExporter & exporter,double stiffness,double damping,double targetValue)1761         Angular(PhysXExporter& exporter,
1762             double stiffness,
1763             double damping,
1764             double targetValue)
1765             : Element(exporter, CSWC::CSW_ELEMENT_ANGULAR)
1766         {
1767             exportStiffness(stiffness);
1768             exportDamping(damping);
1769             exportTargetValue(targetValue);
1770         }
1771 
AreDefaultValues(double stiffness,double damping,double targetValue)1772 		static bool AreDefaultValues(double stiffness, double damping, double targetValue)
1773 		{
1774 			return stiffness == Stiffness::DefaultValue() &&
1775 				damping == Damping::DefaultValue() &&
1776 				targetValue == TargetValue::DefaultValue();
1777 		}
1778 
1779     private:
exportStiffness(double stiffness)1780         void exportStiffness(double stiffness)
1781         {
1782             if (stiffness != Stiffness::DefaultValue())
1783             {
1784                 Stiffness e(getPhysXExporter(), stiffness, withoutPrefix);
1785             }
1786         }
1787 
exportDamping(double damping)1788         void exportDamping(double damping)
1789         {
1790             if (damping != Damping::DefaultValue())
1791             {
1792                 Damping e(getPhysXExporter(), damping, withoutPrefix);
1793             }
1794         }
1795 
exportTargetValue(double targetValue)1796         void exportTargetValue(double targetValue)
1797         {
1798             if (targetValue != TargetValue::DefaultValue())
1799             {
1800                 TargetValue e(getPhysXExporter(), targetValue);
1801             }
1802         }
1803     };
1804 
1805     class Spring : public Element
1806     {
1807     public:
Spring(PhysXExporter & exporter,double angularStiffness,double angularDamping,double angularTargetValue,double linearStiffness,double linearDamping,double linearTargetValue)1808         Spring(PhysXExporter& exporter,
1809             double angularStiffness,
1810             double angularDamping,
1811             double angularTargetValue,
1812             double linearStiffness,
1813             double linearDamping,
1814             double linearTargetValue)
1815             : Element(exporter, CSWC::CSW_ELEMENT_SPRING)
1816         {
1817             exportAngular(angularStiffness, angularDamping, angularTargetValue);
1818             exportLinear(linearStiffness, linearDamping, linearTargetValue);
1819         }
1820 
AreDefaultValues(double angularStiffness,double angularDamping,double angularTargetValue,double linearStiffness,double linearDamping,double linearTargetValue)1821 		static bool AreDefaultValues(
1822 			double angularStiffness,
1823 			double angularDamping,
1824 			double angularTargetValue,
1825 			double linearStiffness,
1826 			double linearDamping,
1827 			double linearTargetValue)
1828 		{
1829 			return Angular::AreDefaultValues(angularStiffness, angularDamping, angularTargetValue) &&
1830 				SpringLinear::AreDefaultValues(linearStiffness, linearDamping, linearTargetValue);
1831 		}
1832 
1833     private:
exportLinear(double stiffness,double damping,double targetValue)1834         void exportLinear(
1835             double stiffness,
1836             double damping,
1837             double targetValue)
1838         {
1839             if (!SpringLinear::AreDefaultValues(stiffness, damping, targetValue))
1840             {
1841                 SpringLinear e(getPhysXExporter(), stiffness, damping, targetValue);
1842             }
1843         }
1844 
exportAngular(double stiffness,double damping,double targetValue)1845         void exportAngular(
1846             double stiffness,
1847             double damping,
1848             double targetValue)
1849         {
1850             if (!Angular::AreDefaultValues(stiffness, damping, targetValue))
1851             {
1852                 Angular e(getPhysXExporter(), stiffness, damping, targetValue);
1853             }
1854         }
1855     };
1856 
1857     class RigidBodyTechniqueCommon : public Element
1858     {
1859     public:
RigidBodyTechniqueCommon(PhysXExporter & exporter,const MObject & rigidBody,const PhysXXML::PxRigidBody & pxRigidBody,const String & rigidBodySid)1860 		RigidBodyTechniqueCommon(PhysXExporter& exporter, const MObject & rigidBody, const PhysXXML::PxRigidBody & pxRigidBody, const String & rigidBodySid)
1861             : Element(exporter, CSWC::CSW_ELEMENT_TECHNIQUE_COMMON)
1862         {
1863             exportDynamic(pxRigidBody);
1864             exportMass(rigidBody, pxRigidBody);
1865             exportMassFrame(rigidBody, pxRigidBody);
1866             exportInertia(rigidBody, pxRigidBody);
1867             exportPhysicsMaterial(pxRigidBody, rigidBodySid);
1868             exportShapes(rigidBody, pxRigidBody);
1869         }
1870 
1871     private:
exportDynamic(const PhysXXML::PxRigidBody & rigidBody)1872 		void exportDynamic(const PhysXXML::PxRigidBody & rigidBody)
1873         {
1874 			Dynamic e(getPhysXExporter(), rigidBody.getType() == PhysXXML::PxRigidBody::Dynamic);
1875         }
1876 
exportMass(const MObject & rigidBody,const PhysXXML::PxRigidBody & pxRigidBody)1877 		void exportMass(const MObject & rigidBody, const PhysXXML::PxRigidBody & pxRigidBody)
1878         {
1879 			int dummy = 0;
1880 			MString overrideMassOrDensityStr;
1881 			DagHelper::getPlugValue(rigidBody, ATTR_OVERRIDE_MASS_OR_DENSITY, dummy, overrideMassOrDensityStr);
1882 			bool overrideMassOrDensity = overrideMassOrDensityStr != OVERRIDE_MASS_OR_DENSITY_DISABLED;
1883 
1884 			if (overrideMassOrDensity)
1885 			{
1886 				if (pxRigidBody.getType() == PhysXXML::PxRigidBody::Dynamic)
1887 				{
1888 					const PhysXXML::PxRigidDynamic & rigidDynamic = static_cast<const PhysXXML::PxRigidDynamic&>(pxRigidBody);
1889 					// PhysX mass is in grams. COLLADA uses kilograms.
1890 					Mass e(getPhysXExporter(), rigidDynamic.mass.mass / 1000.0);
1891 				}
1892 				else
1893 				{
1894 					double mass = getPhysXExporter().GetRigidBodyMass(rigidBody);
1895 					Mass e(getPhysXExporter(), mass);
1896 				}
1897 			}
1898         }
1899 
exportMassFrame(const MObject & rigidBody,const PhysXXML::PxRigidBody & pxRigidBody)1900 		void exportMassFrame(const MObject & rigidBody, const PhysXXML::PxRigidBody & pxRigidBody)
1901         {
1902 			MVector translation = MVector::zero;
1903 			MQuaternion rotation = MQuaternion::identity;
1904 
1905 			if (pxRigidBody.getType() == PhysXXML::PxRigidBody::Dynamic)
1906 			{
1907 				const PhysXXML::PxRigidDynamic & dyn = static_cast<const PhysXXML::PxRigidDynamic&>(pxRigidBody);
1908 
1909 				MMatrix targetWorld = PhysXExporter::GetRigidBodyTargetTM(rigidBody);
1910 				MMatrix cMassLocal = PxTransformToMMatrix(dyn.cMassLocalPose.translation, dyn.cMassLocalPose.rotation);
1911 				MMatrix rigidBodyWorld = PxTransformToMMatrix(dyn.globalPose.translation, dyn.globalPose.rotation);
1912 
1913 				// Center of mass relative to target
1914 				cMassLocal = cMassLocal * rigidBodyWorld * targetWorld.inverse();
1915 
1916 				MTransformationMatrix transform(cMassLocal);
1917 
1918 				translation = transform.getTranslation(MSpace::kTransform);
1919 
1920 				MEulerRotation euler = transform.eulerRotation();
1921 				euler.order = static_cast<MEulerRotation::RotationOrder>(static_cast<int>(transform.rotationOrder()) - MTransformationMatrix::kXYZ + MEulerRotation::kXYZ);
1922 				rotation = euler.asQuaternion();
1923 			}
1924 			else
1925 			{
1926 				int dummy = 0;
1927 				MString centerOfMassMode;
1928 				DagHelper::getPlugValue(rigidBody, ATTR_CENTER_OF_MASS_MODE, dummy, centerOfMassMode);
1929 
1930 				MString overrideMassOrDensityStr;
1931 				DagHelper::getPlugValue(rigidBody, ATTR_OVERRIDE_MASS_OR_DENSITY, dummy, overrideMassOrDensityStr);
1932 				bool overrideMassOrDensity = overrideMassOrDensityStr != OVERRIDE_MASS_OR_DENSITY_DISABLED;
1933 
1934 				if (centerOfMassMode == CENTER_OF_MASS_MODE_CALCULATE_FROM_SHAPES)
1935 				{
1936 					std::vector<MObject> physicsShapes;
1937 					getPhysXExporter().GetRigidBodyShapes(rigidBody, physicsShapes);
1938 
1939 					double totalFactor = 0.0;
1940 					for (size_t i = 0; i < physicsShapes.size(); ++i)
1941 					{
1942 						const MObject & shape = physicsShapes[i];
1943 						MDagPath shapeDagPath;
1944 						MDagPath::getAPathTo(shape, shapeDagPath);
1945 						MFnTransform shapeTransform(shapeDagPath.transform());
1946 						double shapeFactor = overrideMassOrDensity ? getPhysXExporter().GetShapeVolume(shape) : getPhysXExporter().GetShapeMass(shape);
1947 						translation += shapeTransform.getTranslation(MSpace::kObject) * shapeFactor;
1948 						totalFactor += shapeFactor;
1949 					}
1950 					if (totalFactor > 0.0)
1951 					{
1952 						translation /= totalFactor;
1953 					}
1954 				}
1955 				else //if (centerOfMassMode == CENTER_OF_MASS_MODE_MANUAL_OVERRIDE)
1956 				{
1957 					DagHelper::getPlugValue(rigidBody, ATTR_CENTER_OF_MASS_OVERRIDE, translation);
1958 				}
1959 
1960 				translation.x = MDistance::internalToUI(translation.x);
1961 				translation.y = MDistance::internalToUI(translation.y);
1962 				translation.z = MDistance::internalToUI(translation.z);
1963 			}
1964 
1965 			if (!MassFrame::AreDefaultValues(getPhysXExporter(), translation, rotation))
1966 			{
1967 				MassFrame e(getPhysXExporter(), translation, rotation, ATTR_TRANSLATE, ATTR_ROTATE);
1968 			}
1969         }
1970 
exportInertia(const MObject & rigidBody,const PhysXXML::PxRigidBody & pxRigidBody)1971 		void exportInertia(const MObject & rigidBody, const PhysXXML::PxRigidBody & pxRigidBody)
1972         {
1973 			MVector inertiaMatrixDiagonal = MVector::one;
1974 
1975 			if (pxRigidBody.getType() == PhysXXML::PxRigidBody::Dynamic)
1976 			{
1977 				const PhysXXML::PxRigidDynamic & dyn = static_cast<const PhysXXML::PxRigidDynamic&>(pxRigidBody);
1978 				// g to kg
1979 				inertiaMatrixDiagonal = dyn.massSpaceInertiaTensor.massSpaceInertiaTensor / 1000.0;
1980 			}
1981 			else
1982 			{
1983 				/*
1984 				Bounding box inertia matrix =
1985 
1986 				m(b�+c�)/12     0               0
1987 				0               m(a�+c�)/12     0
1988 				0               0               m(a�+b�)/12
1989 
1990 				m -> mass
1991 				a, b, c -> edge lengths
1992 				*/
1993 
1994 				MVector bb = MVector::zero;
1995 				DagHelper::getPlugValue(rigidBody, ATTR_BOUNDING_BOX_SIZE, bb);
1996 
1997 				// Convert to DAE unit
1998 				bb.x = MDistance::internalToUI(bb.x);
1999 				bb.y = MDistance::internalToUI(bb.y);
2000 				bb.z = MDistance::internalToUI(bb.z);
2001 
2002 				double mass = getPhysXExporter().GetRigidBodyMass(rigidBody);
2003 
2004 				inertiaMatrixDiagonal.x = mass * (bb.y * bb.y + bb.z * bb.z) / 12.0;
2005 				inertiaMatrixDiagonal.y = mass * (bb.x * bb.x + bb.z * bb.z) / 12.0;
2006 				inertiaMatrixDiagonal.z = mass * (bb.x * bb.x + bb.y * bb.y) / 12.0;
2007 			}
2008 
2009             Inertia e(getPhysXExporter(), inertiaMatrixDiagonal);
2010         }
2011 
exportPhysicsMaterial(const PhysXXML::PxRigidBody & rigidBody,const String & rigidBodySid)2012 		void exportPhysicsMaterial(const PhysXXML::PxRigidBody & rigidBody, const String & rigidBodySid)
2013         {
2014 			if (const PhysXXML::PxMaterial* material = getPhysXExporter().findPxMaterial(rigidBody))
2015 			{
2016 				String id = rigidBodySid + "_material";
2017 				PhysicsMaterial e(getPhysXExporter(), *material, id);
2018 			}
2019         }
2020 
exportShapes(const MObject & rigidBody,const PhysXXML::PxRigidBody & pxRigidBody)2021         void exportShapes(const MObject & rigidBody, const PhysXXML::PxRigidBody & pxRigidBody)
2022         {
2023 			for (size_t i = 0; i < pxRigidBody.shapes.shapes.size(); ++i)
2024 			{
2025 				MObject shape = getPhysXExporter().findMObject(pxRigidBody.shapes.shapes[i]);
2026 				Shape e(getPhysXExporter(), rigidBody, pxRigidBody, shape, pxRigidBody.shapes.shapes[i]);
2027 			}
2028         }
2029     };
2030 
2031     class RigidConstraintTechniqueCommon : public Element
2032     {
2033     public:
RigidConstraintTechniqueCommon(PhysXExporter & exporter,const MObject & rigidConstraint,const PhysXXML::PxD6Joint & joint)2034 		RigidConstraintTechniqueCommon(PhysXExporter& exporter, const MObject & rigidConstraint, const PhysXXML::PxD6Joint & joint)
2035             : Element(exporter, CSWC::CSW_ELEMENT_TECHNIQUE_COMMON)
2036         {
2037             exportEnabled(rigidConstraint);
2038             exportInterpenetrate(joint);
2039             exportLimits(joint);
2040             exportSpring(joint);
2041         }
2042 
2043     private:
exportEnabled(const MObject & rigidConstraint)2044         void exportEnabled(const MObject & rigidConstraint)
2045         {
2046             bool isEnabled = true;
2047             DagHelper::getPlugValue(rigidConstraint, ATTR_CONSTRAIN, isEnabled);
2048             if (!isEnabled)
2049             {
2050                 Enabled e(getPhysXExporter(), isEnabled);
2051             }
2052         }
2053 
exportInterpenetrate(const PhysXXML::PxD6Joint & joint)2054 		void exportInterpenetrate(const PhysXXML::PxD6Joint & joint)
2055         {
2056 			bool interpenetrate = !joint.constraintFlags.flags.isSet(PhysXXML::ConstraintFlags::CollisionEnabled);
2057 			if (interpenetrate == Interpenetrate::DefaultValue())
2058 			{
2059 				Interpenetrate e(getPhysXExporter(), interpenetrate);
2060 			}
2061         }
2062 
exportLimits(const PhysXXML::PxD6Joint & joint)2063 		void exportLimits(const PhysXXML::PxD6Joint & joint)
2064         {
2065             MVector swingConeAndTwistMin = MVector::zero;
2066 			MVector swingConeAndTwistMax = MVector::zero;
2067 			MVector linearMin = MVector::zero;
2068 			MVector linearMax = MVector::zero;
2069 
2070 			if (joint.motion.eSwing1.eSwing1 == PhysXXML::MotionFlags::Locked)
2071 			{
2072 				swingConeAndTwistMin.x = 0.0;
2073 				swingConeAndTwistMax.x = 0.0;
2074 			}
2075 			else if (joint.motion.eSwing1.eSwing1 == PhysXXML::MotionFlags::Free)
2076 			{
2077 				swingConeAndTwistMin.x = -infinite();
2078 				swingConeAndTwistMax.x = infinite();
2079 			}
2080 			else
2081 			{
2082 				swingConeAndTwistMin.x = COLLADABU::Math::Utils::radToDeg(-joint.swingLimit.yAngle.yAngle);
2083 				swingConeAndTwistMax.x = COLLADABU::Math::Utils::radToDeg(joint.swingLimit.yAngle.yAngle);
2084 			}
2085 
2086 			if (joint.motion.eSwing2.eSwing2 == PhysXXML::MotionFlags::Locked)
2087 			{
2088 				swingConeAndTwistMin.y = 0.0;
2089 				swingConeAndTwistMax.y = 0.0;
2090 			}
2091 			else if (joint.motion.eSwing2.eSwing2 == PhysXXML::MotionFlags::Free)
2092 			{
2093 				swingConeAndTwistMin.y = -infinite();
2094 				swingConeAndTwistMax.y = infinite();
2095 			}
2096 			else
2097 			{
2098 				swingConeAndTwistMin.y = COLLADABU::Math::Utils::radToDeg(-joint.swingLimit.zAngle.zAngle);
2099 				swingConeAndTwistMax.y = COLLADABU::Math::Utils::radToDeg(joint.swingLimit.zAngle.zAngle);
2100 			}
2101 
2102 			if (joint.motion.eTwist.eTwist == PhysXXML::MotionFlags::Locked)
2103 			{
2104 				swingConeAndTwistMin.z = 0.0;
2105 				swingConeAndTwistMax.z = 0.0;
2106 			}
2107 			else if (joint.motion.eTwist.eTwist == PhysXXML::MotionFlags::Free)
2108 			{
2109 				swingConeAndTwistMin.z = -infinite();
2110 				swingConeAndTwistMax.z = infinite();
2111 			}
2112 			else
2113 			{
2114 				swingConeAndTwistMin.z = COLLADABU::Math::Utils::radToDeg(joint.twistLimit.lower.lower);
2115 				swingConeAndTwistMax.z = COLLADABU::Math::Utils::radToDeg(joint.twistLimit.upper.upper);
2116 			}
2117 
2118 			if (joint.motion.eX.eX == PhysXXML::MotionFlags::Locked)
2119 			{
2120 				linearMin.x = 0.0;
2121 				linearMax.x = 0.0;
2122 			}
2123 			else if (joint.motion.eX.eX == PhysXXML::MotionFlags::Free)
2124 			{
2125 				linearMin.x = -infinite();
2126 				linearMax.x = infinite();
2127 			}
2128 			else
2129 			{
2130 				linearMin.x = -joint.linearLimit.value.value;
2131 				linearMax.x = joint.linearLimit.value.value;
2132 			}
2133 
2134 			if (joint.motion.eY.eY == PhysXXML::MotionFlags::Locked)
2135 			{
2136 				linearMin.y = 0.0;
2137 				linearMax.y = 0.0;
2138 			}
2139 			else if (joint.motion.eY.eY == PhysXXML::MotionFlags::Free)
2140 			{
2141 				linearMin.y = -infinite();
2142 				linearMax.y = infinite();
2143 			}
2144 			else
2145 			{
2146 				linearMin.y = -joint.linearLimit.value.value;
2147 				linearMax.y = joint.linearLimit.value.value;
2148 			}
2149 
2150 			if (joint.motion.eZ.eZ == PhysXXML::MotionFlags::Locked)
2151 			{
2152 				linearMin.z = 0.0;
2153 				linearMax.z = 0.0;
2154 			}
2155 			else if (joint.motion.eZ.eZ == PhysXXML::MotionFlags::Free)
2156 			{
2157 				linearMin.z = -infinite();
2158 				linearMax.z = infinite();
2159 			}
2160 			else
2161 			{
2162 				linearMin.z = -joint.linearLimit.value.value;
2163 				linearMax.z = joint.linearLimit.value.value;
2164 			}
2165 
2166             if (!Limits::AreDefaultValues(swingConeAndTwistMin, swingConeAndTwistMax, linearMin, linearMax))
2167             {
2168                 Limits e(getPhysXExporter(),
2169                     swingConeAndTwistMin,
2170                     swingConeAndTwistMax,
2171                     linearMin,
2172                     linearMax);
2173             }
2174         }
2175 
exportSpring(const PhysXXML::PxD6Joint & joint)2176 		void exportSpring(const PhysXXML::PxD6Joint & joint)
2177         {
2178 			double linearStiffness = joint.linearLimit.stiffness.stiffness;
2179 			double linearDamping = joint.linearLimit.damping.damping;
2180             double linearTargetValue = 0.0;
2181 			double angularStiffness = joint.swingLimit.stiffness.stiffness;
2182 			double angularDamping = joint.swingLimit.damping.damping;
2183             double angularTargetValue = 0.0;
2184 
2185             if (!Spring::AreDefaultValues(
2186 				linearStiffness,
2187                 linearDamping,
2188                 linearTargetValue,
2189                 angularStiffness,
2190                 angularDamping,
2191                 angularTargetValue))
2192             {
2193                 Spring e(getPhysXExporter(),
2194                     angularStiffness,
2195                     angularDamping,
2196                     angularTargetValue,
2197                     linearStiffness,
2198                     linearDamping,
2199                     linearTargetValue);
2200             }
2201         }
2202     };
2203 
2204 	class ActorFlags : public Element
2205 	{
2206 	public:
ActorFlags(PhysXExporter & exporter,const Flags<PhysXXML::ActorFlags::FlagEnum> & flags)2207 		ActorFlags(PhysXExporter & exporter, const Flags<PhysXXML::ActorFlags::FlagEnum> & flags)
2208 			: Element(exporter, CSWC::CSW_ELEMENT_ACTOR_FLAGS, withPrefix)
2209 		{
2210 			getStreamWriter().appendValues(PhysXExporter::ActorFlagsToCOLLADA(flags));
2211 		}
2212 
DefaultValue()2213 		static Flags<PhysXXML::ActorFlags::FlagEnum> DefaultValue()
2214 		{
2215 			return Flags<PhysXXML::ActorFlags::FlagEnum>(PhysXXML::ActorFlags::Visualization);
2216 		}
2217 	};
2218 
2219 	class DominanceGroup : public Element
2220 	{
2221 	public:
DominanceGroup(PhysXExporter & exporter,int dominanceGroup)2222 		DominanceGroup(PhysXExporter & exporter, int dominanceGroup)
2223 			: Element(exporter, CSWC::CSW_ELEMENT_DOMINANCE_GROUP, withPrefix)
2224 		{
2225 			getStreamWriter().appendValues(dominanceGroup);
2226 		}
2227 
DefaultValue()2228 		static int DefaultValue()
2229 		{
2230 			return 0;
2231 		}
2232 	};
2233 
2234 	class OwnerClient : public Element
2235 	{
2236 	public:
OwnerClient(PhysXExporter & exporter,int ownerClient)2237 		OwnerClient(PhysXExporter & exporter, int ownerClient)
2238 			: Element(exporter, CSWC::CSW_ELEMENT_OWNER_CLIENT, withPrefix)
2239 		{
2240 			getStreamWriter().appendValues(ownerClient);
2241 		}
2242 
DefaultValue()2243 		static int DefaultValue()
2244 		{
2245 			return 0;
2246 		}
2247 	};
2248 
2249 	class RigidBodyFlags : public Element
2250 	{
2251 	public:
RigidBodyFlags(PhysXExporter & exporter,const Flags<PhysXXML::RigidBodyFlags::FlagEnum> & flags)2252 		RigidBodyFlags(PhysXExporter & exporter, const Flags<PhysXXML::RigidBodyFlags::FlagEnum> & flags)
2253 			: Element(exporter, CSWC::CSW_ELEMENT_RIGID_BODY_FLAGS, withPrefix)
2254 		{
2255 			getStreamWriter().appendValues(PhysXExporter::RigidBodyFlagsToCOLLADA(flags));
2256 		}
2257 
DefaultValue()2258 		static Flags<PhysXXML::RigidBodyFlags::FlagEnum> DefaultValue()
2259 		{
2260 			return Flags<PhysXXML::RigidBodyFlags::FlagEnum>();
2261 		}
2262 	};
2263 
2264 	class MinCCDAdvanceCoefficient : public Element
2265 	{
2266 	public:
MinCCDAdvanceCoefficient(PhysXExporter & exporter,double minCCDAdvanceCoefficient)2267 		MinCCDAdvanceCoefficient(PhysXExporter & exporter, double minCCDAdvanceCoefficient)
2268 			: Element(exporter, CSWC::CSW_ELEMENT_MIN_CCD_ADVANCE_COEFFICIENT, withPrefix)
2269 		{
2270 			getStreamWriter().appendValues(minCCDAdvanceCoefficient);
2271 		}
2272 
DefaultValue()2273 		static double DefaultValue()
2274 		{
2275 			return 0.15;
2276 		}
2277 	};
2278 
2279 	class MaxDepenetrationVelocity : public Element
2280 	{
2281 	public:
MaxDepenetrationVelocity(PhysXExporter & exporter,double maxDepenetrationVelocity)2282 		MaxDepenetrationVelocity(PhysXExporter & exporter, double maxDepenetrationVelocity)
2283 			: Element(exporter, CSWC::CSW_ELEMENT_MAX_DEPENETRATION_VELOCITY, withPrefix)
2284 		{
2285 			getStreamWriter().appendValues(maxDepenetrationVelocity);
2286 		}
2287 
DefaultValue()2288 		static double DefaultValue()
2289 		{
2290 			return infinite();
2291 		}
2292 	};
2293 
2294 	class LinearDamping : public Element
2295 	{
2296 	public:
LinearDamping(PhysXExporter & exporter,double linearDamping)2297 		LinearDamping(PhysXExporter & exporter, double linearDamping)
2298 			: Element(exporter, CSWC::CSW_ELEMENT_LINEAR_DAMPING, withPrefix)
2299 		{
2300 			getStreamWriter().appendValues(linearDamping);
2301 		}
2302 
DefaultValue()2303 		static double DefaultValue()
2304 		{
2305 			return 0.0;
2306 		}
2307 	};
2308 
2309 	class AngularDamping : public Element
2310 	{
2311 	public:
AngularDamping(PhysXExporter & exporter,double angularDamping)2312 		AngularDamping(PhysXExporter & exporter, double angularDamping)
2313 			: Element(exporter, CSWC::CSW_ELEMENT_ANGULAR_DAMPING, withPrefix)
2314 		{
2315 			getStreamWriter().appendValues(angularDamping);
2316 		}
2317 
DefaultValue()2318 		static double DefaultValue()
2319 		{
2320 			return 0.0;
2321 		}
2322 	};
2323 
2324 	class MaxAngularVelocity : public Element
2325 	{
2326 	public:
MaxAngularVelocity(PhysXExporter & exporter,double maxAngularDamping)2327 		MaxAngularVelocity(PhysXExporter & exporter, double maxAngularDamping)
2328 			: Element(exporter, CSWC::CSW_ELEMENT_MAX_ANGULAR_VELOCITY, withPrefix)
2329 		{
2330 			getStreamWriter().appendValues(maxAngularDamping);
2331 		}
2332 
DefaultValue()2333 		static double DefaultValue()
2334 		{
2335 			return 7.0;
2336 		}
2337 	};
2338 
2339 	class SleepThreshold : public Element
2340 	{
2341 	public:
SleepThreshold(PhysXExporter & exporter,double sleepThreshold)2342 		SleepThreshold(PhysXExporter & exporter, double sleepThreshold)
2343 			: Element(exporter, CSWC::CSW_ELEMENT_SLEEP_THRESHOLD, withPrefix)
2344 		{
2345 			getStreamWriter().appendValues(sleepThreshold);
2346 		}
2347 
DefaultValue()2348 		static double DefaultValue()
2349 		{
2350 			return 5e-5;
2351 		}
2352 	};
2353 
2354 	class StabilizationThreshold : public Element
2355 	{
2356 	public:
StabilizationThreshold(PhysXExporter & exporter,double stabilizationThreshold)2357 		StabilizationThreshold(PhysXExporter & exporter, double stabilizationThreshold)
2358 			: Element(exporter, CSWC::CSW_ELEMENT_STABILIZATION_THRESHOLD, withPrefix)
2359 		{
2360 			getStreamWriter().appendValues(stabilizationThreshold);
2361 		}
2362 
DefaultValue()2363 		static double DefaultValue()
2364 		{
2365 			return 1e-5;
2366 		}
2367 	};
2368 
2369 	class WakeCounter : public Element
2370 	{
2371 	public:
WakeCounter(PhysXExporter & exporter,double wakeCounter)2372 		WakeCounter(PhysXExporter & exporter, double wakeCounter)
2373 			: Element(exporter, CSWC::CSW_ELEMENT_WAKE_COUNTER, withPrefix)
2374 		{
2375 			getStreamWriter().appendValues(wakeCounter);
2376 		}
2377 
DefaultValue()2378 		static double DefaultValue()
2379 		{
2380 			return 0.4;
2381 		}
2382 	};
2383 
2384 	class MinPositionIters : public Element
2385 	{
2386 	public:
MinPositionIters(PhysXExporter & exporter,int minPositionIters)2387 		MinPositionIters(PhysXExporter & exporter, int minPositionIters)
2388 			: Element(exporter, CSWC::CSW_ELEMENT_MIN_POSITION_ITERS, withPrefix)
2389 		{
2390 			getStreamWriter().appendValues(minPositionIters);
2391 		}
2392 
DefaultValue()2393 		static int DefaultValue()
2394 		{
2395 			return 4;
2396 		}
2397 	};
2398 
2399 	class MinVelocityIters : public Element
2400 	{
2401 	public:
MinVelocityIters(PhysXExporter & exporter,int minVelocityIters)2402 		MinVelocityIters(PhysXExporter & exporter, int minVelocityIters)
2403 			: Element(exporter, CSWC::CSW_ELEMENT_MIN_VELOCITY_ITERS, withPrefix)
2404 		{
2405 			getStreamWriter().appendValues(minVelocityIters);
2406 		}
2407 
DefaultValue()2408 		static int DefaultValue()
2409 		{
2410 			return 1;
2411 		}
2412 	};
2413 
2414 	class ContactReportThreshold : public Element
2415 	{
2416 	public:
ContactReportThreshold(PhysXExporter & exporter,double contactReportThreshold)2417 		ContactReportThreshold(PhysXExporter & exporter, double contactReportThreshold)
2418 			: Element(exporter, CSWC::CSW_ELEMENT_CONTACT_REPORT_THRESHOLD, withPrefix)
2419 		{
2420 			getStreamWriter().appendValues(contactReportThreshold);
2421 		}
2422 
DefaultValue()2423 		static double DefaultValue()
2424 		{
2425 			return infinite();
2426 		}
2427 	};
2428 
2429 	class GlobalPose : public Element
2430 	{
2431 	public:
GlobalPose(PhysXExporter & exporter,const MQuaternion & rotation,const MVector & translation)2432 		GlobalPose(PhysXExporter& exporter, const MQuaternion & rotation, const MVector & translation)
2433 			: Element(exporter, CSWC::CSW_ELEMENT_GLOBAL_POSE, withPrefix)
2434 		{
2435 			double pose [] = { rotation.x, rotation.y, rotation.z, rotation.w, translation.x, translation.y, translation.z };
2436 			getStreamWriter().appendValues(pose, sizeof(pose) / sizeof(pose[0]));
2437 		}
2438 	};
2439 
2440 	class PxRigidBody : public Element
2441 	{
2442 	public:
PxRigidBody(PhysXExporter & exporter,const PhysXXML::PxRigidBody & rb)2443 		PxRigidBody(PhysXExporter& exporter, const PhysXXML::PxRigidBody & rb)
2444 			: Element(exporter, CSWC::CSW_ELEMENT_PX_RIGID_BODY, withPrefix)
2445 		{
2446 			exportGlobalPose(rb);
2447 			exportActorFlags(rb);
2448 			exportDominanceGroup(rb);
2449 			exportOwnerClient(rb);
2450 			if (rb.getType() == PhysXXML::PxRigidBody::Dynamic)
2451 			{
2452 				const PhysXXML::PxRigidDynamic & rd = static_cast<const PhysXXML::PxRigidDynamic&>(rb);
2453 				exportRigidBodyFlags(rd);
2454 				exportMinCCDAdvanceCoefficient(rd);
2455 				exportMaxDepenetrationVelocity(rd);
2456 				exportLinearDamping(rd);
2457 				exportAngularDamping(rd);
2458 				exportMaxAngularVelocity(rd);
2459 				exportSleepThreshold(rd);
2460 				exportStabilizationThreshold(rd);
2461 				exportWakeCounter(rd);
2462 				exportMinPositionIters(rd);
2463 				exportMinVelocityIters(rd);
2464 				exportContactReportThreshold(rd);
2465 			}
2466 		}
2467 
HasDefaultValues(const PhysXXML::PxRigidBody & rb)2468 		static bool HasDefaultValues(const PhysXXML::PxRigidBody & rb)
2469 		{
2470 			// Always export global pose
2471 			return false;
2472 		}
2473 
2474 	private:
exportGlobalPose(const PhysXXML::PxRigidBody & pxRigidBody)2475 		void exportGlobalPose(const PhysXXML::PxRigidBody & pxRigidBody)
2476 		{
2477 			GlobalPose e(getPhysXExporter(), pxRigidBody.globalPose.rotation, pxRigidBody.globalPose.translation);
2478 		}
2479 
exportActorFlags(const PhysXXML::PxRigidBody & pxRigidBody)2480 		void exportActorFlags(const PhysXXML::PxRigidBody & pxRigidBody)
2481 		{
2482 			if (pxRigidBody.actorFlags.actorFlags != ActorFlags::DefaultValue())
2483 			{
2484 				ActorFlags e(getPhysXExporter(), pxRigidBody.actorFlags.actorFlags);
2485 			}
2486 		}
2487 
exportDominanceGroup(const PhysXXML::PxRigidBody & pxRigidBody)2488 		void exportDominanceGroup(const PhysXXML::PxRigidBody & pxRigidBody)
2489 		{
2490 			if (pxRigidBody.dominanceGroup.dominanceGroup != DominanceGroup::DefaultValue())
2491 			{
2492 				DominanceGroup e(getPhysXExporter(), pxRigidBody.dominanceGroup.dominanceGroup);
2493 			}
2494 		}
2495 
exportOwnerClient(const PhysXXML::PxRigidBody & pxRigidBody)2496 		void exportOwnerClient(const PhysXXML::PxRigidBody & pxRigidBody)
2497 		{
2498 			if (pxRigidBody.ownerClient.ownerClient != OwnerClient::DefaultValue())
2499 			{
2500 				OwnerClient e(getPhysXExporter(), pxRigidBody.ownerClient.ownerClient);
2501 			}
2502 		}
2503 
exportRigidBodyFlags(const PhysXXML::PxRigidDynamic & pxRigidDynamic)2504 		void exportRigidBodyFlags(const PhysXXML::PxRigidDynamic & pxRigidDynamic)
2505 		{
2506 			if (pxRigidDynamic.rigidBodyFlags.rigidBodyFlags != RigidBodyFlags::DefaultValue())
2507 			{
2508 				RigidBodyFlags e(getPhysXExporter(), pxRigidDynamic.rigidBodyFlags.rigidBodyFlags);
2509 			}
2510 		}
2511 
exportMinCCDAdvanceCoefficient(const PhysXXML::PxRigidDynamic & pxRigidDynamic)2512 		void exportMinCCDAdvanceCoefficient(const PhysXXML::PxRigidDynamic & pxRigidDynamic)
2513 		{
2514 			if (pxRigidDynamic.minCCDAdvanceCoefficient.minCCDAdvanceCoefficient != MinCCDAdvanceCoefficient::DefaultValue())
2515 			{
2516 				MinCCDAdvanceCoefficient e(getPhysXExporter(), pxRigidDynamic.minCCDAdvanceCoefficient.minCCDAdvanceCoefficient);
2517 			}
2518 		}
2519 
exportMaxDepenetrationVelocity(const PhysXXML::PxRigidDynamic & pxRigidDynamic)2520 		void exportMaxDepenetrationVelocity(const PhysXXML::PxRigidDynamic & pxRigidDynamic)
2521 		{
2522 			if (pxRigidDynamic.maxDepenetrationVelocity.maxDepenetrationVelocity != MaxDepenetrationVelocity::DefaultValue())
2523 			{
2524 				MaxDepenetrationVelocity e(getPhysXExporter(), pxRigidDynamic.maxDepenetrationVelocity.maxDepenetrationVelocity);
2525 			}
2526 		}
2527 
exportLinearDamping(const PhysXXML::PxRigidDynamic & pxRigidDynamic)2528 		void exportLinearDamping(const PhysXXML::PxRigidDynamic & pxRigidDynamic)
2529 		{
2530 			if (pxRigidDynamic.linearDamping.linearDamping != LinearDamping::DefaultValue())
2531 			{
2532 				LinearDamping e(getPhysXExporter(), pxRigidDynamic.linearDamping.linearDamping);
2533 			}
2534 		}
2535 
exportAngularDamping(const PhysXXML::PxRigidDynamic & pxRigidDynamic)2536 		void exportAngularDamping(const PhysXXML::PxRigidDynamic & pxRigidDynamic)
2537 		{
2538 			if (pxRigidDynamic.angularDamping.angularDamping != AngularDamping::DefaultValue())
2539 			{
2540 				AngularDamping e(getPhysXExporter(), pxRigidDynamic.angularDamping.angularDamping);
2541 			}
2542 		}
2543 
exportMaxAngularVelocity(const PhysXXML::PxRigidDynamic & pxRigidDynamic)2544 		void exportMaxAngularVelocity(const PhysXXML::PxRigidDynamic & pxRigidDynamic)
2545 		{
2546 			if (pxRigidDynamic.maxAngularVelocity.maxAngularVelocity != MaxAngularVelocity::DefaultValue())
2547 			{
2548 				MaxAngularVelocity e(getPhysXExporter(), pxRigidDynamic.maxAngularVelocity.maxAngularVelocity);
2549 			}
2550 		}
2551 
exportSleepThreshold(const PhysXXML::PxRigidDynamic & pxRigidDynamic)2552 		void exportSleepThreshold(const PhysXXML::PxRigidDynamic & pxRigidDynamic)
2553 		{
2554 			if (pxRigidDynamic.sleepThreshold.sleepThreshold != SleepThreshold::DefaultValue())
2555 			{
2556 				SleepThreshold e(getPhysXExporter(), pxRigidDynamic.sleepThreshold.sleepThreshold);
2557 			}
2558 		}
2559 
exportStabilizationThreshold(const PhysXXML::PxRigidDynamic & pxRigidDynamic)2560 		void exportStabilizationThreshold(const PhysXXML::PxRigidDynamic & pxRigidDynamic)
2561 		{
2562 			if (pxRigidDynamic.stabilizationThreshold.stabilizationThreshold != StabilizationThreshold::DefaultValue())
2563 			{
2564 				StabilizationThreshold e(getPhysXExporter(), pxRigidDynamic.stabilizationThreshold.stabilizationThreshold);
2565 			}
2566 		}
2567 
exportWakeCounter(const PhysXXML::PxRigidDynamic & pxRigidDynamic)2568 		void exportWakeCounter(const PhysXXML::PxRigidDynamic & pxRigidDynamic)
2569 		{
2570 			if (pxRigidDynamic.wakeCounter.wakeCounter != WakeCounter::DefaultValue())
2571 			{
2572 				WakeCounter e(getPhysXExporter(), pxRigidDynamic.wakeCounter.wakeCounter);
2573 			}
2574 		}
2575 
exportMinPositionIters(const PhysXXML::PxRigidDynamic & pxRigidDynamic)2576 		void exportMinPositionIters(const PhysXXML::PxRigidDynamic & pxRigidDynamic)
2577 		{
2578 			if (pxRigidDynamic.solverIterationCounts.minPositionIters.minPositionIters != MinPositionIters::DefaultValue())
2579 			{
2580 				MinPositionIters e(getPhysXExporter(), pxRigidDynamic.solverIterationCounts.minPositionIters.minPositionIters);
2581 			}
2582 		}
2583 
exportMinVelocityIters(const PhysXXML::PxRigidDynamic & pxRigidDynamic)2584 		void exportMinVelocityIters(const PhysXXML::PxRigidDynamic & pxRigidDynamic)
2585 		{
2586 			if (pxRigidDynamic.solverIterationCounts.minVelocityIters.minVelocityIters != MinVelocityIters::DefaultValue())
2587 			{
2588 				MinVelocityIters e(getPhysXExporter(), pxRigidDynamic.solverIterationCounts.minVelocityIters.minVelocityIters);
2589 			}
2590 		}
2591 
exportContactReportThreshold(const PhysXXML::PxRigidDynamic & pxRigidDynamic)2592 		void exportContactReportThreshold(const PhysXXML::PxRigidDynamic & pxRigidDynamic)
2593 		{
2594 			if (pxRigidDynamic.contactReportThreshold.contactReportThreshold != ContactReportThreshold::DefaultValue())
2595 			{
2596 				ContactReportThreshold e(getPhysXExporter(), pxRigidDynamic.contactReportThreshold.contactReportThreshold);
2597 			}
2598 		}
2599 	};
2600 
2601 	class ForceToSleep : public Element
2602 	{
2603 	public:
ForceToSleep(PhysXExporter & exporter,const MObject & rigidBody,bool forceToSleep)2604 		ForceToSleep(PhysXExporter& exporter, const MObject & rigidBody, bool forceToSleep)
2605 			: Element(exporter, CSWC::CSW_ELEMENT_FORCE_TO_SLEEP)
2606 		{
2607 			getStreamWriter().appendValues(forceToSleep);
2608 		}
2609 
DefaultValue()2610 		static bool DefaultValue()
2611 		{
2612 			return false;
2613 		}
2614 
GetForceToSleep(const MObject & rb)2615 		static bool GetForceToSleep(const MObject & rb)
2616 		{
2617 			bool forceToSleep = false;
2618 			DagHelper::getPlugValue(rb, ATTR_FORCE_TO_SLEEP, forceToSleep);
2619 			return forceToSleep;
2620 		}
2621 	};
2622 
2623     class RigidBodyTechnique : public Element
2624     {
2625     public:
RigidBodyTechnique(PhysXExporter & exporter,const MObject & rigidBody,const PhysXXML::PxRigidBody & pxRigidBody,const String & profile)2626 		RigidBodyTechnique(PhysXExporter& exporter, const MObject & rigidBody, const PhysXXML::PxRigidBody & pxRigidBody, const String & profile)
2627             : Element(exporter, CSWC::CSW_ELEMENT_TECHNIQUE)
2628         {
2629             getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_PROFILE, profile);
2630 			getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_XMLNS + ":" + CSWC::CSW_PREFIX_PX, PhysXExporter::GetXMLNS());
2631 			getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_XSI_SCHEMALOCATION, PhysXExporter::GetXSISchemaLocation());
2632             if (profile == PROFILE_MAYA) {
2633 				exportForceToSleep(rigidBody);
2634 				exporter.exportExtraAttributes(rigidBody);
2635 			}
2636 			else if (profile == PhysXExporter::GetPhysXProfile()) {
2637 				exportPxRigidBody(pxRigidBody);
2638 			}
2639         }
2640 
HasDefaultValues(const MObject & rigidBody,const PhysXXML::PxRigidBody & rb,const String & profile)2641 		static bool HasDefaultValues(const MObject & rigidBody, const PhysXXML::PxRigidBody & rb, const String & profile)
2642 		{
2643 			if (profile == PhysXExporter::GetPhysXProfile())
2644 			{
2645 				return PxRigidBody::HasDefaultValues(rb);
2646 			}
2647 			else if (profile == PROFILE_MAYA)
2648 			{
2649 				return ForceToSleep::GetForceToSleep(rigidBody) == ForceToSleep::DefaultValue() &&
2650 					!PhysXExporter::HasExtraAttributes(rigidBody);
2651 			}
2652 			return true;
2653 		}
2654 
2655     private:
exportForceToSleep(const MObject & rigidBody)2656 		void exportForceToSleep(const MObject & rigidBody)
2657 		{
2658 			bool forceToSleep = ForceToSleep::GetForceToSleep(rigidBody);
2659 			if (forceToSleep != ForceToSleep::DefaultValue())
2660 			{
2661 				ForceToSleep e(getPhysXExporter(), rigidBody, forceToSleep);
2662 			}
2663 		}
2664 
exportPxRigidBody(const PhysXXML::PxRigidBody & rb)2665 		void exportPxRigidBody(const PhysXXML::PxRigidBody & rb)
2666 		{
2667 			if (!PxRigidBody::HasDefaultValues(rb))
2668 			{
2669 				PxRigidBody e(getPhysXExporter(), rb);
2670 			}
2671 		}
2672 
2673     private:
2674         static std::set<MString, MStringComp> mAttributes;
2675     };
2676     std::set<MString, MStringComp> RigidBodyTechnique::mAttributes;
2677 
2678     class RigidBodyExtra : public Element
2679     {
2680     public:
RigidBodyExtra(PhysXExporter & exporter,const MObject & rigidBody,const PhysXXML::PxRigidBody & pxRigidBody)2681 		RigidBodyExtra(PhysXExporter& exporter, const MObject & rigidBody, const PhysXXML::PxRigidBody & pxRigidBody)
2682             : Element(exporter, CSWC::CSW_ELEMENT_EXTRA)
2683         {
2684 			exportProfile(rigidBody, pxRigidBody, PROFILE_MAYA);
2685 			exportProfile(rigidBody, pxRigidBody, PhysXExporter::GetPhysXProfile());
2686         }
2687 
HasDefaultValues(const MObject & rigidBody,const PhysXXML::PxRigidBody & pxRigidBody)2688 		static bool HasDefaultValues(const MObject & rigidBody, const PhysXXML::PxRigidBody & pxRigidBody)
2689 		{
2690 			return
2691 				RigidBodyTechnique::HasDefaultValues(rigidBody, pxRigidBody, PROFILE_MAYA) &&
2692 				RigidBodyTechnique::HasDefaultValues(rigidBody, pxRigidBody, PhysXExporter::GetPhysXProfile());
2693 		}
2694 
2695     private:
exportProfile(const MObject & rigidBody,const PhysXXML::PxRigidBody & pxRigidBody,const String & profile)2696 		void exportProfile(const MObject& rigidBody, const PhysXXML::PxRigidBody & pxRigidBody, const String& profile)
2697         {
2698 			if (!RigidBodyTechnique::HasDefaultValues(rigidBody, pxRigidBody, profile))
2699 			{
2700 				RigidBodyTechnique e(getPhysXExporter(), rigidBody, pxRigidBody, profile);
2701 			}
2702         }
2703     };
2704 
2705     class RigidBody : public Element
2706     {
2707     public:
RigidBody(PhysXExporter & exporter,const MObject & rigidBody,const String & sid,const String & name="")2708         RigidBody(PhysXExporter& exporter, const MObject & rigidBody, const String & sid, const String & name = "")
2709             : Element(exporter, CSWC::CSW_ELEMENT_RIGID_BODY)
2710         {
2711             getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_SID, sid);
2712             if (name.length() > 0) {
2713                 getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_NAME, name);
2714             }
2715 
2716 			const PhysXXML::PxRigidBody* pxRigidBody = exporter.findPxRigidBody(rigidBody);
2717 			if (pxRigidBody)
2718 			{
2719 				exportTechniqueCommon(rigidBody, *pxRigidBody, sid);
2720 				exportExtra(rigidBody, *pxRigidBody);
2721 			}
2722         }
2723 
RigidBody(PhysXExporter & exporter,const PhysXXML::PxRigidBody & pxRigidBody,const String & sid,const String & name="")2724 		RigidBody(PhysXExporter& exporter, const PhysXXML::PxRigidBody & pxRigidBody, const String & sid, const String & name = "")
2725 			: Element(exporter, CSWC::CSW_ELEMENT_RIGID_BODY)
2726 		{
2727 			MObject rigidBody;
2728 			getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_SID, sid);
2729 			if (name.length() > 0) {
2730 				getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_NAME, name);
2731 			}
2732 
2733 			exportTechniqueCommon(rigidBody, pxRigidBody, sid);
2734 			exportExtra(rigidBody, pxRigidBody);
2735 		}
2736 
2737     private:
exportTechniqueCommon(const MObject & rigidBody,const PhysXXML::PxRigidBody & pxRigidBody,const String & sid)2738 		void exportTechniqueCommon(const MObject & rigidBody, const PhysXXML::PxRigidBody & pxRigidBody, const String & sid)
2739         {
2740 			RigidBodyTechniqueCommon e(getPhysXExporter(), rigidBody, pxRigidBody, sid);
2741         }
2742 
exportExtra(const MObject & rigidBody,const PhysXXML::PxRigidBody & pxRigidBody)2743 		void exportExtra(const MObject & rigidBody, const PhysXXML::PxRigidBody & pxRigidBody)
2744         {
2745 			if (!RigidBodyExtra::HasDefaultValues(rigidBody, pxRigidBody))
2746 			{
2747 				RigidBodyExtra e(getPhysXExporter(), rigidBody, pxRigidBody);
2748 			}
2749         }
2750     };
2751 
2752 	class IAttachment
2753 	{
2754 	public:
exportRotateTranslate(PhysXExporter & exporter,uint64_t actor,const MVector & localPoseActorTranslation,const MQuaternion & localPoseActorRotation)2755 		void exportRotateTranslate(PhysXExporter & exporter, uint64_t actor, const MVector & localPoseActorTranslation, const MQuaternion & localPoseActorRotation)
2756 		{
2757 			const PhysXXML::PxRigidBody* pxRigidBody = exporter.findPxRigidBody(actor);
2758 
2759 			MVector translation = uiToInternal(localPoseActorTranslation);
2760 			MEulerRotation rotation = localPoseActorRotation.asEulerRotation();
2761 
2762 			if (pxRigidBody)
2763 			{
2764 				MObject target = DagHelper::getNode(pxRigidBody->name.name.c_str());
2765 				MObject rigidBody = exporter.getNodeRigidBody(target);
2766 				if (!rigidBody.isNull())
2767 				{
2768 					MMatrix targetWorld = PhysXExporter::GetRigidBodyTargetTM(rigidBody);
2769 					MMatrix constraintLocal = PxTransformToMMatrix(localPoseActorTranslation, localPoseActorRotation);
2770 					MMatrix rigidBodyWorld = PxTransformToMMatrix(pxRigidBody->globalPose.translation, pxRigidBody->globalPose.rotation);
2771 
2772 					constraintLocal = constraintLocal * rigidBodyWorld * targetWorld.inverse();
2773 
2774 					MTransformationMatrix tm(constraintLocal);
2775 					translation = tm.getTranslation(MSpace::kTransform);
2776 					rotation = tm.eulerRotation();
2777 					rotation.order = static_cast<MEulerRotation::RotationOrder>(static_cast<int>(tm.rotationOrder()) - MTransformationMatrix::kXYZ + MEulerRotation::kXYZ);
2778 				}
2779 			}
2780 
2781 			exporter.exportTranslation(translation, ATTR_TRANSLATE);
2782 			exporter.exportRotation(rotation, ATTR_ROTATE);
2783 		}
2784 	};
2785 
2786     class RefAttachment : public Element, public IAttachment
2787     {
2788     public:
RefAttachment(PhysXExporter & exporter,const PhysXXML::PxD6Joint & joint,const URI & attachmentURI)2789 		RefAttachment(PhysXExporter& exporter, const PhysXXML::PxD6Joint & joint, const URI & attachmentURI)
2790             : Element(exporter, CSWC::CSW_ELEMENT_REF_ATTACHMENT)
2791         {
2792             getStreamWriter().appendURIAttribute(CSWC::CSW_ATTRIBUTE_RIGID_BODY, attachmentURI);
2793             exportRotateTranslate(joint);
2794         }
2795 
2796     private:
exportRotateTranslate(const PhysXXML::PxD6Joint & joint)2797 		void exportRotateTranslate(const PhysXXML::PxD6Joint & joint)
2798         {
2799 			IAttachment::exportRotateTranslate(getPhysXExporter(), joint.actors.actor0.actor0, joint.localPose.eActor0.translation, joint.localPose.eActor0.rotation);
2800         }
2801     };
2802 
2803     class Attachment : public Element, public IAttachment
2804     {
2805     public:
Attachment(PhysXExporter & exporter,const PhysXXML::PxD6Joint & joint,const URI & attachmentURI)2806 		Attachment(PhysXExporter& exporter, const PhysXXML::PxD6Joint & joint, const URI & attachmentURI)
2807             : Element(exporter, CSWC::CSW_ELEMENT_ATTACHMENT)
2808         {
2809             getStreamWriter().appendURIAttribute(CSWC::CSW_ATTRIBUTE_RIGID_BODY, attachmentURI);
2810             exportRotateTranslate(joint);
2811         }
2812 
2813     private:
exportRotateTranslate(const PhysXXML::PxD6Joint & joint)2814 		void exportRotateTranslate(const PhysXXML::PxD6Joint & joint)
2815         {
2816 			IAttachment::exportRotateTranslate(getPhysXExporter(), joint.actors.actor1.actor1, joint.localPose.eActor1.translation, joint.localPose.eActor1.rotation);
2817         }
2818     };
2819 
2820 	class BreakForce : public Element
2821 	{
2822 	public:
BreakForce(PhysXExporter & exporter,double breakForce)2823 		BreakForce(PhysXExporter & exporter, double breakForce)
2824 			: Element(exporter, CSWC::CSW_ELEMENT_BREAK_FORCE, withPrefix)
2825 		{
2826 			getStreamWriter().appendValues(breakForce);
2827 		}
2828 
DefaultValue()2829 		static double DefaultValue()
2830 		{
2831 			return infinite();
2832 		}
2833 	};
2834 
2835 	class BreakTorque : public Element
2836 	{
2837 	public:
BreakTorque(PhysXExporter & exporter,double breakTorque)2838 		BreakTorque(PhysXExporter & exporter, double breakTorque)
2839 			: Element(exporter, CSWC::CSW_ELEMENT_BREAK_TORQUE, withPrefix)
2840 		{
2841 			getStreamWriter().appendValues(breakTorque);
2842 		}
2843 
DefaultValue()2844 		static double DefaultValue()
2845 		{
2846 			return infinite();
2847 		}
2848 	};
2849 
2850 	class ConstraintFlags : public Element
2851 	{
2852 	public:
ConstraintFlags(PhysXExporter & exporter,const Flags<PhysXXML::ConstraintFlags::FlagEnum> & flags)2853 		ConstraintFlags(PhysXExporter & exporter, const Flags<PhysXXML::ConstraintFlags::FlagEnum> & flags)
2854 			: Element(exporter, CSWC::CSW_ELEMENT_CONSTRAINT_FLAGS, withPrefix)
2855 		{
2856 			getStreamWriter().appendValues(PhysXExporter::ConstraintFlagsToCOLLADA(flags));
2857 		}
2858 
DefaultValue()2859 		static Flags<PhysXXML::ConstraintFlags::FlagEnum> DefaultValue()
2860 		{
2861 			return Flags<PhysXXML::ConstraintFlags::FlagEnum>();
2862 		}
2863 	};
2864 
2865 	class InvMassScale0 : public Element
2866 	{
2867 	public:
InvMassScale0(PhysXExporter & exporter,double invMassScale0)2868 		InvMassScale0(PhysXExporter & exporter, double invMassScale0)
2869 			: Element(exporter, CSWC::CSW_ELEMENT_INV_MASS_SCALE_0, withPrefix)
2870 		{
2871 			getStreamWriter().appendValues(invMassScale0);
2872 		}
2873 
DefaultValue()2874 		static double DefaultValue()
2875 		{
2876 			return 1.0;
2877 		}
2878 	};
2879 
2880 	class InvInertiaScale0 : public Element
2881 	{
2882 	public:
InvInertiaScale0(PhysXExporter & exporter,double invInertiaScale0)2883 		InvInertiaScale0(PhysXExporter & exporter, double invInertiaScale0)
2884 			: Element(exporter, CSWC::CSW_ELEMENT_INV_INERTIA_SCALE_0, withPrefix)
2885 		{
2886 			getStreamWriter().appendValues(invInertiaScale0);
2887 		}
2888 
DefaultValue()2889 		static double DefaultValue()
2890 		{
2891 			return 1.0;
2892 		}
2893 	};
2894 
2895 	class InvMassScale1 : public Element
2896 	{
2897 	public:
InvMassScale1(PhysXExporter & exporter,double invMassScale1)2898 		InvMassScale1(PhysXExporter & exporter, double invMassScale1)
2899 			: Element(exporter, CSWC::CSW_ELEMENT_INV_MASS_SCALE_1, withPrefix)
2900 		{
2901 			getStreamWriter().appendValues(invMassScale1);
2902 		}
2903 
DefaultValue()2904 		static double DefaultValue()
2905 		{
2906 			return 1.0;
2907 		}
2908 	};
2909 
2910 	class InvInertiaScale1 : public Element
2911 	{
2912 	public:
InvInertiaScale1(PhysXExporter & exporter,double invInertiaScale1)2913 		InvInertiaScale1(PhysXExporter & exporter, double invInertiaScale1)
2914 			: Element(exporter, CSWC::CSW_ELEMENT_INV_INERTIA_SCALE_1, withPrefix)
2915 		{
2916 			getStreamWriter().appendValues(invInertiaScale1);
2917 		}
2918 
DefaultValue()2919 		static double DefaultValue()
2920 		{
2921 			return 1.0;
2922 		}
2923 	};
2924 
2925 	class ProjectionLinearTolerance : public Element
2926 	{
2927 	public:
ProjectionLinearTolerance(PhysXExporter & exporter,double projectionLinearTolerance)2928 		ProjectionLinearTolerance(PhysXExporter & exporter, double projectionLinearTolerance)
2929 			: Element(exporter, CSWC::CSW_ELEMENT_PROJECTION_LINEAR_TOLERANCE, withPrefix)
2930 		{
2931 			getStreamWriter().appendValues(projectionLinearTolerance);
2932 		}
2933 
DefaultValue()2934 		static double DefaultValue()
2935 		{
2936 			return 1e10;
2937 		}
2938 	};
2939 
2940 	class ProjectionAngularTolerance : public Element
2941 	{
2942 	public:
ProjectionAngularTolerance(PhysXExporter & exporter,double projectionAngularTolerance)2943 		ProjectionAngularTolerance(PhysXExporter & exporter, double projectionAngularTolerance)
2944 			: Element(exporter, CSWC::CSW_ELEMENT_PROJECTION_ANGULAR_TOLERANCE, withPrefix)
2945 		{
2946 			getStreamWriter().appendValues(COLLADABU::Math::Utils::radToDeg(projectionAngularTolerance));
2947 		}
2948 
DefaultValue()2949 		static double DefaultValue()
2950 		{
2951 			return M_PI;
2952 		}
2953 	};
2954 
2955 	class BounceThreshold : public Element
2956 	{
2957 	public:
BounceThreshold(PhysXExporter & exporter,double bounceThreshold)2958 		BounceThreshold(PhysXExporter & exporter, double bounceThreshold)
2959 			: Element(exporter, CSWC::CSW_ELEMENT_BOUNCE_THRESHOLD, withPrefix)
2960 		{
2961 			getStreamWriter().appendValues(bounceThreshold);
2962 		}
2963 
DefaultValue()2964 		static double DefaultValue()
2965 		{
2966 			return 0.0;
2967 		}
2968 	};
2969 
2970 	class ContactDistance : public Element
2971 	{
2972 	public:
ContactDistance(PhysXExporter & exporter,double contactDistance)2973 		ContactDistance(PhysXExporter & exporter, double contactDistance)
2974 			: Element(exporter, CSWC::CSW_ELEMENT_CONTACT_DISTANCE, withPrefix)
2975 		{
2976 			getStreamWriter().appendValues(contactDistance);
2977 		}
2978 
DefaultValue()2979 		static double DefaultValue()
2980 		{
2981 			return 0.0;
2982 		}
2983 	};
2984 
2985 	class LimitsLinearExtra : public Element
2986 	{
2987 	public:
LimitsLinearExtra(PhysXExporter & exporter,const PhysXXML::PxD6Joint & joint)2988 		LimitsLinearExtra(PhysXExporter & exporter, const PhysXXML::PxD6Joint & joint)
2989 			: Element(exporter, CSWC::CSW_ELEMENT_LINEAR_EXTRA, withPrefix)
2990 		{
2991 			exportRestitution(joint);
2992 			exportBounceThreshold(joint);
2993 			exportContactDistance(joint);
2994 		}
2995 
HasDefaultValues(const PhysXXML::PxD6Joint & joint)2996 		static bool HasDefaultValues(const PhysXXML::PxD6Joint & joint)
2997 		{
2998 			return
2999 				joint.linearLimit.restitution.restitution == Restitution::DefaultValue() &&
3000 				joint.linearLimit.bounceThreshold.bounceThreshold == BounceThreshold::DefaultValue() &&
3001 				joint.linearLimit.contactDistance.contactDistance == ContactDistance::DefaultValue();
3002 		}
3003 
3004 	private:
exportRestitution(const PhysXXML::PxD6Joint & joint)3005 		void exportRestitution(const PhysXXML::PxD6Joint & joint)
3006 		{
3007 			if (joint.linearLimit.restitution.restitution != Restitution::DefaultValue())
3008 			{
3009 				Restitution e(getPhysXExporter(), joint.linearLimit.restitution.restitution);
3010 			}
3011 		}
3012 
exportBounceThreshold(const PhysXXML::PxD6Joint & joint)3013 		void exportBounceThreshold(const PhysXXML::PxD6Joint & joint)
3014 		{
3015 			if (joint.linearLimit.bounceThreshold.bounceThreshold != BounceThreshold::DefaultValue())
3016 			{
3017 				BounceThreshold e(getPhysXExporter(), joint.linearLimit.bounceThreshold.bounceThreshold);
3018 			}
3019 		}
3020 
exportContactDistance(const PhysXXML::PxD6Joint & joint)3021 		void exportContactDistance(const PhysXXML::PxD6Joint & joint)
3022 		{
3023 			if (joint.linearLimit.contactDistance.contactDistance != ContactDistance::DefaultValue())
3024 			{
3025 				ContactDistance e(getPhysXExporter(), joint.linearLimit.contactDistance.contactDistance);
3026 			}
3027 		}
3028 	};
3029 
3030 	class Restitution2 : public Element
3031 	{
3032 	public:
Restitution2(PhysXExporter & exporter,double swingRestitution,double twistRestitution)3033 		Restitution2(PhysXExporter & exporter, double swingRestitution, double twistRestitution)
3034 			: Element(exporter, CSWC::CSW_ELEMENT_RESTITUTION, withPrefix)
3035 		{
3036 			getStreamWriter().appendValues(swingRestitution, twistRestitution);
3037 		}
3038 
AreDefaultValues(double swingRestitution,double twistRestitution)3039 		static bool AreDefaultValues(double swingRestitution, double twistRestitution)
3040 		{
3041 			return swingRestitution == Restitution::DefaultValue() && twistRestitution == Restitution::DefaultValue();
3042 		}
3043 	};
3044 
3045 	class BounceThreshold2 : public Element
3046 	{
3047 	public:
BounceThreshold2(PhysXExporter & exporter,double swingBounceThreshold,double twistBounceThreshold)3048 		BounceThreshold2(PhysXExporter & exporter, double swingBounceThreshold, double twistBounceThreshold)
3049 			: Element(exporter, CSWC::CSW_ELEMENT_BOUNCE_THRESHOLD, withPrefix)
3050 		{
3051 			getStreamWriter().appendValues(swingBounceThreshold, twistBounceThreshold);
3052 		}
3053 
AreDefaultValues(double swingBounceThreshold,double twistBounceThreshold)3054 		static bool AreDefaultValues(double swingBounceThreshold, double twistBounceThreshold)
3055 		{
3056 			return swingBounceThreshold == BounceThreshold::DefaultValue() && twistBounceThreshold == BounceThreshold::DefaultValue();
3057 		}
3058 	};
3059 
3060 	class ContactDistance2 : public Element
3061 	{
3062 	public:
ContactDistance2(PhysXExporter & exporter,double swingContactDistance,double twistContactDistance)3063 		ContactDistance2(PhysXExporter & exporter, double swingContactDistance, double twistContactDistance)
3064 			: Element(exporter, CSWC::CSW_ELEMENT_CONTACT_DISTANCE, withPrefix)
3065 		{
3066 			getStreamWriter().appendValues(swingContactDistance, twistContactDistance);
3067 		}
3068 
AreDefaultValues(double swingContactDistance,double twistContactDistance)3069 		static bool AreDefaultValues(double swingContactDistance, double twistContactDistance)
3070 		{
3071 			return swingContactDistance == ContactDistance::DefaultValue() && twistContactDistance == ContactDistance::DefaultValue();
3072 		}
3073 	};
3074 
3075 	class SwingConeAndTwistExtra : public Element
3076 	{
3077 	public:
SwingConeAndTwistExtra(PhysXExporter & exporter,const PhysXXML::PxD6Joint & joint)3078 		SwingConeAndTwistExtra(PhysXExporter & exporter, const PhysXXML::PxD6Joint & joint)
3079 			: Element(exporter, CSWC::CSW_ELEMENT_SWING_CONE_AND_TWIST_EXTRA, withPrefix)
3080 		{
3081 			exportRestitution(joint);
3082 			exportBounceThreshold(joint);
3083 			exportContactDistance(joint);
3084 		}
3085 
HasDefaultValues(const PhysXXML::PxD6Joint & joint)3086 		static bool HasDefaultValues(const PhysXXML::PxD6Joint & joint)
3087 		{
3088 			return
3089 				Restitution2::AreDefaultValues(joint.swingLimit.restitution.restitution, joint.twistLimit.restitution.restitution) &&
3090 				BounceThreshold2::AreDefaultValues(joint.swingLimit.bounceThreshold.bounceThreshold, joint.twistLimit.bounceThreshold.bounceThreshold) &&
3091 				ContactDistance2::AreDefaultValues(joint.swingLimit.contactDistance.contactDistance, joint.twistLimit.contactDistance.contactDistance);
3092 		}
3093 
3094 	private:
exportRestitution(const PhysXXML::PxD6Joint & joint)3095 		void exportRestitution(const PhysXXML::PxD6Joint & joint)
3096 		{
3097 			if (!Restitution2::AreDefaultValues(joint.swingLimit.restitution.restitution, joint.twistLimit.restitution.restitution))
3098 			{
3099 				Restitution2 e(getPhysXExporter(), joint.swingLimit.restitution.restitution, joint.twistLimit.restitution.restitution);
3100 			}
3101 		}
3102 
exportBounceThreshold(const PhysXXML::PxD6Joint & joint)3103 		void exportBounceThreshold(const PhysXXML::PxD6Joint & joint)
3104 		{
3105 			if (!BounceThreshold2::AreDefaultValues(joint.swingLimit.bounceThreshold.bounceThreshold, joint.twistLimit.bounceThreshold.bounceThreshold))
3106 			{
3107 				BounceThreshold2 e(getPhysXExporter(), joint.swingLimit.bounceThreshold.bounceThreshold, joint.twistLimit.bounceThreshold.bounceThreshold);
3108 			}
3109 		}
3110 
exportContactDistance(const PhysXXML::PxD6Joint & joint)3111 		void exportContactDistance(const PhysXXML::PxD6Joint & joint)
3112 		{
3113 			if (!ContactDistance2::AreDefaultValues(joint.swingLimit.contactDistance.contactDistance, joint.twistLimit.contactDistance.contactDistance))
3114 			{
3115 				ContactDistance2 e(getPhysXExporter(), joint.swingLimit.contactDistance.contactDistance, joint.twistLimit.contactDistance.contactDistance);
3116 			}
3117 		}
3118 	};
3119 
3120 	class LimitsExtra : public Element
3121 	{
3122 	public:
LimitsExtra(PhysXExporter & exporter,const PhysXXML::PxD6Joint & joint)3123 		LimitsExtra(PhysXExporter & exporter, const PhysXXML::PxD6Joint & joint)
3124 			: Element(exporter, CSWC::CSW_ELEMENT_LIMITS_EXTRA, withPrefix)
3125 		{
3126 			exportLinearExtra(joint);
3127 			exportSwingConeAndTwistExtra(joint);
3128 		}
3129 
HasDefaultValues(const PhysXXML::PxD6Joint & joint)3130 		static bool HasDefaultValues(const PhysXXML::PxD6Joint & joint)
3131 		{
3132 			return LimitsLinearExtra::HasDefaultValues(joint) &&
3133 				SwingConeAndTwistExtra::HasDefaultValues(joint);
3134 		}
3135 
3136 	private:
exportLinearExtra(const PhysXXML::PxD6Joint & joint)3137 		void exportLinearExtra(const PhysXXML::PxD6Joint & joint)
3138 		{
3139 			if (!LimitsLinearExtra::HasDefaultValues(joint))
3140 			{
3141 				LimitsLinearExtra e(getPhysXExporter(), joint);
3142 			}
3143 		}
3144 
exportSwingConeAndTwistExtra(const PhysXXML::PxD6Joint & joint)3145 		void exportSwingConeAndTwistExtra(const PhysXXML::PxD6Joint & joint)
3146 		{
3147 			if (!SwingConeAndTwistExtra::HasDefaultValues(joint))
3148 			{
3149 				SwingConeAndTwistExtra e(getPhysXExporter(), joint);
3150 			}
3151 		}
3152 	};
3153 
3154 	class SpringAngularExtra : public Element
3155 	{
3156 	public:
SpringAngularExtra(PhysXExporter & exporter,const PhysXXML::PxD6Joint & joint)3157 		SpringAngularExtra(PhysXExporter & exporter, const PhysXXML::PxD6Joint & joint)
3158 			: Element(exporter, CSWC::CSW_ELEMENT_ANGULAR_EXTRA, withPrefix)
3159 		{
3160 			exportStiffness(joint);
3161 			exportDamping(joint);
3162 		}
3163 
HasDefaultValues(const PhysXXML::PxD6Joint & joint)3164 		static bool HasDefaultValues(const PhysXXML::PxD6Joint & joint)
3165 		{
3166 			return joint.twistLimit.stiffness.stiffness == Stiffness::DefaultValue() &&
3167 				joint.twistLimit.damping.damping == Damping::DefaultValue();
3168 		}
3169 
3170 	private:
exportStiffness(const PhysXXML::PxD6Joint & joint)3171 		void exportStiffness(const PhysXXML::PxD6Joint & joint)
3172 		{
3173 			if (joint.twistLimit.stiffness.stiffness != Stiffness::DefaultValue())
3174 			{
3175 				Stiffness e(getPhysXExporter(), joint.twistLimit.stiffness.stiffness, withPrefix);
3176 			}
3177 		}
3178 
exportDamping(const PhysXXML::PxD6Joint & joint)3179 		void exportDamping(const PhysXXML::PxD6Joint & joint)
3180 		{
3181 			if (joint.twistLimit.damping.damping != Damping::DefaultValue())
3182 			{
3183 				Damping e(getPhysXExporter(), joint.twistLimit.damping.damping, withPrefix);
3184 			}
3185 		}
3186 	};
3187 
3188 	class SpringExtra : public Element
3189 	{
3190 	public:
SpringExtra(PhysXExporter & exporter,const PhysXXML::PxD6Joint & joint)3191 		SpringExtra(PhysXExporter & exporter, const PhysXXML::PxD6Joint & joint)
3192 			: Element(exporter, CSWC::CSW_ELEMENT_SPRING_EXTRA, withPrefix)
3193 		{
3194 			exportAngularExtra(joint);
3195 		}
3196 
HasDefaultValues(const PhysXXML::PxD6Joint & joint)3197 		static bool HasDefaultValues(const PhysXXML::PxD6Joint & joint)
3198 		{
3199 			return SpringAngularExtra::HasDefaultValues(joint);
3200 		}
3201 
3202 	private:
exportAngularExtra(const PhysXXML::PxD6Joint & joint)3203 		void exportAngularExtra(const PhysXXML::PxD6Joint & joint)
3204 		{
3205 			if (!SpringAngularExtra::HasDefaultValues(joint))
3206 			{
3207 				SpringAngularExtra e(getPhysXExporter(), joint);
3208 			}
3209 		}
3210 	};
3211 
3212 	class ForceLimit : public Element
3213 	{
3214 	public:
ForceLimit(PhysXExporter & exporter,double forceLimit)3215 		ForceLimit(PhysXExporter & exporter, double forceLimit)
3216 			: Element(exporter, CSWC::CSW_ELEMENT_FORCE_LIMIT, withPrefix)
3217 		{
3218 			getStreamWriter().appendValues(forceLimit);
3219 		}
3220 
DefaultValue()3221 		static double DefaultValue()
3222 		{
3223 			return infinite();
3224 		}
3225 	};
3226 
3227 	class DriveFlags : public Element
3228 	{
3229 	public:
DriveFlags(PhysXExporter & exporter,const Flags<PhysXXML::DriveFlags::FlagEnum> & flags)3230 		DriveFlags(PhysXExporter & exporter, const Flags<PhysXXML::DriveFlags::FlagEnum> & flags)
3231 			: Element(exporter, CSWC::CSW_ELEMENT_DRIVE_FLAGS, withPrefix)
3232 		{
3233 			getStreamWriter().appendValues(PhysXExporter::DriveFlagsToCOLLADA(flags));
3234 		}
3235 
DefaultValue()3236 		static Flags<PhysXXML::DriveFlags::FlagEnum> DefaultValue()
3237 		{
3238 			return Flags<PhysXXML::DriveFlags::FlagEnum>();
3239 		}
3240 	};
3241 
3242 	class LinearX : public Element
3243 	{
3244 	public:
LinearX(PhysXExporter & exporter,const PhysXXML::PxD6Joint & joint)3245 		LinearX(PhysXExporter & exporter, const PhysXXML::PxD6Joint & joint)
3246 			: Element(exporter, CSWC::CSW_ELEMENT_LINEAR_X, withPrefix)
3247 		{
3248 			exportStiffness(joint);
3249 			exportDamping(joint);
3250 			exportForceLimit(joint);
3251 			exportDriveFlags(joint);
3252 		}
3253 
HasDefaultValues(const PhysXXML::PxD6Joint & joint)3254 		static bool HasDefaultValues(const PhysXXML::PxD6Joint & joint)
3255 		{
3256 			return joint.drive.driveX.stiffness.stiffness == Stiffness::DefaultValue() &&
3257 				joint.drive.driveX.damping.damping == Damping::DefaultValue() &&
3258 				joint.drive.driveX.forceLimit.forceLimit == ForceLimit::DefaultValue() &&
3259 				joint.drive.driveX.flags.flags == DriveFlags::DefaultValue();
3260 		}
3261 
3262 	private:
exportStiffness(const PhysXXML::PxD6Joint & joint)3263 		void exportStiffness(const PhysXXML::PxD6Joint & joint)
3264 		{
3265 			if (joint.drive.driveX.stiffness.stiffness != Stiffness::DefaultValue())
3266 			{
3267 				Stiffness e(getPhysXExporter(), joint.drive.driveX.stiffness.stiffness, withPrefix);
3268 			}
3269 		}
3270 
exportDamping(const PhysXXML::PxD6Joint & joint)3271 		void exportDamping(const PhysXXML::PxD6Joint & joint)
3272 		{
3273 			if (joint.drive.driveX.damping.damping != Damping::DefaultValue())
3274 			{
3275 				Damping e(getPhysXExporter(), joint.drive.driveX.damping.damping, withPrefix);
3276 			}
3277 		}
3278 
exportForceLimit(const PhysXXML::PxD6Joint & joint)3279 		void exportForceLimit(const PhysXXML::PxD6Joint & joint)
3280 		{
3281 			if (joint.drive.driveX.forceLimit.forceLimit != ForceLimit::DefaultValue())
3282 			{
3283 				ForceLimit e(getPhysXExporter(), joint.drive.driveX.forceLimit.forceLimit);
3284 			}
3285 		}
3286 
exportDriveFlags(const PhysXXML::PxD6Joint & joint)3287 		void exportDriveFlags(const PhysXXML::PxD6Joint & joint)
3288 		{
3289 			if (joint.drive.driveX.flags.flags != DriveFlags::DefaultValue())
3290 			{
3291 				DriveFlags e(getPhysXExporter(), joint.drive.driveX.flags.flags);
3292 			}
3293 		}
3294 	};
3295 
3296 	class LinearY : public Element
3297 	{
3298 	public:
LinearY(PhysXExporter & exporter,const PhysXXML::PxD6Joint & joint)3299 		LinearY(PhysXExporter & exporter, const PhysXXML::PxD6Joint & joint)
3300 			: Element(exporter, CSWC::CSW_ELEMENT_LINEAR_Y, withPrefix)
3301 		{
3302 			exportStiffness(joint);
3303 			exportDamping(joint);
3304 			exportForceLimit(joint);
3305 			exportDriveFlags(joint);
3306 		}
3307 
HasDefaultValues(const PhysXXML::PxD6Joint & joint)3308 		static bool HasDefaultValues(const PhysXXML::PxD6Joint & joint)
3309 		{
3310 			return joint.drive.driveY.stiffness.stiffness == Stiffness::DefaultValue() &&
3311 				joint.drive.driveY.damping.damping == Damping::DefaultValue() &&
3312 				joint.drive.driveY.forceLimit.forceLimit == ForceLimit::DefaultValue() &&
3313 				joint.drive.driveY.flags.flags == DriveFlags::DefaultValue();
3314 		}
3315 
3316 	private:
exportStiffness(const PhysXXML::PxD6Joint & joint)3317 		void exportStiffness(const PhysXXML::PxD6Joint & joint)
3318 		{
3319 			if (joint.drive.driveY.stiffness.stiffness != Stiffness::DefaultValue())
3320 			{
3321 				Stiffness e(getPhysXExporter(), joint.drive.driveY.stiffness.stiffness, withPrefix);
3322 			}
3323 		}
3324 
exportDamping(const PhysXXML::PxD6Joint & joint)3325 		void exportDamping(const PhysXXML::PxD6Joint & joint)
3326 		{
3327 			if (joint.drive.driveY.damping.damping != Damping::DefaultValue())
3328 			{
3329 				Damping e(getPhysXExporter(), joint.drive.driveY.damping.damping, withPrefix);
3330 			}
3331 		}
3332 
exportForceLimit(const PhysXXML::PxD6Joint & joint)3333 		void exportForceLimit(const PhysXXML::PxD6Joint & joint)
3334 		{
3335 			if (joint.drive.driveY.forceLimit.forceLimit != ForceLimit::DefaultValue())
3336 			{
3337 				ForceLimit e(getPhysXExporter(), joint.drive.driveY.forceLimit.forceLimit);
3338 			}
3339 		}
3340 
exportDriveFlags(const PhysXXML::PxD6Joint & joint)3341 		void exportDriveFlags(const PhysXXML::PxD6Joint & joint)
3342 		{
3343 			if (joint.drive.driveY.flags.flags != DriveFlags::DefaultValue())
3344 			{
3345 				DriveFlags e(getPhysXExporter(), joint.drive.driveY.flags.flags);
3346 			}
3347 		}
3348 	};
3349 
3350 	class LinearZ : public Element
3351 	{
3352 	public:
LinearZ(PhysXExporter & exporter,const PhysXXML::PxD6Joint & joint)3353 		LinearZ(PhysXExporter & exporter, const PhysXXML::PxD6Joint & joint)
3354 			: Element(exporter, CSWC::CSW_ELEMENT_LINEAR_Z, withPrefix)
3355 		{
3356 			exportStiffness(joint);
3357 			exportDamping(joint);
3358 			exportForceLimit(joint);
3359 			exportDriveFlags(joint);
3360 		}
3361 
HasDefaultValues(const PhysXXML::PxD6Joint & joint)3362 		static bool HasDefaultValues(const PhysXXML::PxD6Joint & joint)
3363 		{
3364 			return joint.drive.driveZ.stiffness.stiffness == Stiffness::DefaultValue() &&
3365 				joint.drive.driveZ.damping.damping == Damping::DefaultValue() &&
3366 				joint.drive.driveZ.forceLimit.forceLimit == ForceLimit::DefaultValue() &&
3367 				joint.drive.driveZ.flags.flags == DriveFlags::DefaultValue();
3368 		}
3369 
3370 	private:
exportStiffness(const PhysXXML::PxD6Joint & joint)3371 		void exportStiffness(const PhysXXML::PxD6Joint & joint)
3372 		{
3373 			if (joint.drive.driveZ.stiffness.stiffness != Stiffness::DefaultValue())
3374 			{
3375 				Stiffness e(getPhysXExporter(), joint.drive.driveZ.stiffness.stiffness, withPrefix);
3376 			}
3377 		}
3378 
exportDamping(const PhysXXML::PxD6Joint & joint)3379 		void exportDamping(const PhysXXML::PxD6Joint & joint)
3380 		{
3381 			if (joint.drive.driveZ.damping.damping != Damping::DefaultValue())
3382 			{
3383 				Damping e(getPhysXExporter(), joint.drive.driveZ.damping.damping, withPrefix);
3384 			}
3385 		}
3386 
exportForceLimit(const PhysXXML::PxD6Joint & joint)3387 		void exportForceLimit(const PhysXXML::PxD6Joint & joint)
3388 		{
3389 			if (joint.drive.driveZ.forceLimit.forceLimit != ForceLimit::DefaultValue())
3390 			{
3391 				ForceLimit e(getPhysXExporter(), joint.drive.driveZ.forceLimit.forceLimit);
3392 			}
3393 		}
3394 
exportDriveFlags(const PhysXXML::PxD6Joint & joint)3395 		void exportDriveFlags(const PhysXXML::PxD6Joint & joint)
3396 		{
3397 			if (joint.drive.driveZ.flags.flags != DriveFlags::DefaultValue())
3398 			{
3399 				DriveFlags e(getPhysXExporter(), joint.drive.driveZ.flags.flags);
3400 			}
3401 		}
3402 	};
3403 
3404 	class Swing : public Element
3405 	{
3406 	public:
Swing(PhysXExporter & exporter,const PhysXXML::PxD6Joint & joint)3407 		Swing(PhysXExporter & exporter, const PhysXXML::PxD6Joint & joint)
3408 			: Element(exporter, CSWC::CSW_ELEMENT_SWING, withPrefix)
3409 		{
3410 			exportStiffness(joint);
3411 			exportDamping(joint);
3412 			exportForceLimit(joint);
3413 			exportDriveFlags(joint);
3414 		}
3415 
HasDefaultValues(const PhysXXML::PxD6Joint & joint)3416 		static bool HasDefaultValues(const PhysXXML::PxD6Joint & joint)
3417 		{
3418 			return joint.drive.driveSwing.stiffness.stiffness == Stiffness::DefaultValue() &&
3419 				joint.drive.driveSwing.damping.damping == Damping::DefaultValue() &&
3420 				joint.drive.driveSwing.forceLimit.forceLimit == ForceLimit::DefaultValue() &&
3421 				joint.drive.driveSwing.flags.flags == DriveFlags::DefaultValue();
3422 		}
3423 
3424 	private:
exportStiffness(const PhysXXML::PxD6Joint & joint)3425 		void exportStiffness(const PhysXXML::PxD6Joint & joint)
3426 		{
3427 			if (joint.drive.driveSwing.stiffness.stiffness != Stiffness::DefaultValue())
3428 			{
3429 				Stiffness e(getPhysXExporter(), joint.drive.driveSwing.stiffness.stiffness, withPrefix);
3430 			}
3431 		}
3432 
exportDamping(const PhysXXML::PxD6Joint & joint)3433 		void exportDamping(const PhysXXML::PxD6Joint & joint)
3434 		{
3435 			if (joint.drive.driveSwing.damping.damping != Damping::DefaultValue())
3436 			{
3437 				Damping e(getPhysXExporter(), joint.drive.driveSwing.damping.damping, withPrefix);
3438 			}
3439 		}
3440 
exportForceLimit(const PhysXXML::PxD6Joint & joint)3441 		void exportForceLimit(const PhysXXML::PxD6Joint & joint)
3442 		{
3443 			if (joint.drive.driveSwing.forceLimit.forceLimit != ForceLimit::DefaultValue())
3444 			{
3445 				ForceLimit e(getPhysXExporter(), joint.drive.driveSwing.forceLimit.forceLimit);
3446 			}
3447 		}
3448 
exportDriveFlags(const PhysXXML::PxD6Joint & joint)3449 		void exportDriveFlags(const PhysXXML::PxD6Joint & joint)
3450 		{
3451 			if (joint.drive.driveSwing.flags.flags != DriveFlags::DefaultValue())
3452 			{
3453 				DriveFlags e(getPhysXExporter(), joint.drive.driveSwing.flags.flags);
3454 			}
3455 		}
3456 	};
3457 
3458 	class Twist : public Element
3459 	{
3460 	public:
Twist(PhysXExporter & exporter,const PhysXXML::PxD6Joint & joint)3461 		Twist(PhysXExporter & exporter, const PhysXXML::PxD6Joint & joint)
3462 			: Element(exporter, CSWC::CSW_ELEMENT_TWIST, withPrefix)
3463 		{
3464 			exportStiffness(joint);
3465 			exportDamping(joint);
3466 			exportForceLimit(joint);
3467 			exportDriveFlags(joint);
3468 		}
3469 
HasDefaultValues(const PhysXXML::PxD6Joint & joint)3470 		static bool HasDefaultValues(const PhysXXML::PxD6Joint & joint)
3471 		{
3472 			return joint.drive.driveTwist.stiffness.stiffness == Stiffness::DefaultValue() &&
3473 				joint.drive.driveTwist.damping.damping == Damping::DefaultValue() &&
3474 				joint.drive.driveTwist.forceLimit.forceLimit == ForceLimit::DefaultValue() &&
3475 				joint.drive.driveTwist.flags.flags == DriveFlags::DefaultValue();
3476 		}
3477 
3478 	private:
exportStiffness(const PhysXXML::PxD6Joint & joint)3479 		void exportStiffness(const PhysXXML::PxD6Joint & joint)
3480 		{
3481 			if (joint.drive.driveTwist.stiffness.stiffness != Stiffness::DefaultValue())
3482 			{
3483 				Stiffness e(getPhysXExporter(), joint.drive.driveTwist.stiffness.stiffness, withPrefix);
3484 			}
3485 		}
3486 
exportDamping(const PhysXXML::PxD6Joint & joint)3487 		void exportDamping(const PhysXXML::PxD6Joint & joint)
3488 		{
3489 			if (joint.drive.driveTwist.damping.damping != Damping::DefaultValue())
3490 			{
3491 				Damping e(getPhysXExporter(), joint.drive.driveTwist.damping.damping, withPrefix);
3492 			}
3493 		}
3494 
exportForceLimit(const PhysXXML::PxD6Joint & joint)3495 		void exportForceLimit(const PhysXXML::PxD6Joint & joint)
3496 		{
3497 			if (joint.drive.driveTwist.forceLimit.forceLimit != ForceLimit::DefaultValue())
3498 			{
3499 				ForceLimit e(getPhysXExporter(), joint.drive.driveTwist.forceLimit.forceLimit);
3500 			}
3501 		}
3502 
exportDriveFlags(const PhysXXML::PxD6Joint & joint)3503 		void exportDriveFlags(const PhysXXML::PxD6Joint & joint)
3504 		{
3505 			if (joint.drive.driveTwist.flags.flags != DriveFlags::DefaultValue())
3506 			{
3507 				DriveFlags e(getPhysXExporter(), joint.drive.driveTwist.flags.flags);
3508 			}
3509 		}
3510 	};
3511 
3512 	class Slerp : public Element
3513 	{
3514 	public:
Slerp(PhysXExporter & exporter,const PhysXXML::PxD6Joint & joint)3515 		Slerp(PhysXExporter & exporter, const PhysXXML::PxD6Joint & joint)
3516 			: Element(exporter, CSWC::CSW_ELEMENT_SLERP, withPrefix)
3517 		{
3518 			exportStiffness(joint);
3519 			exportDamping(joint);
3520 			exportForceLimit(joint);
3521 			exportDriveFlags(joint);
3522 		}
3523 
HasDefaultValues(const PhysXXML::PxD6Joint & joint)3524 		static bool HasDefaultValues(const PhysXXML::PxD6Joint & joint)
3525 		{
3526 			return joint.drive.driveSlerp.stiffness.stiffness == Stiffness::DefaultValue() &&
3527 				joint.drive.driveSlerp.damping.damping == Damping::DefaultValue() &&
3528 				joint.drive.driveSlerp.forceLimit.forceLimit == ForceLimit::DefaultValue();
3529 		}
3530 
3531 	private:
exportStiffness(const PhysXXML::PxD6Joint & joint)3532 		void exportStiffness(const PhysXXML::PxD6Joint & joint)
3533 		{
3534 			if (joint.drive.driveSlerp.stiffness.stiffness != Stiffness::DefaultValue())
3535 			{
3536 				Stiffness e(getPhysXExporter(), joint.drive.driveSlerp.stiffness.stiffness, withPrefix);
3537 			}
3538 		}
3539 
exportDamping(const PhysXXML::PxD6Joint & joint)3540 		void exportDamping(const PhysXXML::PxD6Joint & joint)
3541 		{
3542 			if (joint.drive.driveSlerp.damping.damping != Damping::DefaultValue())
3543 			{
3544 				Damping e(getPhysXExporter(), joint.drive.driveSlerp.damping.damping, withPrefix);
3545 			}
3546 		}
3547 
exportForceLimit(const PhysXXML::PxD6Joint & joint)3548 		void exportForceLimit(const PhysXXML::PxD6Joint & joint)
3549 		{
3550 			if (joint.drive.driveSlerp.forceLimit.forceLimit != ForceLimit::DefaultValue())
3551 			{
3552 				ForceLimit e(getPhysXExporter(), joint.drive.driveSlerp.forceLimit.forceLimit);
3553 			}
3554 		}
3555 
exportDriveFlags(const PhysXXML::PxD6Joint & joint)3556 		void exportDriveFlags(const PhysXXML::PxD6Joint & joint)
3557 		{
3558 			if (joint.drive.driveSlerp.flags.flags != DriveFlags::DefaultValue())
3559 			{
3560 				DriveFlags e(getPhysXExporter(), joint.drive.driveSlerp.flags.flags);
3561 			}
3562 		}
3563 	};
3564 
3565 	class LinearVelocity : public Element
3566 	{
3567 	public:
LinearVelocity(PhysXExporter & exporter,const MVector & linearVelocity)3568 		LinearVelocity(PhysXExporter & exporter, const MVector & linearVelocity)
3569 			: Element(exporter, CSWC::CSW_ELEMENT_LINEAR_VELOCITY, withPrefix)
3570 		{
3571 			getStreamWriter().appendValues(linearVelocity.x, linearVelocity.y, linearVelocity.z);
3572 		}
3573 
DefaultValue()3574 		static const MVector & DefaultValue()
3575 		{
3576 			return MVector::zero;
3577 		}
3578 	};
3579 
3580 	class AngularVelocity : public Element
3581 	{
3582 	public:
AngularVelocity(PhysXExporter & exporter,const MVector & velocity,bool elementForm)3583 		AngularVelocity(PhysXExporter & exporter, const MVector & velocity, bool elementForm)
3584 			: Element(exporter, CSWC::CSW_ELEMENT_ANGULAR_VELOCITY, elementForm)
3585 		{
3586 			getStreamWriter().appendValues(velocity.x, velocity.y, velocity.z);
3587 		}
3588 
DefaultValue()3589 		static const MVector & DefaultValue()
3590 		{
3591 			return MVector::zero;
3592 		}
3593 	};
3594 
3595 	class Drive : public Element
3596 	{
3597 	public:
Drive(PhysXExporter & exporter,const PhysXXML::PxD6Joint & joint)3598 		Drive(PhysXExporter & exporter, const PhysXXML::PxD6Joint & joint)
3599 			: Element(exporter, CSWC::CSW_ELEMENT_DRIVE, withPrefix)
3600 		{
3601 			exportLinearX(joint);
3602 			exportLinearY(joint);
3603 			exportLinearZ(joint);
3604 			exportSwing(joint);
3605 			exportTwist(joint);
3606 			exportSlerp(joint);
3607 			exportRotateTranslate(joint);
3608 			exportLinearVelocity(joint);
3609 			exportAngularVelocity(joint);
3610 		}
3611 
HasDefaultValues(const PhysXXML::PxD6Joint & joint)3612 		static bool HasDefaultValues(const PhysXXML::PxD6Joint & joint)
3613 		{
3614 			return LinearX::HasDefaultValues(joint) &&
3615 				LinearY::HasDefaultValues(joint) &&
3616 				LinearZ::HasDefaultValues(joint) &&
3617 				Swing::HasDefaultValues(joint) &&
3618 				Twist::HasDefaultValues(joint) &&
3619 				Slerp::HasDefaultValues(joint) &&
3620 				joint.drivePosition.translation == MVector::zero &&
3621 				joint.drivePosition.rotation == MQuaternion::identity &&
3622 				joint.driveVelocity.linear.linear == LinearVelocity::DefaultValue() &&
3623 				joint.driveVelocity.angular.angular == AngularVelocity::DefaultValue();
3624 		}
3625 
3626 	private:
exportLinearX(const PhysXXML::PxD6Joint & joint)3627 		void exportLinearX(const PhysXXML::PxD6Joint & joint)
3628 		{
3629 			if (!LinearX::HasDefaultValues(joint))
3630 			{
3631 				LinearX e(getPhysXExporter(), joint);
3632 			}
3633 		}
3634 
exportLinearY(const PhysXXML::PxD6Joint & joint)3635 		void exportLinearY(const PhysXXML::PxD6Joint & joint)
3636 		{
3637 			if (!LinearY::HasDefaultValues(joint))
3638 			{
3639 				LinearY e(getPhysXExporter(), joint);
3640 			}
3641 		}
3642 
exportLinearZ(const PhysXXML::PxD6Joint & joint)3643 		void exportLinearZ(const PhysXXML::PxD6Joint & joint)
3644 		{
3645 			if (!LinearZ::HasDefaultValues(joint))
3646 			{
3647 				LinearZ e(getPhysXExporter(), joint);
3648 			}
3649 		}
3650 
exportSwing(const PhysXXML::PxD6Joint & joint)3651 		void exportSwing(const PhysXXML::PxD6Joint & joint)
3652 		{
3653 			if (!Swing::HasDefaultValues(joint))
3654 			{
3655 				Swing e(getPhysXExporter(), joint);
3656 			}
3657 		}
3658 
exportTwist(const PhysXXML::PxD6Joint & joint)3659 		void exportTwist(const PhysXXML::PxD6Joint & joint)
3660 		{
3661 			if (!Twist::HasDefaultValues(joint))
3662 			{
3663 				Twist e(getPhysXExporter(), joint);
3664 			}
3665 		}
3666 
exportSlerp(const PhysXXML::PxD6Joint & joint)3667 		void exportSlerp(const PhysXXML::PxD6Joint & joint)
3668 		{
3669 			if (!Slerp::HasDefaultValues(joint))
3670 			{
3671 				Slerp e(getPhysXExporter(), joint);
3672 			}
3673 		}
3674 
exportRotateTranslate(const PhysXXML::PxD6Joint & joint)3675 		void exportRotateTranslate(const PhysXXML::PxD6Joint & joint)
3676 		{
3677 			MVector translation = joint.drivePosition.translation;
3678 			MEulerRotation rotation = joint.drivePosition.rotation.asEulerRotation();
3679 
3680 			getPhysXExporter().exportTranslationWithoutConversion(translation, ATTR_TRANSLATE);
3681 			getPhysXExporter().exportRotation(rotation, ATTR_ROTATE);
3682 		}
3683 
exportLinearVelocity(const PhysXXML::PxD6Joint & joint)3684 		void exportLinearVelocity(const PhysXXML::PxD6Joint & joint)
3685 		{
3686 			if (joint.driveVelocity.linear.linear != LinearVelocity::DefaultValue())
3687 			{
3688 				LinearVelocity e(getPhysXExporter(), joint.driveVelocity.linear.linear);
3689 			}
3690 		}
3691 
exportAngularVelocity(const PhysXXML::PxD6Joint & joint)3692 		void exportAngularVelocity(const PhysXXML::PxD6Joint & joint)
3693 		{
3694 			if (joint.driveVelocity.angular.angular != AngularVelocity::DefaultValue())
3695 			{
3696 				AngularVelocity e(getPhysXExporter(), joint.driveVelocity.angular.angular, withPrefix);
3697 			}
3698 		}
3699 	};
3700 
3701 	class LocalPose0 : public Element
3702 	{
3703 	public:
LocalPose0(PhysXExporter & exporter,const MQuaternion & rotation,const MVector & translation)3704 		LocalPose0(PhysXExporter& exporter, const MQuaternion& rotation, const MVector& translation)
3705 			: Element(exporter, CSWC::CSW_ELEMENT_LOCAL_POSE_0, withPrefix)
3706 		{
3707 			double localPose[] = { rotation.x, rotation.y, rotation.z, rotation.w, translation.x, translation.y, translation.z };
3708 			getStreamWriter().appendValues(localPose, sizeof(localPose) / sizeof(localPose[0]));
3709 		}
3710 	};
3711 
3712 	class LocalPose1 : public Element
3713 	{
3714 	public:
LocalPose1(PhysXExporter & exporter,const MQuaternion & rotation,const MVector & translation)3715 		LocalPose1(PhysXExporter& exporter, const MQuaternion& rotation, const MVector& translation)
3716 			: Element(exporter, CSWC::CSW_ELEMENT_LOCAL_POSE_1, withPrefix)
3717 		{
3718 			double localPose[] = { rotation.x, rotation.y, rotation.z, rotation.w, translation.x, translation.y, translation.z };
3719 			getStreamWriter().appendValues(localPose, sizeof(localPose) / sizeof(localPose[0]));
3720 		}
3721 	};
3722 
3723 	class PxD6Joint : public Element
3724 	{
3725 	public:
PxD6Joint(PhysXExporter & exporter,const PhysXXML::PxD6Joint & joint)3726 		PxD6Joint(PhysXExporter& exporter, const PhysXXML::PxD6Joint & joint)
3727 			: Element(exporter, CSWC::CSW_ELEMENT_PX_D6JOINT, withPrefix)
3728 		{
3729 			exportLocalPose0(joint);
3730 			exportLocalPose1(joint);
3731 			exportBreakForce(joint);
3732 			exportBreakTorque(joint);
3733 			exportConstraintFlags(joint);
3734 			exportInvMassScale0(joint);
3735 			exportInvInertiaScale0(joint);
3736 			exportInvMassScale1(joint);
3737 			exportInvInertiaScale1(joint);
3738 			exportProjectionLinearTolerance(joint);
3739 			exportProjectionAngularTolerance(joint);
3740 			exportLimitsExtra(joint);
3741 			exportSpringExtra(joint);
3742 			exportDrive(joint);
3743 		}
3744 
HasDefaultValues(const PhysXXML::PxD6Joint & joint)3745 		static bool HasDefaultValues(const PhysXXML::PxD6Joint & joint)
3746 		{
3747 			// Always export local pose 0 and 1
3748 			return false;
3749 		}
3750 
3751 	private:
exportLocalPose0(const PhysXXML::PxD6Joint & joint)3752 		void exportLocalPose0(const PhysXXML::PxD6Joint & joint)
3753 		{
3754 			LocalPose0 e(getPhysXExporter(), joint.localPose.eActor0.rotation, joint.localPose.eActor0.translation);
3755 		}
3756 
exportLocalPose1(const PhysXXML::PxD6Joint & joint)3757 		void exportLocalPose1(const PhysXXML::PxD6Joint & joint)
3758 		{
3759 			LocalPose1 e(getPhysXExporter(), joint.localPose.eActor1.rotation, joint.localPose.eActor1.translation);
3760 		}
3761 
exportBreakForce(const PhysXXML::PxD6Joint & joint)3762 		void exportBreakForce(const PhysXXML::PxD6Joint & joint)
3763 		{
3764 			if (joint.breakForce.force.force != BreakForce::DefaultValue())
3765 			{
3766 				BreakForce e(getPhysXExporter(), joint.breakForce.force.force);
3767 			}
3768 		}
3769 
exportBreakTorque(const PhysXXML::PxD6Joint & joint)3770 		void exportBreakTorque(const PhysXXML::PxD6Joint & joint)
3771 		{
3772 			if (joint.breakForce.torque.torque != BreakTorque::DefaultValue())
3773 			{
3774 				BreakTorque e(getPhysXExporter(), joint.breakForce.torque.torque);
3775 			}
3776 		}
3777 
exportConstraintFlags(const PhysXXML::PxD6Joint & joint)3778 		void exportConstraintFlags(const PhysXXML::PxD6Joint & joint)
3779 		{
3780 			if (joint.constraintFlags.flags != ConstraintFlags::DefaultValue())
3781 			{
3782 				ConstraintFlags e(getPhysXExporter(), joint.constraintFlags.flags);
3783 			}
3784 		}
3785 
exportInvMassScale0(const PhysXXML::PxD6Joint & joint)3786 		void exportInvMassScale0(const PhysXXML::PxD6Joint & joint)
3787 		{
3788 			if (joint.invMassScale0.invMassScale0 != InvMassScale0::DefaultValue())
3789 			{
3790 				InvMassScale0 e(getPhysXExporter(), joint.invMassScale0.invMassScale0);
3791 			}
3792 		}
3793 
exportInvInertiaScale0(const PhysXXML::PxD6Joint & joint)3794 		void exportInvInertiaScale0(const PhysXXML::PxD6Joint & joint)
3795 		{
3796 			if (joint.invInertiaScale0.invInertiaScale0 != InvInertiaScale0::DefaultValue())
3797 			{
3798 				InvInertiaScale0 e(getPhysXExporter(), joint.invInertiaScale0.invInertiaScale0);
3799 			}
3800 		}
3801 
exportInvMassScale1(const PhysXXML::PxD6Joint & joint)3802 		void exportInvMassScale1(const PhysXXML::PxD6Joint & joint)
3803 		{
3804 			if (joint.invMassScale1.invMassScale1 != InvMassScale1::DefaultValue())
3805 			{
3806 				InvMassScale1 e(getPhysXExporter(), joint.invMassScale1.invMassScale1);
3807 			}
3808 		}
3809 
exportInvInertiaScale1(const PhysXXML::PxD6Joint & joint)3810 		void exportInvInertiaScale1(const PhysXXML::PxD6Joint & joint)
3811 		{
3812 			if (joint.invInertiaScale1.invInertiaScale1 != InvInertiaScale1::DefaultValue())
3813 			{
3814 				InvInertiaScale1 e(getPhysXExporter(), joint.invInertiaScale1.invInertiaScale1);
3815 			}
3816 		}
3817 
exportProjectionLinearTolerance(const PhysXXML::PxD6Joint & joint)3818 		void exportProjectionLinearTolerance(const PhysXXML::PxD6Joint & joint)
3819 		{
3820 			if (joint.projectionLinearTolerance.projectionLinearTolerance != ProjectionLinearTolerance::DefaultValue())
3821 			{
3822 				ProjectionLinearTolerance e(getPhysXExporter(), joint.projectionLinearTolerance.projectionLinearTolerance);
3823 			}
3824 		}
3825 
exportProjectionAngularTolerance(const PhysXXML::PxD6Joint & joint)3826 		void exportProjectionAngularTolerance(const PhysXXML::PxD6Joint & joint)
3827 		{
3828 			if (joint.projectionAngularTolerance.projectionAngularTolerance != ProjectionAngularTolerance::DefaultValue())
3829 			{
3830 				ProjectionAngularTolerance e(getPhysXExporter(), joint.projectionAngularTolerance.projectionAngularTolerance);
3831 			}
3832 		}
3833 
exportLimitsExtra(const PhysXXML::PxD6Joint & joint)3834 		void exportLimitsExtra(const PhysXXML::PxD6Joint & joint)
3835 		{
3836 			if (!LimitsExtra::HasDefaultValues(joint))
3837 			{
3838 				LimitsExtra e(getPhysXExporter(), joint);
3839 			}
3840 		}
3841 
exportSpringExtra(const PhysXXML::PxD6Joint & joint)3842 		void exportSpringExtra(const PhysXXML::PxD6Joint & joint)
3843 		{
3844 			if (!SpringExtra::HasDefaultValues(joint))
3845 			{
3846 				SpringExtra e(getPhysXExporter(), joint);
3847 			}
3848 		}
3849 
exportDrive(const PhysXXML::PxD6Joint & joint)3850 		void exportDrive(const PhysXXML::PxD6Joint & joint)
3851 		{
3852 			if (!Drive::HasDefaultValues(joint))
3853 			{
3854 				Drive e(getPhysXExporter(), joint);
3855 			}
3856 		}
3857 	};
3858 
3859     class RigidConstraintTechnique : public Element
3860     {
3861     public:
RigidConstraintTechnique(PhysXExporter & exporter,const MObject & rigidConstraint,const PhysXXML::PxD6Joint & joint,const String & profile)3862 		RigidConstraintTechnique(PhysXExporter& exporter, const MObject & rigidConstraint, const PhysXXML::PxD6Joint & joint, const String & profile)
3863             : Element(exporter, CSWC::CSW_ELEMENT_TECHNIQUE)
3864         {
3865             getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_PROFILE, profile);
3866 			getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_XMLNS + ":" + CSWC::CSW_PREFIX_PX, PhysXExporter::GetXMLNS());
3867 			getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_XSI_SCHEMALOCATION, PhysXExporter::GetXSISchemaLocation());
3868 			if (profile == PROFILE_MAYA) {
3869 				exporter.exportExtraAttributes(rigidConstraint);
3870 			}
3871 			else if (profile == PhysXExporter::GetPhysXProfile()) {
3872 				exportPxD6Joint(joint);
3873 			}
3874         }
3875 
HasDefaultValues(const MObject & constraint,const PhysXXML::PxD6Joint & joint,const String & profile)3876 		static bool HasDefaultValues(const MObject & constraint, const PhysXXML::PxD6Joint & joint, const String & profile)
3877 		{
3878 			if (profile == PhysXExporter::GetPhysXProfile())
3879 			{
3880 				return PxD6Joint::HasDefaultValues(joint);
3881 			}
3882 			else if (profile == PROFILE_MAYA)
3883 			{
3884 				return !PhysXExporter::HasExtraAttributes(constraint);
3885 			}
3886 			return true;
3887 		}
3888 
3889     private:
exportPxD6Joint(const PhysXXML::PxD6Joint & joint)3890 		void exportPxD6Joint(const PhysXXML::PxD6Joint & joint)
3891 		{
3892 			if (!PxD6Joint::HasDefaultValues(joint))
3893 			{
3894 				PxD6Joint e(getPhysXExporter(), joint);
3895 			}
3896 		}
3897 
3898     private:
3899         static std::set<MString, MStringComp> mAttributes;
3900     };
3901     std::set<MString, MStringComp> RigidConstraintTechnique::mAttributes;
3902 
3903     class RigidConstraintExtra : public Element
3904     {
3905     public:
RigidConstraintExtra(PhysXExporter & exporter,const MObject & rigidConstraint,const PhysXXML::PxD6Joint & joint)3906 		RigidConstraintExtra(PhysXExporter& exporter, const MObject & rigidConstraint, const PhysXXML::PxD6Joint & joint)
3907             : Element(exporter, CSWC::CSW_ELEMENT_EXTRA)
3908         {
3909 			if (PhysXExporter::HasExtraAttributes(rigidConstraint)) {
3910 				exportTechnique(rigidConstraint, joint, PROFILE_MAYA);
3911 			}
3912 			exportTechnique(rigidConstraint, joint, PhysXExporter::GetPhysXProfile());
3913         }
3914 
HasDefaultValues(const MObject & constraint,const PhysXXML::PxD6Joint & joint)3915 		static bool HasDefaultValues(const MObject & constraint, const PhysXXML::PxD6Joint & joint)
3916 		{
3917 			return
3918 				RigidConstraintTechnique::HasDefaultValues(constraint, joint, PROFILE_MAYA) &&
3919 				RigidConstraintTechnique::HasDefaultValues(constraint, joint, PhysXExporter::GetPhysXProfile());
3920 		}
3921 
3922     private:
exportTechnique(const MObject & rigidConstraint,const PhysXXML::PxD6Joint & joint,const String & profile)3923 		void exportTechnique(const MObject& rigidConstraint, const PhysXXML::PxD6Joint & joint, const String& profile)
3924         {
3925 			if (!RigidConstraintTechnique::HasDefaultValues(rigidConstraint, joint, profile))
3926 			{
3927 				RigidConstraintTechnique e(getPhysXExporter(), rigidConstraint, joint, profile);
3928 			}
3929         }
3930     };
3931 
3932     class RigidConstraint : public Element
3933     {
3934     public:
RigidConstraint(PhysXExporter & exporter,const MObject & rigidConstraint,const String & sid,const String & name="")3935         RigidConstraint(PhysXExporter& exporter, const MObject & rigidConstraint, const String & sid, const String & name = "")
3936             : Element(exporter, CSWC::CSW_ELEMENT_RIGID_CONSTRAINT)
3937         {
3938             getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_SID, sid);
3939             if (name.length() > 0) {
3940                 getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_NAME, name);
3941             }
3942 
3943 			const PhysXXML::PxD6Joint* joint = exporter.findPxD6Joint(rigidConstraint);
3944 			if (joint)
3945 			{
3946 				exportRefAttachment(*joint);
3947 				exportAttachment(*joint);
3948 				exportTechniqueCommon(rigidConstraint, *joint);
3949 				exportExtra(rigidConstraint, *joint);
3950 			}
3951         }
3952 
3953     private:
exportRefAttachment(const PhysXXML::PxD6Joint & joint)3954 		void exportRefAttachment(const PhysXXML::PxD6Joint & joint)
3955         {
3956 			MObject rigidBody;
3957 			if (const PhysXXML::PxRigidBody* pxRigidBody = getPhysXExporter().findPxRigidBody(joint.actors.actor0.actor0))
3958 			{
3959 				MObject target = DagHelper::getNode(pxRigidBody->name.name.c_str());
3960 				rigidBody = getPhysXExporter().getNodeRigidBody(target);
3961 			}
3962 
3963             URI rigidBodyURI;
3964             if (rigidBody.isNull())
3965             {
3966                 rigidBodyURI.set("");
3967             }
3968             else
3969             {
3970                 MDagPath rigidBodyDagPath;
3971                 MDagPath::getAPathTo(rigidBody, rigidBodyDagPath);
3972 
3973                 String rigidBodySid = getPhysXExporter().generateColladaId(rigidBodyDagPath);
3974 				String rigidBodyId = getPhysXExporter().GetDefaultPhysicsModelId() + '/' + rigidBodySid;
3975                 URI rigidBodyURI = getPhysXExporter().getDocumentExporter().getVisualSceneExporter()->getSceneElementURI(rigidBodyDagPath, rigidBodyId);
3976             }
3977 
3978             RefAttachment e(getPhysXExporter(), joint, rigidBodyURI);
3979         }
3980 
exportAttachment(const PhysXXML::PxD6Joint & joint)3981 		void exportAttachment(const PhysXXML::PxD6Joint & joint)
3982         {
3983 			const PhysXXML::PxRigidBody* pxRigidBody = getPhysXExporter().findPxRigidBody(joint.actors.actor1.actor1);
3984 			if (!pxRigidBody)
3985 				return;
3986 
3987 			MObject target = DagHelper::getNode(pxRigidBody->name.name.c_str());
3988 			MObject rigidBody = getPhysXExporter().getNodeRigidBody(target);
3989 
3990             MDagPath rigidBodyDagPath;
3991             MDagPath::getAPathTo(rigidBody, rigidBodyDagPath);
3992 
3993 			String rigidBodySid = getPhysXExporter().generateColladaId(rigidBodyDagPath);
3994 			String rigidBodyId = getPhysXExporter().GetDefaultPhysicsModelId() + '/' + rigidBodySid;
3995 			URI rigidBodyURI = getPhysXExporter().getDocumentExporter().getVisualSceneExporter()->getSceneElementURI(rigidBodyDagPath, rigidBodyId);
3996 
3997             Attachment e(getPhysXExporter(), joint, rigidBodyURI);
3998         }
3999 
exportTechniqueCommon(const MObject & rigidConstraint,const PhysXXML::PxD6Joint & joint)4000 		void exportTechniqueCommon(const MObject & rigidConstraint, const PhysXXML::PxD6Joint & joint)
4001         {
4002             RigidConstraintTechniqueCommon e(getPhysXExporter(), rigidConstraint, joint);
4003         }
4004 
exportExtra(const MObject & rigidConstraint,const PhysXXML::PxD6Joint & joint)4005 		void exportExtra(const MObject & rigidConstraint, const PhysXXML::PxD6Joint & joint)
4006         {
4007 			if (!RigidConstraintExtra::HasDefaultValues(rigidConstraint, joint))
4008 			{
4009 				RigidConstraintExtra e(getPhysXExporter(), rigidConstraint, joint);
4010 			}
4011         }
4012     };
4013 
4014     class Velocity : public Element
4015     {
4016     public:
Velocity(PhysXExporter & exporter,const MVector & velocity)4017         Velocity(PhysXExporter & exporter, const MVector & velocity)
4018             : Element(exporter, CSWC::CSW_ELEMENT_VELOCITY)
4019         {
4020             getStreamWriter().appendValues(velocity.x, velocity.y, velocity.z);
4021         }
4022 
DefaultValue()4023 		static const MVector & DefaultValue()
4024 		{
4025 			return MVector::zero;
4026 		}
4027     };
4028 
4029     class InstanceRigidBodyTechniqueCommon : public Element
4030     {
4031     public:
InstanceRigidBodyTechniqueCommon(PhysXExporter & exporter,const MVector & angularVelocity,const MVector & velocity)4032         InstanceRigidBodyTechniqueCommon(PhysXExporter& exporter, const MVector & angularVelocity, const MVector& velocity)
4033             : Element(exporter, CSWC::CSW_ELEMENT_TECHNIQUE_COMMON)
4034         {
4035             exportAngularVelocity(angularVelocity);
4036             exportVelocity(velocity);
4037         }
4038 
AreDefaultValues(const MVector & angularVelocity,const MVector & velocity)4039 		static bool AreDefaultValues(const MVector & angularVelocity, const MVector & velocity)
4040 		{
4041 			return
4042 				angularVelocity == AngularVelocity::DefaultValue() &&
4043 				velocity == Velocity::DefaultValue();
4044 		}
4045 
4046     private:
exportAngularVelocity(const MVector & angularVelocity)4047         void exportAngularVelocity(const MVector& angularVelocity)
4048         {
4049             if (angularVelocity != AngularVelocity::DefaultValue())
4050             {
4051                 AngularVelocity e(getPhysXExporter(), angularVelocity, withoutPrefix);
4052             }
4053         }
4054 
exportVelocity(const MVector & velocity)4055         void exportVelocity(const MVector& velocity)
4056         {
4057             if (velocity != Velocity::DefaultValue())
4058             {
4059                 Velocity e(getPhysXExporter(), velocity);
4060             }
4061         }
4062     };
4063 
4064     class InstanceRigidBody : public Element
4065     {
4066     public:
InstanceRigidBody(PhysXExporter & exporter,const MObject & rigidBody,const String & instanceRigidBodySID,const String & rigidBodySID,const URI & targetURI)4067         InstanceRigidBody(PhysXExporter& exporter, const MObject & rigidBody, const String& instanceRigidBodySID, const String & rigidBodySID, const URI & targetURI)
4068             : Element(exporter, CSWC::CSW_ELEMENT_INSTANCE_RIGID_BODY)
4069         {
4070             getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_SID, instanceRigidBodySID);
4071             getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_BODY, rigidBodySID);
4072             getStreamWriter().appendURIAttribute(CSWC::CSW_ATTRIBUTE_TARGET, targetURI);
4073 
4074 			MVector initialSpin = MVector::zero;
4075 			MVector initialVelocity = MVector::zero;
4076 			if (!rigidBody.isNull())
4077 			{
4078 				DagHelper::getPlugValue(rigidBody, ATTR_INITIAL_SPIN, initialSpin);
4079 				initialSpin.x = COLLADABU::Math::Utils::radToDeg(initialSpin.x);
4080 				initialSpin.y = COLLADABU::Math::Utils::radToDeg(initialSpin.y);
4081 				initialSpin.z = COLLADABU::Math::Utils::radToDeg(initialSpin.z);
4082 
4083 				DagHelper::getPlugValue(rigidBody, ATTR_INITIAL_VELOCITY, initialVelocity);
4084 				initialVelocity.x = MDistance::internalToUI(initialVelocity.x);
4085 				initialVelocity.y = MDistance::internalToUI(initialVelocity.y);
4086 				initialVelocity.z = MDistance::internalToUI(initialVelocity.z);
4087 			}
4088 			exportTechniqueCommon(initialSpin, initialVelocity);
4089         }
4090 
4091     private:
exportTechniqueCommon(const MVector & angularVelocity,const MVector & velocity)4092         void exportTechniqueCommon(const MVector& angularVelocity, const MVector& velocity)
4093         {
4094             InstanceRigidBodyTechniqueCommon e(getPhysXExporter(), angularVelocity, velocity);
4095         }
4096     };
4097 
4098     class InstanceRigidConstraint : public Element
4099     {
4100     public:
InstanceRigidConstraint(PhysXExporter & exporter,const String & instanceConstraintSid,const String & constraintSid)4101         InstanceRigidConstraint(PhysXExporter & exporter, const String& instanceConstraintSid, const String & constraintSid)
4102             : Element(exporter, CSWC::CSW_ELEMENT_INSTANCE_RIGID_CONSTRAINT)
4103         {
4104             getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_SID, instanceConstraintSid);
4105             getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_CONSTRAINT, constraintSid);
4106         }
4107     };
4108 
4109     class InstancePhysicsModel : public Element
4110     {
4111     public:
InstancePhysicsModel(PhysXExporter & exporter,const String & sid,const URI & uri)4112         InstancePhysicsModel(PhysXExporter& exporter, const String& sid, const URI& uri)
4113             : Element(exporter, CSWC::CSW_ELEMENT_INSTANCE_PHYSICS_MODEL)
4114         {
4115             if (!sid.empty()) {
4116                 getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_SID, sid);
4117             }
4118             getStreamWriter().appendURIAttribute(CSWC::CSW_ATTRIBUTE_URL, uri);
4119 
4120             exportInstanceRigidBodies();
4121             exportInstanceRigidConstraints();
4122         }
4123 
4124     private:
4125         class RigidBodyParser
4126         {
4127         public:
RigidBodyParser(PhysXExporter & exporter)4128             RigidBodyParser(PhysXExporter & exporter)
4129             : mPhysXExporter(exporter)
4130             , mInstanceRigidBodyIndex(0)
4131             {}
4132 
operator ()(SceneElement & element)4133             bool operator()(SceneElement & element)
4134             {
4135                 if (element.getType() == SceneElement::PHYSX_RIGID_BODY &&
4136                     element.getIsLocal())
4137                 {
4138                     const MObject & rigidBody = element.getNode();
4139 
4140                     MObject target = PhysXExporter::GetRigidBodyTarget(rigidBody);
4141                     MDagPath targetDagPath;
4142                     MDagPath::getAPathTo(target, targetDagPath);
4143                     SceneElement* targetElement = mPhysXExporter.getDocumentExporter().getSceneGraph()->findElement(targetDagPath);
4144                     if (targetElement)
4145                     {
4146                         String rigidBodySid = mPhysXExporter.generateColladaId(element.getPath());
4147                         std::stringstream s;
4148                         s << "_" << mInstanceRigidBodyIndex++;
4149                         String instanceRigidBodySid = rigidBodySid + s.str();
4150                         URI targetURI = mPhysXExporter.getDocumentExporter().getVisualSceneExporter()->getSceneElementURI(targetElement);
4151                         InstanceRigidBody e(mPhysXExporter, rigidBody, instanceRigidBodySid, rigidBodySid, targetURI);
4152                     }
4153                 }
4154                 return true;
4155             }
4156 
4157         private:
4158             PhysXExporter & mPhysXExporter;
4159             int mInstanceRigidBodyIndex;
4160         };
4161 
exportInstanceRigidBodies()4162         void exportInstanceRigidBodies()
4163         {
4164             PhysXExporter& exporter = getPhysXExporter();
4165 
4166             // Export ground plane if enabled
4167             MObject rigidSolver = exporter.getRigidSolver();
4168             if (!rigidSolver.isNull())
4169             {
4170                 String name = GROUND_PLANE_NAME;
4171                 String sid = name;
4172 
4173                 bool useGroundPlane = false;
4174                 DagHelper::getPlugValue(rigidSolver, ATTR_USE_GROUND_PLANE, useGroundPlane);
4175 				const PhysXXML::PxRigidBody* groundPlane = exporter.findPxRigidBody(name);
4176                 if (useGroundPlane && groundPlane)
4177                 {
4178 					InstanceRigidBody e(exporter, MObject::kNullObj, name, name, "");
4179                 }
4180             }
4181 
4182             RigidBodyParser rigidBodyParser(exporter);
4183             exporter.parseSceneElements(rigidBodyParser);
4184         }
4185 
4186         class RigidConstraintParser
4187         {
4188         public:
RigidConstraintParser(PhysXExporter & exporter)4189             RigidConstraintParser(PhysXExporter & exporter)
4190             : mPhysXExporter(exporter)
4191             , mInstanceRigidConstraintIndex(0)
4192             {}
4193 
operator ()(SceneElement & element)4194             bool operator()(SceneElement & element)
4195             {
4196                 if (element.getType() == SceneElement::PHYSX_RIGID_CONSTRAINT &&
4197                     element.getIsLocal())
4198                 {
4199                     const MObject & rigidConstraint = element.getNode();
4200 
4201                     String rigidConstraintSid = mPhysXExporter.generateColladaId(element.getPath());
4202                     std::stringstream s;
4203                     s << "_" << mInstanceRigidConstraintIndex++;
4204                     String instanceRigidConstraintSid = rigidConstraintSid + s.str();
4205                     InstanceRigidConstraint e(mPhysXExporter, instanceRigidConstraintSid, rigidConstraintSid);
4206                 }
4207                 return true;
4208             }
4209 
4210         private:
4211             PhysXExporter & mPhysXExporter;
4212             int mInstanceRigidConstraintIndex;
4213         };
4214 
exportInstanceRigidConstraints()4215         void exportInstanceRigidConstraints()
4216         {
4217             RigidConstraintParser rigidConstraintParser(getPhysXExporter());
4218             getPhysXExporter().parseSceneElements(rigidConstraintParser);
4219         }
4220     };
4221 
4222     class PhysicsModel : public Element
4223     {
4224     public:
PhysicsModel(PhysXExporter & exporter,const String & id)4225         PhysicsModel(PhysXExporter& exporter, const String & id)
4226             : Element(exporter, CSWC::CSW_ELEMENT_PHYSICS_MODEL)
4227         {
4228             if (!id.empty()) {
4229                 getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_ID, id);
4230             }
4231             exportRigidBodies();
4232             exportRigidConstraints();
4233             //exportInstancePhysicsModels();
4234         }
4235 
4236     private:
4237         class RigidBodyParser
4238         {
4239         public:
RigidBodyParser(PhysXExporter & exporter)4240             RigidBodyParser(PhysXExporter & exporter)
4241             : mPhysXExporter(exporter)
4242             {}
4243 
operator ()(SceneElement & element)4244             bool operator()(SceneElement & element)
4245             {
4246                 if (element.getType() == SceneElement::PHYSX_RIGID_BODY &&
4247                     element.getIsLocal())
4248                 {
4249                     String rigidBodySid = mPhysXExporter.generateColladaId(element.getPath());
4250                     String rigidBodyName = mPhysXExporter.generateColladaName(element.getPath());
4251 
4252                     const MObject & rigidBody = element.getNode();
4253 
4254                     RigidBody e(mPhysXExporter, rigidBody, rigidBodySid, rigidBodyName);
4255                 }
4256                 return true;
4257             }
4258 
4259         private:
4260             PhysXExporter & mPhysXExporter;
4261         };
4262 
exportRigidBodies()4263         void exportRigidBodies()
4264         {
4265             PhysXExporter& exporter = getPhysXExporter();
4266 
4267             // Export ground plane if enabled
4268 			MObject rigidSolver = exporter.getRigidSolver();
4269             if (!rigidSolver.isNull())
4270             {
4271                 String name = GROUND_PLANE_NAME;
4272                 String sid = name;
4273 
4274                 bool useGroundPlane = false;
4275                 DagHelper::getPlugValue(rigidSolver, ATTR_USE_GROUND_PLANE, useGroundPlane);
4276 				const PhysXXML::PxRigidBody* groundPlane = exporter.findPxRigidBody(name);
4277                 if (useGroundPlane && groundPlane)
4278                 {
4279 					RigidBody e(exporter, *groundPlane, sid, name);
4280                 }
4281             }
4282 
4283             // Export the other rigid bodies
4284             RigidBodyParser rigidBodyParser(exporter);
4285             exporter.parseSceneElements(rigidBodyParser);
4286         }
4287 
4288         class RigidConstraintParser
4289         {
4290         public:
RigidConstraintParser(PhysXExporter & exporter)4291             RigidConstraintParser(PhysXExporter & exporter)
4292             : mPhysXExporter(exporter)
4293             {}
4294 
operator ()(SceneElement & element)4295             bool operator()(SceneElement & element)
4296             {
4297                 if (element.getType() == SceneElement::PHYSX_RIGID_CONSTRAINT &&
4298                     element.getIsLocal())
4299                 {
4300                     String rigidConstraintSid = mPhysXExporter.generateColladaId(element.getPath());
4301                     String rigidConstraintName = mPhysXExporter.generateColladaName(element.getPath());
4302 
4303                     const MObject & rigidConstraint = element.getNode();
4304 
4305                     RigidConstraint e(mPhysXExporter, rigidConstraint, rigidConstraintSid, rigidConstraintName);
4306                 }
4307                 return true;
4308             }
4309 
4310         private:
4311             PhysXExporter & mPhysXExporter;
4312         };
4313 
exportRigidConstraints()4314         void exportRigidConstraints()
4315         {
4316             RigidConstraintParser rigidConstraintParser(getPhysXExporter());
4317             getPhysXExporter().parseSceneElements(rigidConstraintParser);
4318         }
4319     };
4320 
4321     class LibraryPhysicsModels : public Element
4322     {
4323     public:
LibraryPhysicsModels(PhysXExporter & exporter)4324         LibraryPhysicsModels(PhysXExporter& exporter)
4325             : Element(exporter, CSWC::CSW_ELEMENT_LIBRARY_PHYSICS_MODELS)
4326         {
4327             PhysicsModel e(exporter, PhysXExporter::GetDefaultPhysicsModelId());
4328         }
4329     };
4330 
4331     class Gravity : public Element
4332     {
4333     public:
Gravity(PhysXExporter & exporter,const MVector & gravity)4334         Gravity(PhysXExporter & exporter, const MVector & gravity)
4335             : Element(exporter, CSWC::CSW_ELEMENT_GRAVITY)
4336         {
4337             getStreamWriter().appendValues(gravity.x, gravity.y, gravity.z);
4338         }
4339     };
4340 
4341     class PhysicsSceneTechniqueCommon : public Element
4342     {
4343     public:
PhysicsSceneTechniqueCommon(PhysXExporter & exporter)4344         PhysicsSceneTechniqueCommon(PhysXExporter & exporter)
4345             : Element(exporter, CSWC::CSW_ELEMENT_TECHNIQUE_COMMON)
4346         {
4347 			MObject rigidSolver = exporter.getRigidSolver();
4348             if (!rigidSolver.isNull())
4349             {
4350                 exportGravity(rigidSolver);
4351                 exportTimeStep(rigidSolver);
4352             }
4353         }
4354 
4355     private:
exportGravity(const MObject & rigidSolver)4356         void exportGravity(const MObject & rigidSolver)
4357         {
4358             bool gravityEnabled = false;
4359             DagHelper::getPlugValue(rigidSolver, ATTR_GRAVITY, gravityEnabled);
4360             if (gravityEnabled)
4361             {
4362                 double gravityMagnitude = 9.18;
4363                 DagHelper::getPlugValue(rigidSolver, ATTR_GRAVITY_MAGNITUDE, gravityMagnitude);
4364 
4365                 MVector gravityDirection(0.0, -1.0, 0.0);
4366                 DagHelper::getPlugValue(rigidSolver, ATTR_GRAVITY_DIRECTION, gravityDirection);
4367 
4368                 gravityDirection.x = MDistance::internalToUI(gravityDirection.x);
4369                 gravityDirection.y = MDistance::internalToUI(gravityDirection.y);
4370                 gravityDirection.z = MDistance::internalToUI(gravityDirection.z);
4371 
4372                 Gravity e(getPhysXExporter(), gravityDirection * gravityMagnitude);
4373             }
4374         }
4375 
exportTimeStep(const MObject & rigidSolver)4376         void exportTimeStep(const MObject & rigidSolver)
4377         {
4378 
4379         }
4380     };
4381 
4382     class PhysicsScene : public Element
4383     {
4384     public:
PhysicsScene(PhysXExporter & exporter,const String & id)4385         PhysicsScene(PhysXExporter& exporter, const String & id)
4386             : Element(exporter, CSWC::CSW_ELEMENT_PHYSICS_SCENE)
4387         {
4388             if (!id.empty()) {
4389                 getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_ID, id);
4390             }
4391             exportInstancePhysicsModels();
4392             exportTechniqueCommon();
4393         }
4394 
4395     private:
exportInstancePhysicsModels()4396         void exportInstancePhysicsModels()
4397         {
4398             // Local physics model
4399             if (getPhysXExporter().sceneHas(SceneElement::PHYSX_RIGID_BODY, PhysXExporter::Local) ||
4400                 getPhysXExporter().sceneHas(SceneElement::PHYSX_RIGID_CONSTRAINT, PhysXExporter::Local))
4401             {
4402                 String physicsModelId = PhysXExporter::GetDefaultPhysicsModelId();
4403 
4404                 URI uri;
4405                 uri.set("");
4406                 uri.setFragment(physicsModelId);
4407 
4408                 InstancePhysicsModel e(getPhysXExporter(), PhysXExporter::GetDefaultInstancePhysicsModelSid(), uri);
4409             }
4410         }
4411 
exportTechniqueCommon()4412         void exportTechniqueCommon()
4413         {
4414             PhysicsSceneTechniqueCommon e(getPhysXExporter());
4415         }
4416     };
4417 
4418     class LibraryPhysicsScenes : public Element
4419     {
4420     public:
LibraryPhysicsScenes(PhysXExporter & exporter)4421         LibraryPhysicsScenes(PhysXExporter& exporter)
4422             : Element(exporter, CSWC::CSW_ELEMENT_LIBRARY_PHYSICS_SCENES)
4423         {
4424             PhysicsScene e(exporter, PhysXExporter::GetDefaultPhysicsSceneId());
4425         }
4426     };
4427 
4428     class Translate : public Element
4429     {
4430     public:
Translate(PhysXExporter & exporter,const MVector & translation,const String & sid="")4431         Translate(PhysXExporter& exporter, const MVector & translation, const String & sid = "")
4432             : Element(exporter, CSWC::CSW_ELEMENT_TRANSLATE)
4433         {
4434             if (sid.length() > 0)
4435                 getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_SID, sid);
4436             getStreamWriter().appendValues(translation.x, translation.y, translation.z);
4437         }
4438     };
4439 
4440     class Rotate : public Element
4441     {
4442     public:
Rotate(PhysXExporter & exporter,const MVector & axis,double angle,const String & sid="")4443         Rotate(PhysXExporter& exporter, const MVector & axis, double angle, const String & sid = "")
4444             : Element(exporter, CSWC::CSW_ELEMENT_ROTATE)
4445         {
4446             if (sid.length() > 0) {
4447                 getStreamWriter().appendAttribute(CSWC::CSW_ATTRIBUTE_SID, sid);
4448             }
4449             getStreamWriter().appendValues(axis.x, axis.y, axis.z, angle);
4450         }
4451     };
4452 
4453     String PhysXExporter::mDefaultPhysicsModelId = "collada_physics_model";
4454     String PhysXExporter::mDefaultPhysicsSceneId = "collada_physics_scene";
4455     String PhysXExporter::mDefaultInstancePhysicsModelSid = "instancePhysicsModel";
4456 	String PhysXExporter::mPhysXProfile = "PhysX_3.x";
4457 	String PhysXExporter::mXMLNS = "http://www.collada.org/2016/08/COLLADAPhysX3Schema";
4458 	String PhysXExporter::mSchemaLocation = "http://www.collada.org/2016/08/COLLADAPhysX3Schema.xsd";
4459 
PhysXExporter(StreamWriter & streamWriter,DocumentExporter & documentExporter)4460     PhysXExporter::PhysXExporter(StreamWriter& streamWriter, DocumentExporter& documentExporter)
4461         : mStreamWriter(streamWriter)
4462         , mDocumentExporter(documentExporter)
4463     {}
4464 
4465     class RigidBodyParser
4466     {
4467     public:
RigidBodyParser(const SceneElement & meshElement)4468         RigidBodyParser(const SceneElement & meshElement)
4469         : mMeshElement(meshElement)
4470         , mNeedsConvexHullOfMeshElement(false)
4471         {}
4472 
operator ()(SceneElement & element)4473         bool operator()(SceneElement & element)
4474         {
4475             if (element.getType() == SceneElement::PHYSX_RIGID_BODY)
4476             {
4477                 std::vector<MObject> shapes;
4478                 PhysXExporter::GetRigidBodyShapes(element.getNode(), shapes);
4479 
4480                 for (size_t i = 0; i < shapes.size(); ++i)
4481                 {
4482                     const MObject & shape = shapes[i];
4483                     int dummy = 0;
4484                     MString shapeType;
4485                     DagHelper::getPlugValue(shape, ATTR_SHAPE_TYPE, dummy, shapeType);
4486                     if (shapeType == SHAPE_TYPE_CONVEX_HULL)
4487                     {
4488                         MObject connectedMesh;
4489                         PhysXShape::GetConnectedInMesh(shape, connectedMesh);
4490 
4491                         if (mMeshElement.getNode() == connectedMesh ||
4492                             mMeshElement.getNode() == shape)
4493                         {
4494                             mNeedsConvexHullOfMeshElement = true;
4495                             mShape = shape;
4496                             return false;
4497                         }
4498                     }
4499                 }
4500             }
4501             return true;
4502         }
4503 
needsConvexHullOfMeshElement() const4504         bool needsConvexHullOfMeshElement() const
4505         {
4506             return mNeedsConvexHullOfMeshElement;
4507         }
4508 
getShape() const4509         const MObject& getShape() const
4510         {
4511             return mShape;
4512         }
4513 
4514     private:
4515         const SceneElement & mMeshElement;
4516         bool mNeedsConvexHullOfMeshElement;
4517         MObject mShape;
4518     };
4519 
needsConvexHullOf(const SceneElement & meshElement,MObject & shape)4520     bool PhysXExporter::needsConvexHullOf(const SceneElement & meshElement, MObject& shape)
4521     {
4522         if (!ExportOptions::exportPhysics())
4523             return false;
4524 
4525         RigidBodyParser parser(meshElement);
4526         parseSceneElements(parser);
4527         shape = parser.getShape();
4528         return parser.needsConvexHullOfMeshElement();
4529     }
4530 
ExtractPhysXPluginVersionNumbers(const MString & mversion,int & major,int & minor,int & a,int & b)4531     bool ExtractPhysXPluginVersionNumbers(
4532 		const MString & mversion,
4533         int & major,
4534         int & minor,
4535         int & a,
4536         int & b)
4537     {
4538         String version = mversion.asChar();
4539 
4540         size_t p1 = version.find('(');
4541         if (p1 == String::npos) return false;
4542         ++p1;
4543         if (p1 >= version.length()) return false;
4544 
4545         size_t p2 = version.find(')', p1);
4546         if (p2 == String::npos) return false;
4547 
4548         MString mnumbers = version.substr(p1, p2 - p1).c_str();
4549         MStringArray numbers;
4550         mnumbers.split('.', numbers);
4551         if (numbers.length() != 4) return false;
4552 
4553         std::stringstream s;
4554         s << numbers[0] << ' ' << numbers[1] << ' ' << numbers[2] << ' ' << numbers[3];
4555         s >> major >> minor >> a >> b;
4556 
4557         return true;
4558     }
4559 
CheckPhysXPluginVersion()4560     bool PhysXExporter::CheckPhysXPluginVersion()
4561     {
4562         MObject pluginObject = MFnPlugin::findPlugin("physx");
4563 
4564         if (pluginObject.isNull()) {
4565             return false;
4566         }
4567 
4568         MFnPlugin fnPlugin(pluginObject);
4569 
4570         MStatus status;
4571         MString mversion = fnPlugin.version(&status);
4572         if (!status) return false;
4573 
4574         int requ_major = 0;
4575         int requ_minor = 0;
4576         int requ_a = 0;
4577         int requ_b = 0;
4578 
4579         int curr_major = 0;
4580         int curr_minor = 0;
4581         int curr_a = 0;
4582         int curr_b = 0;
4583 
4584         if (!ExtractPhysXPluginVersionNumbers(GetRequiredPhysXPluginVersion(), requ_major, requ_minor, requ_a, requ_b)) {
4585             return false;
4586         }
4587 
4588         if (!ExtractPhysXPluginVersionNumbers(GetInstalledPhysXPluginVersion(), curr_major, curr_minor, curr_a, curr_b)) {
4589             return false;
4590         }
4591 
4592 		if (curr_major > requ_major) return false;
4593 		if (curr_major < requ_major) return false;
4594 		if (curr_minor > requ_minor) return true;
4595 		if (curr_minor < requ_minor) return false;
4596 		if (curr_a > requ_a) return true;
4597 		if (curr_a < requ_a) return false;
4598 		if (curr_b >= requ_b) return true;
4599 		if (curr_b < requ_b) return false;
4600 
4601         return true;
4602     }
4603 
GetRequiredPhysXPluginVersion()4604     MString PhysXExporter::GetRequiredPhysXPluginVersion()
4605     {
4606         return MString("PhysxForMaya (3.3.10708.21402) , compiled 7/8/2015 9:40:44 PM");
4607     }
4608 
GetInstalledPhysXPluginVersion()4609     MString PhysXExporter::GetInstalledPhysXPluginVersion()
4610     {
4611         static MString na = "N/A";
4612 
4613         MObject pluginObject = MFnPlugin::findPlugin("physx");
4614         if (pluginObject.isNull()) {
4615             return na;
4616         }
4617 
4618         MFnPlugin fnPlugin(pluginObject);
4619 
4620         MStatus status;
4621         MString version = fnPlugin.version(&status);
4622         if (!status) return na;
4623 
4624         return version;
4625     }
4626 
4627     class AutoDeleteFile
4628     {
4629     public:
AutoDeleteFile(const String & filePath)4630         AutoDeleteFile(const String& filePath)
4631             : mFilePath(filePath)
4632         {}
4633 
~AutoDeleteFile()4634         ~AutoDeleteFile()
4635         {
4636             if (!mFilePath.empty()) {
4637                 COLLADABU::Utils::deleteFile(mFilePath);
4638             }
4639         }
4640 
4641     private:
4642         String mFilePath;
4643     };
4644 
4645     class AutoXmlFreeDoc
4646     {
4647     public:
AutoXmlFreeDoc(xmlDocPtr xml)4648         AutoXmlFreeDoc(xmlDocPtr xml)
4649             : mXml(xml)
4650         {}
4651 
~AutoXmlFreeDoc()4652         ~AutoXmlFreeDoc()
4653         {
4654             if (mXml) {
4655                 xmlFreeDoc(mXml);
4656             }
4657         }
4658 
4659     private:
4660         xmlDocPtr mXml;
4661     };
4662 
4663     class AutoRestorePhysXExportOptions
4664     {
4665     public:
AutoRestorePhysXExportOptions()4666         AutoRestorePhysXExportOptions()
4667             : mError(false)
4668         {
4669             mOptions.push_back(Option("apexClothingExport_APBs", Integer));
4670             mOptions.push_back(Option("validatePhysXSceneBeforeExport", Integer));
4671             mOptions.push_back(Option("PhysXExport_useFolderName", Integer));
4672             mOptions.push_back(Option("apexExport_RemoveNamespaceForJoint", Integer));
4673             mOptions.push_back(Option("apexClothingExport_VisibleOnly", Integer));
4674             mOptions.push_back(Option("PhysXExport_UseJointLongName", Integer));
4675             mOptions.push_back(Option("PhysXExport_exportPxProjFile", Integer));
4676             mOptions.push_back(Option("PhysXExport_exportPhysX", Integer));
4677             mOptions.push_back(Option("PhysXExport_outputUnit", String));
4678             mOptions.push_back(Option("PhysXExport_customScaling", Integer));
4679             mOptions.push_back(Option("PhysXExport_outputScale", Double));
4680 
4681             for (size_t i = 0; i < mOptions.size(); ++i) {
4682                 switch (mOptions[i].type)
4683                 {
4684                 case Integer:
4685                 {
4686                     int oldValue = 0;
4687                     MStatus status = MGlobal::executeCommand("optionVar -q \"" + mOptions[i].name + "\"", oldValue);
4688                     if (!status) mError |= true;
4689                     MString oldValueStr("");
4690                     oldValueStr += oldValue;
4691                     mOldValues.push_back(oldValueStr);
4692                     break;
4693                 }
4694                 case Double:
4695                 {
4696                     double oldValue = 0.0;
4697                     MStatus status = MGlobal::executeCommand("optionVar -q \"" + mOptions[i].name + "\"", oldValue);
4698                     if (!status) mError |= true;
4699                     MString oldValueStr("");
4700                     oldValueStr += oldValue;
4701                     mOldValues.push_back(oldValueStr);
4702                     break;
4703                 }
4704                 case String:
4705                 {
4706                     MString oldValue;
4707                     MStatus status = MGlobal::executeCommand("optionVar -q \"" + mOptions[i].name + "\"", oldValue);
4708                     if (!status) mError |= true;
4709                     mOldValues.push_back(oldValue);
4710                     break;
4711                 }
4712                 }
4713             }
4714         }
4715 
~AutoRestorePhysXExportOptions()4716         ~AutoRestorePhysXExportOptions()
4717         {
4718             for (size_t i = 0; i < mOptions.size(); ++i) {
4719                 MString command = "optionVar -";
4720                 switch (mOptions[i].type)
4721                 {
4722                 case Integer:	command += "i"; break;
4723                 case Double:	command += "f"; break;
4724                 case String:	command += "s"; break;
4725                 }
4726 				command += "v \"" + mOptions[i].name + "\" ";
4727 				if (mOptions[i].type == String)
4728 					command += "\"";
4729 				command += mOldValues[i];
4730 				if (mOptions[i].type == String)
4731 					command += "\"";
4732                 MGlobal::executeCommand(command);
4733             }
4734         }
4735 
error() const4736         bool error() const
4737         {
4738             return mError;
4739         }
4740 
4741     private:
4742         enum OptionType
4743         {
4744             Integer,
4745             Double,
4746             String
4747         };
4748 
4749         struct Option
4750         {
OptionCOLLADAMaya::AutoRestorePhysXExportOptions::Option4751             Option(const MString& name_, OptionType type_)
4752                 : name(name_)
4753                 , type(type_)
4754             {}
4755 
4756             MString name;
4757             OptionType type;
4758         };
4759         std::vector<Option> mOptions;
4760         std::vector<MString> mOldValues;
4761         bool mError;
4762     };
4763 
4764 	class PhysicsExportPrePass
4765 	{
4766 	public:
PhysicsExportPrePass(PhysXExporter & exporter)4767 		PhysicsExportPrePass(PhysXExporter & exporter)
4768 			: mExporter(exporter)
4769 		{}
4770 
operator ()(SceneElement & e)4771 		bool operator()(SceneElement& e)
4772 		{
4773 			const MObject & object = e.getNode();
4774 
4775 			switch (e.getType())
4776 			{
4777 			case SceneElement::PHYSX_RIGID_BODY:
4778 			{
4779 				MObject target = PhysXExporter::GetRigidBodyTarget(e.getNode());
4780 				MFnDagNode targetNode(target);
4781 				MString targetName = targetNode.fullPathName();
4782 
4783 				mExporter.mTargetToRigidBodyMap[target] = object;
4784 
4785 				if (const PhysXXML::PxRigidBody* pxRigidBody = mExporter.mPhysXDoc->findRigidBody(targetName.asChar()))
4786 				{
4787 					mExporter.mRigidBodyToPxRigidBodyMap[object] = pxRigidBody;
4788 					mExporter.mPxRigidBodyToRigidBodyMap[pxRigidBody] = object;
4789 
4790 					if (pxRigidBody->shapes.shapes.size() > 0)
4791 					{
4792 						if (const PhysXXML::PxMaterial* pxMaterial = mExporter.mPhysXDoc->findMaterial(pxRigidBody->shapes.shapes[0].materials.materialRef.materialRef))
4793 						{
4794 							mExporter.mRigidBodyToPxMaterialMap[object] = pxMaterial;
4795 						}
4796 					}
4797 				}
4798 			}
4799 			break;
4800 			case SceneElement::PHYSX_SHAPE:
4801 			{
4802 				MFnDagNode shapeNode(e.getNode());
4803 				MString shapeName = shapeNode.fullPathName();
4804 				if (const PhysXXML::PxShape* pxShape = mExporter.mPhysXDoc->findShape(shapeName.asChar())) {
4805 					mExporter.mShapeToPxShapeMap[object] = pxShape;
4806 					mExporter.mPxShapeToShapeMap[pxShape] = object;
4807 				}
4808 			}
4809 			break;
4810 			case SceneElement::PHYSX_RIGID_CONSTRAINT:
4811 			{
4812 				MFnDagNode constraintNode(e.getNode());
4813 				MString constraintName = constraintNode.fullPathName();
4814 				if (const PhysXXML::PxD6Joint* joint = mExporter.mPhysXDoc->findD6Joint(constraintName.asChar())) {
4815 					mExporter.mConstraintToPxD6JointMap[object] = joint;
4816 					mExporter.mPxD6JointToConstraintMap[joint] = object;
4817 				}
4818 			}
4819 			break;
4820 			case SceneElement::PHYSX_RIGID_SOLVER:
4821 			{
4822 				mExporter.mRigidSolver = e.getNode();
4823 			}
4824 			break;
4825 			default:
4826 				break;
4827 			}
4828 			return true;
4829 		}
4830 
4831 	private:
4832 		PhysXExporter & mExporter;
4833 	};
4834 
generatePhysXXML()4835     bool PhysXExporter::generatePhysXXML()
4836     {
4837         MStatus status;
4838 
4839         // Backup export options
4840         AutoRestorePhysXExportOptions autoRestorePhysXExportOptions;
4841 
4842         // Set export options
4843         status = MGlobal::executeCommand("optionVar -iv \"apexClothingExport_APBs\" 2");
4844         if (!status) return false;
4845         status = MGlobal::executeCommand("optionVar -iv \"validatePhysXSceneBeforeExport\" 0");
4846         if (!status) return false;
4847         status = MGlobal::executeCommand("optionVar -iv \"PhysXExport_useFolderName\" 0");
4848         if (!status) return false;
4849         status = MGlobal::executeCommand("optionVar -iv \"apexExport_RemoveNamespaceForJoint\" 0");
4850         if (!status) return false;
4851         status = MGlobal::executeCommand("optionVar -iv \"apexClothingExport_VisibleOnly\" 0");
4852         if (!status) return false;
4853         status = MGlobal::executeCommand("optionVar -iv \"PhysXExport_UseJointLongName\" 1");
4854         if (!status) return false;
4855         status = MGlobal::executeCommand("optionVar -iv \"PhysXExport_exportPxProjFile\" 0");
4856         if (!status) return false;
4857         status = MGlobal::executeCommand("optionVar -iv \"PhysXExport_exportPhysX\" 1");
4858         if (!status) return false;
4859         status = MGlobal::executeCommand("optionVar -sv \"PhysXExport_outputUnit\" \"meter\"");
4860         if (!status) return false;
4861         status = MGlobal::executeCommand("optionVar -iv \"PhysXExport_customScaling\" true");
4862         if (!status) return false;
4863         status = MGlobal::executeCommand("optionVar -fv \"PhysXExport_outputScale\" 1.0");
4864         if (!status) return false;
4865 
4866         String filePath = mDocumentExporter.getFilename();
4867         std::stringstream exportCommand;
4868         exportCommand << "file -force -options \"none=0;\" -type \"PhysX\" -pr";
4869         if (mDocumentExporter.getSceneGraph()->getExportSelectedOnly()) {
4870             exportCommand << " -es";
4871         }
4872         else {
4873             exportCommand << " -ea";
4874         }
4875 
4876         // Generate temp file name
4877         size_t extPos = filePath.find_last_of('.');
4878         String filePathNoExt = filePath.substr(0, extPos);
4879         String tempFilePath = filePathNoExt + ".xml";
4880         std::ifstream tempFile(tempFilePath.c_str());
4881         int index = 0;
4882         while (tempFile.is_open()) {
4883             std::stringstream s;
4884             s << index++;
4885             tempFilePath = filePathNoExt + s.str() + ".xml";
4886             tempFile.close();
4887             tempFile.open(tempFilePath.c_str());
4888         }
4889 
4890         // Set .pxproj as extension but plugin will export a .xml file
4891         String pxProjPath = tempFilePath;
4892         extPos = pxProjPath.find_last_of('.');
4893         pxProjPath.replace(extPos, pxProjPath.length() - extPos, ".PxProj");
4894 
4895         exportCommand << " \"" << pxProjPath << "\";";
4896         status = MGlobal::executeCommand(exportCommand.str().c_str());
4897         if (!status) return false;
4898 
4899         // delete .xml file when we are done with it.
4900         AutoDeleteFile autoDeleteFile(tempFilePath);
4901 
4902         // Read .xml file
4903 
4904         // Is this necessary?
4905         LIBXML_TEST_VERSION;
4906 
4907         std::ifstream file(tempFilePath.c_str());
4908         if (!file.is_open()) {
4909             return false;
4910         }
4911 
4912         std::stringstream fileContentStream;
4913         fileContentStream << file.rdbuf();
4914         std::string fileContent(fileContentStream.str());
4915 
4916         int length = static_cast<int>(fileContent.length());
4917         xmlDocPtr xml = xmlReadMemory(fileContent.c_str(), length, "noname.xml", NULL, 0);
4918         if (xml == NULL) {
4919             return false;
4920         }
4921 
4922         AutoXmlFreeDoc autoXmlFreeDoc(xml);
4923 
4924         // Init our PhysX xml tree
4925         mPhysXDoc = xml;
4926 
4927         // Check for duplicated names
4928         if (!mPhysXDoc->validate()) {
4929             MGlobal::displayError("Error while exporting PhysX scene: duplicated names found.");
4930             return false;
4931         }
4932 
4933         xmlCleanupParser();
4934 
4935 		// Initialize physics exporter internal data
4936 		PhysicsExportPrePass prepass(*this);
4937 		parseSceneElements(prepass);
4938 
4939         return true;
4940     }
4941 
exportPhysicsLibraries()4942     bool PhysXExporter::exportPhysicsLibraries()
4943     {
4944         // Export to .xml format first using PhysX plugin exporter.
4945         // Produced file contains information not accessible with Maya API.
4946         if (!mPhysXDoc) {
4947             MGlobal::displayError("Can't generate PhysX XML data. PhysX will not be exported.");
4948             return false;
4949         }
4950 
4951         bool hasPhysicsScene = false;
4952 
4953         if (!ExportOptions::exportPhysics()) {
4954             return hasPhysicsScene;
4955         }
4956 
4957         if (sceneHas(SceneElement::PHYSX_RIGID_BODY, Local) ||
4958             sceneHas(SceneElement::PHYSX_RIGID_CONSTRAINT, Local)) {
4959             {
4960                 LibraryPhysicsModels(*this);
4961             }
4962             {
4963                 LibraryPhysicsScenes(*this);
4964             }
4965             hasPhysicsScene = true;
4966         }
4967 
4968         return hasPhysicsScene;
4969     }
4970 
getStreamWriter()4971     StreamWriter& PhysXExporter::getStreamWriter()
4972     {
4973         return mStreamWriter;
4974     }
4975 
getDocumentExporter()4976     DocumentExporter& PhysXExporter::getDocumentExporter()
4977     {
4978         return mDocumentExporter;
4979     }
4980 
exportTranslationWithoutConversion(const MVector & translation,const String & sid)4981 	void PhysXExporter::exportTranslationWithoutConversion(const MVector & translation, const String & sid)
4982 	{
4983 		if (!(COLLADABU::Math::Utils::equalsZero(translation.x, mDocumentExporter.getTolerance()) &&
4984 			COLLADABU::Math::Utils::equalsZero(translation.y, mDocumentExporter.getTolerance()) &&
4985 			COLLADABU::Math::Utils::equalsZero(translation.z, mDocumentExporter.getTolerance())))
4986 		{
4987 			Translate(*this, translation, sid);
4988 		}
4989 	}
4990 
exportTranslation(const MVector & translation,const String & sid)4991     void PhysXExporter::exportTranslation(const MVector & translation, const String & sid)
4992     {
4993         if (!(COLLADABU::Math::Utils::equalsZero(translation.x, mDocumentExporter.getTolerance()) &&
4994             COLLADABU::Math::Utils::equalsZero(translation.y, mDocumentExporter.getTolerance()) &&
4995             COLLADABU::Math::Utils::equalsZero(translation.z, mDocumentExporter.getTolerance())))
4996         {
4997             // Convert from Maya internal unit (cm) to export unit
4998             MVector convertedTranslation;
4999             convertedTranslation.x = MDistance::internalToUI(translation.x);
5000             convertedTranslation.y = MDistance::internalToUI(translation.y);
5001             convertedTranslation.z = MDistance::internalToUI(translation.z);
5002 
5003             Translate(*this, convertedTranslation, sid);
5004         }
5005     }
5006 
exportRotation(const MEulerRotation & rotation,const String & sid)5007     void PhysXExporter::exportRotation(const MEulerRotation & rotation, const String & sid)
5008     {
5009         RotateHelper rotateHelper(rotation);
5010         const std::vector<std::vector<double> >& rotationMatrix = rotateHelper.getRotationMatrix();
5011         const std::vector<String>& rotationParameters = rotateHelper.getRotationParameters();
5012 
5013         // Go through the axes for the rotations.
5014         for (uint i = 0; i < 3; ++i)
5015         {
5016             if (!COLLADABU::Math::Utils::equalsZero(rotationMatrix[i][3], mDocumentExporter.getTolerance()))
5017             {
5018                 exportRotate(MVector(
5019                     COLLADABU::Math::Utils::equalsZero(rotationMatrix[i][0], mDocumentExporter.getTolerance()) ? 0.0 : rotationMatrix[i][0],
5020                     COLLADABU::Math::Utils::equalsZero(rotationMatrix[i][1], mDocumentExporter.getTolerance()) ? 0.0 : rotationMatrix[i][1],
5021                     COLLADABU::Math::Utils::equalsZero(rotationMatrix[i][2], mDocumentExporter.getTolerance()) ? 0.0 : rotationMatrix[i][2]),
5022                     COLLADABU::Math::Utils::equalsZero(rotationMatrix[i][3], mDocumentExporter.getTolerance()) ? 0.0 : rotationMatrix[i][3],
5023                     sid + rotationParameters[i]
5024                     );
5025             }
5026         }
5027     }
5028 
exportAttributes(const MObject & object,const std::set<MString,MStringComp> & attributes)5029     void PhysXExporter::exportAttributes(const MObject & object, const std::set<MString, MStringComp> & attributes)
5030     {
5031         AttributeExporter attributeExporter(*this, attributes);
5032         MFnDependencyNode fnDependencyNode(object);
5033         AttributeParser::parseAttributes(fnDependencyNode, attributeExporter);
5034     }
5035 
5036 	namespace local
5037 	{
5038 		class ExtraAttributeExporter : public AttributeParser
5039 		{
5040 		public:
ExtraAttributeExporter(COLLADASW::StreamWriter & streamWriter,const MObject & obj)5041 			ExtraAttributeExporter(COLLADASW::StreamWriter& streamWriter, const MObject & obj)
5042 				: mStreamWriter(streamWriter)
5043 				, mObject(obj)
5044 			{}
5045 
5046 		private:
5047 			COLLADASW::StreamWriter & mStreamWriter;
5048 			MObject mObject;
5049 
5050 		protected:
onBeforePlug(MPlug & plug)5051 			virtual bool onBeforePlug(MPlug & plug) override
5052 			{
5053 				MStatus status;
5054 
5055 				MObject attr = plug.attribute(&status);
5056 				if (!status) return false;
5057 
5058 				MFnAttribute fnAttr(attr, &status);
5059 				if (!status) return false;
5060 
5061 				MString attrName = fnAttr.name(&status);
5062 				if (!status) return false;
5063 
5064 				bool isDynamic = fnAttr.isDynamic(&status);
5065 				if (!status) return false;
5066 
5067 				if (!isDynamic)
5068 					return false;
5069 
5070 				bool isHidden = fnAttr.isHidden(&status);
5071 				if (!status) return false;
5072 
5073 				if (isHidden)
5074 					return false;
5075 
5076 				return true;
5077 			}
5078 
5079 			template<typename ValueType>
exportExtraAttribute(const String & name,const String & type,const ValueType & value)5080 			void exportExtraAttribute(const String & name, const String & type, const ValueType & value)
5081 			{
5082 				mStreamWriter.openElement(CSWC::CSW_ELEMENT_PARAM);
5083 				mStreamWriter.appendAttribute(CSWC::CSW_ATTRIBUTE_NAME, name);
5084 				mStreamWriter.appendAttribute(CSWC::CSW_ATTRIBUTE_TYPE, type);
5085 				mStreamWriter.appendValues(value);
5086 				mStreamWriter.closeElement();
5087 			}
5088 
5089 			template<typename ValueType>
exportExtraAttribute(const String & name,const String & type,const ValueType & value0,const ValueType & value1)5090 			void exportExtraAttribute(const String & name, const String & type, const ValueType & value0, const ValueType & value1)
5091 			{
5092 				mStreamWriter.openElement(CSWC::CSW_ELEMENT_PARAM);
5093 				mStreamWriter.appendAttribute(CSWC::CSW_ATTRIBUTE_NAME, name);
5094 				mStreamWriter.appendAttribute(CSWC::CSW_ATTRIBUTE_TYPE, type);
5095 				mStreamWriter.appendValues(value0, value1);
5096 				mStreamWriter.closeElement();
5097 			}
5098 
5099 			template<typename ValueType>
exportExtraAttribute(const String & name,const String & type,const ValueType & value0,const ValueType & value1,const ValueType & value2)5100 			void exportExtraAttribute(const String & name, const String & type, const ValueType & value0, const ValueType & value1, const ValueType & value2)
5101 			{
5102 				mStreamWriter.openElement(CSWC::CSW_ELEMENT_PARAM);
5103 				mStreamWriter.appendAttribute(CSWC::CSW_ATTRIBUTE_NAME, name);
5104 				mStreamWriter.appendAttribute(CSWC::CSW_ATTRIBUTE_TYPE, type);
5105 				mStreamWriter.appendValues(value0, value1, value2);
5106 				mStreamWriter.closeElement();
5107 			}
5108 
5109 			template<typename ValueType>
exportExtraAttribute(const String & name,const String & type,const ValueType & value0,const ValueType & value1,const ValueType & value2,const ValueType & value3)5110 			void exportExtraAttribute(const String & name, const String & type, const ValueType & value0, const ValueType & value1, const ValueType & value2, const ValueType & value3)
5111 			{
5112 				mStreamWriter.openElement(CSWC::CSW_ELEMENT_PARAM);
5113 				mStreamWriter.appendAttribute(CSWC::CSW_ATTRIBUTE_NAME, name);
5114 				mStreamWriter.appendAttribute(CSWC::CSW_ATTRIBUTE_TYPE, type);
5115 				mStreamWriter.appendValues(value0, value1, value2, value3);
5116 				mStreamWriter.closeElement();
5117 			}
5118 
onBoolean(MPlug & plug,const MString & name,bool value)5119 			virtual void onBoolean(MPlug & plug, const MString & name, bool value) override
5120 			{
5121 				exportExtraAttribute(name.asChar(), CSWC::CSW_VALUE_TYPE_BOOL, value);
5122 			}
5123 
onInteger(MPlug & plug,const MString & name,int value)5124 			virtual void onInteger(MPlug & plug, const MString & name, int value) override
5125 			{
5126 				exportExtraAttribute(name.asChar(), CSWC::CSW_VALUE_TYPE_INT, value);
5127 			}
5128 
onInteger2(MPlug & plug,const MString & name,int value[2])5129 			virtual void onInteger2(MPlug & plug, const MString & name, int value[2]) override
5130 			{
5131 				exportExtraAttribute(name.asChar(), CSWC::CSW_VALUE_TYPE_INT2, value[0], value[1]);
5132 			}
5133 
onInteger3(MPlug & plug,const MString & name,int value[3])5134 			virtual void onInteger3(MPlug & plug, const MString & name, int value[3]) override
5135 			{
5136 				exportExtraAttribute(name.asChar(), CSWC::CSW_VALUE_TYPE_INT3, value[0], value[1], value[2]);
5137 			}
5138 
onFloat(MPlug & plug,const MString & name,float value)5139 			virtual void onFloat(MPlug & plug, const MString & name, float value) override
5140 			{
5141 				exportExtraAttribute(name.asChar(), CSWC::CSW_VALUE_TYPE_FLOAT, value);
5142 			}
5143 
onFloat2(MPlug & plug,const MString & name,float value[2])5144 			virtual void onFloat2(MPlug & plug, const MString & name, float value[2]) override
5145 			{
5146 				exportExtraAttribute(name.asChar(), CSWC::CSW_VALUE_TYPE_FLOAT2, value[0], value[1]);
5147 			}
5148 
onFloat3(MPlug & plug,const MString & name,float value[3])5149 			virtual void onFloat3(MPlug & plug, const MString & name, float value[3]) override
5150 			{
5151 				exportExtraAttribute(name.asChar(), CSWC::CSW_VALUE_TYPE_FLOAT3, value[0], value[1], value[2]);
5152 			}
5153 
onDouble(MPlug & plug,const MString & name,double value)5154 			virtual void onDouble(MPlug & plug, const MString & name, double value) override
5155 			{
5156 				exportExtraAttribute(name.asChar(), CSWC::CSW_VALUE_TYPE_DOUBLE, value);
5157 			}
5158 
onDouble2(MPlug & plug,const MString & name,double value[2])5159 			virtual void onDouble2(MPlug & plug, const MString & name, double value[2]) override
5160 			{
5161 				exportExtraAttribute(name.asChar(), CSWC::CSW_VALUE_TYPE_DOUBLE2, value[0], value[1]);
5162 			}
5163 
onDouble3(MPlug & plug,const MString & name,double value[3])5164 			virtual void onDouble3(MPlug & plug, const MString & name, double value[3]) override
5165 			{
5166 				exportExtraAttribute(name.asChar(), CSWC::CSW_VALUE_TYPE_DOUBLE3, value[0], value[1], value[2]);
5167 			}
5168 
onDouble4(MPlug & plug,const MString & name,double value[4])5169 			virtual void onDouble4(MPlug & plug, const MString & name, double value[4]) override
5170 			{
5171 				exportExtraAttribute(name.asChar(), CSWC::CSW_VALUE_TYPE_DOUBLE4, value[0], value[1], value[2], value[3]);
5172 			}
5173 
onString(MPlug & plug,const MString & name,const MString & value)5174 			virtual void onString(MPlug & plug, const MString & name, const MString & value) override
5175 			{
5176 				exportExtraAttribute(name.asChar(), CSWC::CSW_VALUE_TYPE_STRING, value.asChar());
5177 			}
5178 
onEnum(MPlug & plug,const MString & name,int enumValue,const MString & enumName)5179 			virtual void onEnum(MPlug & plug, const MString & name, int enumValue, const MString & enumName) override
5180 			{
5181 				// TODO export all possible enum values to be able to re-import them?
5182 				exportExtraAttribute(name.asChar(), CSWC::CSW_VALUE_TYPE_STRING, COLLADABU::StringUtils::translateToXML(String(enumName.asChar())));
5183 			}
5184 		};
5185 	}
5186 
exportExtraAttributes(const MObject & object)5187     void PhysXExporter::exportExtraAttributes(const MObject & object)
5188     {
5189 		if (HasExtraAttributes(object))
5190 		{
5191 			local::ExtraAttributeExporter extraAttributeExporter(mStreamWriter, object);
5192 			MFnDependencyNode node(object);
5193 			AttributeParser::parseAttributes(node, extraAttributeExporter);
5194 		}
5195     }
5196 
exportRotate(const MVector & axis,double angle,const String & sid)5197     void PhysXExporter::exportRotate(const MVector & axis, double angle, const String & sid)
5198     {
5199         Rotate(*this, axis, angle, sid);
5200     }
5201 
sceneHas(SceneElement::Type type,PhysXExporter::Filter filter)5202     bool PhysXExporter::sceneHas(SceneElement::Type type, PhysXExporter::Filter filter)
5203     {
5204         SceneGraph& sceneGraph = *mDocumentExporter.getSceneGraph();
5205         SceneElementsList& exportNodesTree = *sceneGraph.getExportNodesTree();
5206 
5207         // Parse all/selected DAG nodes
5208         for (size_t i = 0; i < exportNodesTree.size(); ++i)
5209         {
5210             SceneElement& sceneElement = *exportNodesTree[i];
5211             if (ElementHas(sceneElement, type, filter)) {
5212                 return true;
5213             }
5214         }
5215         return false;
5216     }
5217 
ElementHas(const SceneElement & element,SceneElement::Type type,PhysXExporter::Filter filter)5218     bool PhysXExporter::ElementHas(const SceneElement & element, SceneElement::Type type, PhysXExporter::Filter filter)
5219     {
5220         if (element.getType() == type) {
5221             switch (filter)
5222             {
5223             case All:
5224                 return true;
5225             case Local:
5226                 return element.getIsLocal();
5227             case Reference:
5228                 return !element.getIsLocal();
5229             }
5230         }
5231 
5232         // Recursive call for all the child elements
5233         for (uint i = 0; i<element.getChildCount(); ++i)
5234         {
5235             const SceneElement& childElement = *element.getChild(i);
5236             if (ElementHas(childElement, type, filter)) {
5237                 return true;
5238             }
5239         }
5240         return false;
5241     }
5242 
generateColladaId(const MDagPath & dagPath)5243     String PhysXExporter::generateColladaId(const MDagPath & dagPath)
5244     {
5245         // Get the maya mesh id.
5246         String mayaId = mDocumentExporter.dagPathToColladaId(dagPath);
5247 
5248         // Generate a COLLADA id for the new object.
5249         String colladaId = findColladaId(mayaId);
5250 
5251         // Check, if the unique id for the current geometry is already generated.
5252         if (!colladaId.empty()) return colladaId;
5253 
5254         // Get the node of the current mesh
5255         colladaId = mDocumentExporter.dagPathToColladaName(dagPath);
5256 
5257         // Make the id unique and store it in a map.
5258         colladaId = mIdList.addId(colladaId);
5259         mMayaIdToColladaId[mayaId] = colladaId;
5260 
5261         return colladaId;
5262     }
5263 
generateColladaName(const MDagPath & dagPath)5264     String PhysXExporter::generateColladaName(const MDagPath & dagPath)
5265     {
5266         return mDocumentExporter.dagPathToColladaName(dagPath);
5267     }
5268 
GetDefaultPhysicsModelId()5269     const String& PhysXExporter::GetDefaultPhysicsModelId()
5270     {
5271         return mDefaultPhysicsModelId;
5272     }
5273 
GetDefaultPhysicsSceneId()5274     const String& PhysXExporter::GetDefaultPhysicsSceneId()
5275     {
5276         return mDefaultPhysicsSceneId;
5277     }
5278 
GetDefaultInstancePhysicsModelSid()5279     const String& PhysXExporter::GetDefaultInstancePhysicsModelSid()
5280     {
5281         return mDefaultInstancePhysicsModelSid;
5282     }
5283 
GetPhysXProfile()5284 	const String & PhysXExporter::GetPhysXProfile()
5285 	{
5286 		return mPhysXProfile;
5287 	}
5288 
GetXMLNS()5289 	const String& PhysXExporter::GetXMLNS()
5290 	{
5291 		return mXMLNS;
5292 	}
5293 
GetXSISchemaLocation()5294 	String PhysXExporter::GetXSISchemaLocation()
5295 	{
5296 		return mXMLNS + " " + mSchemaLocation;
5297 	}
5298 
5299 	namespace local
5300 	{
5301 		class ExtraAttributeParser : public AttributeParser
5302 		{
5303 		public:
ExtraAttributeParser(const MObject & obj)5304 			ExtraAttributeParser(const MObject & obj)
5305 				: mHasExtraAttributes(false)
5306 			{}
5307 
hasExtraAttributes() const5308 			bool hasExtraAttributes() const { return mHasExtraAttributes; }
5309 
5310 		private:
5311 			bool mHasExtraAttributes;
5312 
5313 		protected:
onBeforePlug(MPlug & plug)5314 			virtual bool onBeforePlug(MPlug & plug) override
5315 			{
5316 				MStatus status;
5317 
5318 				MObject attr = plug.attribute(&status);
5319 				if (!status) return false;
5320 
5321 				MFnAttribute fnAttr(attr, &status);
5322 				if (!status) return false;
5323 
5324 				MString attrName = fnAttr.name(&status);
5325 				if (!status) return false;
5326 
5327 				bool isDynamic = fnAttr.isDynamic(&status);
5328 				if (!status) return false;
5329 
5330 				if (!isDynamic)
5331 					return false;
5332 
5333 				bool isHidden = fnAttr.isHidden(&status);
5334 				if (!status) return false;
5335 
5336 				if (isHidden)
5337 					return false;
5338 
5339 				mHasExtraAttributes = true;
5340 
5341 				// No need to continue parsing
5342 				return false;
5343 			}
5344 		};
5345 	}
5346 
HasExtraAttributes(const MObject & object)5347 	bool PhysXExporter::HasExtraAttributes(const MObject & object)
5348 	{
5349 		local::ExtraAttributeParser parser(object);
5350 		MFnDependencyNode node(object);
5351 		AttributeParser::parseAttributes(node, parser);
5352 		return parser.hasExtraAttributes();
5353 	}
5354 
CombineModeToCOLLADA(PhysXXML::CombineMode::FlagEnum flag)5355 	String PhysXExporter::CombineModeToCOLLADA(PhysXXML::CombineMode::FlagEnum flag)
5356 	{
5357 		return FlagsToCOLLADA(Flags<PhysXXML::CombineMode::FlagEnum>(flag), PhysXXML::CombineMode::GetFlagToStringMap());
5358 	}
5359 
ShapeFlagsToCOLLADA(const Flags<PhysXXML::ShapeFlags::FlagEnum> & flags)5360 	String PhysXExporter::ShapeFlagsToCOLLADA(const Flags<PhysXXML::ShapeFlags::FlagEnum> & flags)
5361 	{
5362 		return FlagsToCOLLADA(flags, PhysXXML::ShapeFlags::GetFlagToStringMap());
5363 	}
5364 
ActorFlagsToCOLLADA(const Flags<PhysXXML::ActorFlags::FlagEnum> & flags)5365 	String PhysXExporter::ActorFlagsToCOLLADA(const Flags<PhysXXML::ActorFlags::FlagEnum> & flags)
5366 	{
5367 		return FlagsToCOLLADA(flags, PhysXXML::ActorFlags::GetFlagToStringMap());
5368 	}
5369 
RigidBodyFlagsToCOLLADA(const Flags<PhysXXML::RigidBodyFlags::FlagEnum> & flags)5370 	String PhysXExporter::RigidBodyFlagsToCOLLADA(const Flags<PhysXXML::RigidBodyFlags::FlagEnum> & flags)
5371 	{
5372 		return FlagsToCOLLADA(flags, PhysXXML::RigidBodyFlags::GetFlagToStringMap());
5373 	}
5374 
ConstraintFlagsToCOLLADA(const Flags<PhysXXML::ConstraintFlags::FlagEnum> & flags)5375 	String PhysXExporter::ConstraintFlagsToCOLLADA(const Flags<PhysXXML::ConstraintFlags::FlagEnum> & flags)
5376 	{
5377 		return FlagsToCOLLADA(flags, PhysXXML::ConstraintFlags::GetFlagToStringMap());
5378 	}
5379 
DriveFlagsToCOLLADA(const Flags<PhysXXML::DriveFlags::FlagEnum> & flags)5380 	String PhysXExporter::DriveFlagsToCOLLADA(const Flags<PhysXXML::DriveFlags::FlagEnum> & flags)
5381 	{
5382 		return FlagsToCOLLADA(flags, PhysXXML::DriveFlags::GetFlagToStringMap());
5383 	}
5384 
findColladaId(const String & mayaId)5385     const String & PhysXExporter::findColladaId(const String & mayaId)
5386     {
5387         const StringToStringMap::const_iterator it = mMayaIdToColladaId.find(mayaId);
5388         if (it != mMayaIdToColladaId.end()) {
5389             return it->second;
5390         }
5391         return EMPTY_STRING;
5392     }
5393 
GetRigidBodyTargetTM(const MObject & rigidBody)5394 	MMatrix PhysXExporter::GetRigidBodyTargetTM(const MObject& rigidBody)
5395 	{
5396 		MObject target = GetRigidBodyTarget(rigidBody);
5397 		MDagPath targetDagPath;
5398 		MDagPath::getAPathTo(target, targetDagPath);
5399 		return targetDagPath.inclusiveMatrix();
5400 	}
5401 
GetRigidBodyTarget(const MObject & rigidBody)5402 	MObject PhysXExporter::GetRigidBodyTarget(const MObject& rigidBody)
5403 	{
5404 		MObject target;
5405 		PhysXExporter::GetPluggedObject(rigidBody, ATTR_TARGET, target);
5406 
5407 		// If target is null then use rigidBody as target
5408 		if (target.isNull())
5409 		{
5410 			target = rigidBody;
5411 		}
5412 		return target;
5413 	}
5414 
GetRigidBodyShapes(const MObject & rigidBody,std::vector<MObject> & shapes)5415     void PhysXExporter::GetRigidBodyShapes(const MObject & rigidBody, std::vector<MObject> & shapes)
5416     {
5417         MFnDependencyNode rigidBodyNode(rigidBody);
5418         MPlug plug = rigidBodyNode.findPlug(ATTR_PHYSICS_SHAPES);
5419         uint numConnectedElements = plug.numConnectedElements();
5420 
5421         for (uint i = 0; i < numConnectedElements; ++i)
5422         {
5423             MPlug elementPlug = plug.connectionByPhysicalIndex(i);
5424             MPlugArray connections;
5425             if (elementPlug.connectedTo(connections, true, false))
5426             {
5427                 shapes.push_back(connections[0].node());
5428             }
5429         }
5430     }
5431 
5432     // in kg
GetRigidBodyMass(const MObject & rigidBody)5433     double PhysXExporter::GetRigidBodyMass(const MObject & rigidBody)
5434     {
5435         int dummy = 0;
5436         MString overrideMassOrDensity;
5437         DagHelper::getPlugValue(rigidBody, ATTR_OVERRIDE_MASS_OR_DENSITY, dummy, overrideMassOrDensity);
5438 
5439         double mass = 0.0;
5440         if (overrideMassOrDensity == OVERRIDE_MASS_OR_DENSITY_MASS)
5441         {
5442             // Mass attribute is in kg
5443             DagHelper::getPlugValue(rigidBody, ATTR_MASS, mass);
5444         }
5445         else if (overrideMassOrDensity == OVERRIDE_MASS_OR_DENSITY_DENSITY)
5446         {
5447             // Density attribute is in g/cm3
5448             double density = 0.0;
5449             DagHelper::getPlugValue(rigidBody, ATTR_DENSITY, density);
5450             // Volume in cm3
5451             mass = density * GetRigidBodyVolume(rigidBody);
5452             // Convert g to kg
5453             mass /= 1000.0;
5454         }
5455         else //if (overrideMassOrDensity == OVERRIDE_MASS_OR_DENSITY_DISABLED)
5456         {
5457             std::vector<MObject> shapes;
5458             GetRigidBodyShapes(rigidBody, shapes);
5459             for (size_t i = 0; i < shapes.size(); ++i)
5460             {
5461                 mass += GetShapeMass(shapes[i]);
5462             }
5463         }
5464         return mass;
5465     }
5466 
5467     // in kg
GetShapeMass(const MObject & shape)5468     double PhysXExporter::GetShapeMass(const MObject & shape)
5469     {
5470         int dummy = 0;
5471         MString useMassOrDensity;
5472         DagHelper::getPlugValue(shape, ATTR_USE_MASS_OR_DENSITY, dummy, useMassOrDensity);
5473 
5474         double mass = 0.0;
5475         if (useMassOrDensity == USE_MASS_OR_DENSITY_MASS)
5476         {
5477             // Mass in kg
5478             DagHelper::getPlugValue(shape, ATTR_MASS, mass);
5479         }
5480         else //if (useMassOrDensity == USE_MASS_OR_DENSITY_DENSITY)
5481         {
5482             // Density in g/cm3
5483             double density = 0.0;
5484             DagHelper::getPlugValue(shape, ATTR_DENSITY, density);
5485             mass = density * GetShapeVolume(shape);
5486             // Convert g to kg
5487             mass /= 1000.0;
5488         }
5489 
5490         return mass;
5491     }
5492 
5493     // cm3
GetRigidBodyVolume(const MObject & rigidBody)5494     double PhysXExporter::GetRigidBodyVolume(const MObject & rigidBody)
5495     {
5496         std::vector<MObject> shapes;
5497         GetRigidBodyShapes(rigidBody, shapes);
5498         double volume = 0.0;
5499         for (size_t i = 0; i < shapes.size(); ++i)
5500         {
5501             volume += GetShapeVolume(shapes[i]);
5502         }
5503         return volume;
5504     }
5505 
5506     // cm3
GetShapeVolume(const MObject & shape)5507     double PhysXExporter::GetShapeVolume(const MObject & shape)
5508     {
5509         int dummy = 0;
5510         MString shapeType;
5511         DagHelper::getPlugValue(shape, ATTR_SHAPE_TYPE, dummy, shapeType);
5512 
5513         double volume = 0.0;
5514 
5515         if (shapeType == SHAPE_TYPE_BOX)
5516         {
5517             MVector size = MVector::zero;
5518             DagHelper::getPlugValue(shape, ATTR_SIZE, size);
5519             volume = size.x * size.y * size.z;
5520         }
5521         else if (shapeType == SHAPE_TYPE_CAPSULE)
5522         {
5523             double radius = 0.0;
5524             double height = 0.0;
5525             DagHelper::getPlugValue(shape, ATTR_RADIUS, radius);
5526             DagHelper::getPlugValue(shape, ATTR_HEIGHT, height);
5527             volume = M_PI * radius * radius * (4.0 / 3.0 * radius + height);
5528         }
5529         else if (
5530             shapeType == SHAPE_TYPE_CLOTH_SPHERES ||
5531             shapeType == SHAPE_TYPE_SPHERE
5532             )
5533         {
5534             double radius = 0.0;
5535             DagHelper::getPlugValue(shape, ATTR_RADIUS, radius);
5536             volume = 4.0 / 3.0 * M_PI * radius * radius * radius;
5537         }
5538         else if (shapeType == SHAPE_TYPE_CONVEX_HULL)
5539         {
5540             // Get convex mesh (not connected mesh)
5541             MObject mesh;
5542             PhysXShape::GetInMesh(shape, mesh);
5543 
5544             // Parse triangles
5545             MItMeshPolygon itMeshPolygon(mesh);
5546             for (itMeshPolygon.reset(); !itMeshPolygon.isDone(); itMeshPolygon.next())
5547             {
5548                 int numTriangles = 0;
5549                 itMeshPolygon.numTriangles(numTriangles);
5550                 for (int triangleIndex = 0; triangleIndex < numTriangles; ++triangleIndex)
5551                 {
5552                     MPointArray vertexList;
5553                     MIntArray vertexIndexList;
5554                     itMeshPolygon.getTriangle(triangleIndex, vertexList, vertexIndexList);
5555 
5556                     MPoint a, b, c;
5557                     a = vertexList[0];
5558                     b = vertexList[1];
5559                     c = vertexList[2];
5560 
5561                     MVector vab, vbc, vca;
5562                     vab = b - a;
5563                     vbc = c - b;
5564                     vca = a - c;
5565                     double ab, bc, ca;
5566                     ab = vab.length();
5567                     bc = vbc.length();
5568                     ca = vca.length();
5569                     // Use Heron's formula to calculate triangular pyramid signed volume
5570                     // base triangle perimeter
5571                     double p = 0.5 * (ab + bc + ca);
5572                     // base triangle area
5573                     double area = sqrt(p * (p-ab) * (p-bc) * (p-ca));
5574                     MVector vac;
5575                     vac = c - a;
5576                     // triangle plane normal
5577                     MVector n = vab ^ vac;
5578                     n.normalize();
5579                     // triangle plane equation constant
5580                     double d = -a.x*n.x - a.y*n.y - a.z*n.z;
5581                     // pyramid height
5582                     double h = d;
5583                     // pyramid volume
5584                     double subVolume = 1.0/3.0 * area * h;
5585                     subVolume *= -1;
5586                     // add to total volume
5587                     volume += subVolume;
5588                 }
5589             }
5590         }
5591         else
5592         {
5593             MVector bbSize = MVector::zero;
5594             DagHelper::getPlugValue(shape, ATTR_BOUNDING_BOX_SIZE, bbSize);
5595             volume = bbSize.x * bbSize.y * bbSize.z;
5596         }
5597 
5598         return volume;
5599     }
5600 
GetPluggedObject(const MObject & object,const MString & attribute,MObject & pluggedObject)5601     MStatus PhysXExporter::GetPluggedObject(const MObject & object, const MString & attribute, MObject & pluggedObject)
5602     {
5603         MStatus status;
5604 
5605         MFnDependencyNode node(object, &status);
5606         if (!status) return status;
5607 
5608         MPlug plug = node.findPlug(attribute, &status);
5609         if (!status) return status;
5610 
5611         MPlugArray plugArray;
5612         bool hasConnection = plug.connectedTo(plugArray, true, false, &status);
5613         if (!status) return status;
5614         if (hasConnection)
5615         {
5616             MPlug externalPlug = plugArray[0];
5617             bool externalPlugNull = externalPlug.isNull(&status);
5618             if (!status) return status;
5619             if (!externalPlugNull)
5620             {
5621                 pluggedObject = externalPlug.node(&status);
5622                 if (!status) return status;
5623             }
5624         }
5625         return MS::kSuccess;
5626     }
5627 
getMeshURI(const MObject & mesh,URI & meshURI)5628     MStatus PhysXExporter::getMeshURI(const MObject & mesh, URI & meshURI)
5629     {
5630         MStatus status;
5631 
5632         MFnDagNode meshDagNode(mesh, &status);
5633         if (!status) return status;
5634 
5635         MDagPath meshDagPath;
5636         status = meshDagNode.getPath(meshDagPath);
5637         if (!status) return status;
5638 
5639         String geometryId = mDocumentExporter.getGeometryExporter()->generateColladaMeshId(meshDagPath);
5640         meshURI = getDocumentExporter().getVisualSceneExporter()->getSceneElementURI(meshDagPath, geometryId);
5641 
5642         return status;
5643     }
5644 }
5645