1 /*
2     Copyright (c) 2008-2009 NetAllied Systems GmbH
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 #include "COLLADAMayaVisualSceneExporter.h"
18 #include "COLLADAMayaSceneGraph.h"
19 #include "COLLADAMayaGeometryExporter.h"
20 #include "COLLADAMayaDagHelper.h"
21 #include "COLLADAMayaConversion.h"
22 #include "COLLADAMayaExportOptions.h"
23 #include "COLLADAMayaAnimationExporter.h"
24 #include "COLLADAMayaSyntax.h"
25 #include "COLLADAMayaControllerExporter.h"
26 #include "COLLADAMayaRotateHelper.h"
27 #include "COLLADAMayaReferenceManager.h"
28 #include "COLLADAMayaMaterialExporter.h"
29 #include "COLLADAMayaLightExporter.h"
30 #include "COLLADAMayaLightProbeExporter.h"
31 #include "COLLADAMayaCameraExporter.h"
32 #include "COLLADAMayaEffectExporter.h"
33 #include "COLLADAMayaPhysicsExporter.h"
34 #include "COLLADAMayaShaderHelper.h"
35 #include "COLLADAMayaAttributeParser.h"
36 
37 #include <maya/MFnIkHandle.h>
38 #include <maya/MFnSkinCluster.h>
39 #include <maya/MItDag.h>
40 #include <maya/MFnIkJoint.h>
41 #include <maya/MQuaternion.h>
42 #include <maya/MEulerRotation.h>
43 #include <maya/MDagPath.h>
44 #include <maya/MFnCamera.h>
45 #include <maya/MFileIO.h>
46 #include <maya/MFnAttribute.h>
47 
48 #include "COLLADASWNode.h"
49 #include "COLLADASWInstanceGeometry.h"
50 #include "COLLADASWInstanceController.h"
51 #include "COLLADASWLibraryControllers.h"
52 #include "COLLADASWInstanceLight.h"
53 #include "COLLADASWInstanceCamera.h"
54 #include "COLLADASWInstanceNode.h"
55 #include "COLLADASWConstants.h"
56 #include "COLLADASWExtraTechnique.h"
57 
58 #include "Math/COLLADABUMathUtils.h"
59 
60 #include "assert.h"
61 
62 
63 namespace COLLADAMaya
64 {
65 
66     //---------------------------------------------------------------
VisualSceneExporter(COLLADASW::StreamWriter * streamWriter,DocumentExporter * documentExporter,const String & sceneId)67     VisualSceneExporter::VisualSceneExporter (
68         COLLADASW::StreamWriter* streamWriter,
69         DocumentExporter* documentExporter,
70         const String& sceneId )
71     : COLLADASW::LibraryVisualScenes ( streamWriter )
72     , mDocumentExporter ( documentExporter )
73     , mSceneId ( sceneId )
74     , mIsJoint ( false )
75     , mIsFirstRotation ( true )
76     , mVisualSceneAdded ( false )
77     , mVisualSceneNode ( NULL )
78 	, mLODIndexCounter1(0)
79 	, mLODIndexCounter2(0)
80     {
81     }
82 
~VisualSceneExporter()83 	VisualSceneExporter::~VisualSceneExporter()
84 	{
85 		lodCounterMap.clear();
86 	}
87 
88 
89     // ------------------------------------------------------------
exportVisualScenes()90     bool VisualSceneExporter::exportVisualScenes()
91     {
92         // Get the list with the transform nodes.
93         SceneGraph* sceneGraph = mDocumentExporter->getSceneGraph();
94         SceneElementsList* exportNodesTree = sceneGraph->getExportNodesTree();
95 
96         // The flag, if a node was exported and the visual scene tags must to be closed
97         bool nodeExported = false;
98 
99         // Export all/selected DAG nodes
100         size_t length = exportNodesTree->size();
101         for ( size_t i = 0; i < length; ++i )
102         {
103             // No instance node under the visual scene!
104             SceneElement* sceneElement = ( *exportNodesTree ) [i];
105 
106             // Exports all the nodes in a node and all its child nodes recursive
107             if ( exportVisualSceneNodes ( sceneElement ) ) nodeExported = true;
108         }
109 
110         // Just if a node was exported, the visual scene tag
111         // in the collada document is open and should be closed.
112         if ( nodeExported ) closeVisualScene();
113 
114         closeLibrary();
115 
116         // TODO
117         // Setup the reference information
118         // GetReferenceManager()->Synchronize();
119 
120         return nodeExported;
121     }
122 
123     // ---------------------------------------------------------------
124     // Exports all the nodes in a node and all its child nodes recursive
exportVisualSceneNodes(SceneElement * sceneElement)125     bool VisualSceneExporter::exportVisualSceneNodes ( SceneElement* sceneElement )
126     {
127         // Get the path of the current scene element.
128         const MDagPath dagPath = sceneElement->getPath();
129 
130         // Check if the element isn't already exported
131         SceneGraph* sceneGraph = mDocumentExporter->getSceneGraph();
132         SceneElement* instantiatedSceneElement = sceneGraph->findExportedElement ( dagPath );
133 
134         // If the element is a root element and it is instanced, we have to try to set
135         bool isInstance = dagPath.isInstanced ();
136         bool hasPreviousInstance =  ( instantiatedSceneElement != NULL );
137         if ( hasPreviousInstance )
138         {
139             sceneElement->setInstantiatedSceneElement ( instantiatedSceneElement );
140         }
141 
142         // The transform node
143         MStatus status;
144         MObject transformNode = dagPath.transform ( &status );
145         if ( ( status != MS::kSuccess ) && status.statusCode () == MStatus::kInvalidParameter ) return false;
146         MFnDagNode transform ( transformNode, &status );
147         if ( !status )
148         {
149             status.perror ( "MFnDagNode constructor" );
150             return false;
151         }
152 
153         bool isForced = sceneElement->getIsForced();
154         bool isVisible = sceneElement->getIsVisible();
155         bool isExportNode = sceneElement->getIsExportNode();
156 		bool isPhysicsNode = sceneElement->getIsPhysicsNode();
157 
158         // Check for a file reference
159         bool isLocal = sceneElement->getIsLocal();
160 
161         // If this is a DAG node (not a DAG shape) check to see whether we should enter
162         bool animationExport = true;
163         bool isSceneRoot = dagPath.length() == 0;
164         if ( !isSceneRoot )
165         {
166             if ( !isExportNode )
167             {
168                 animationExport = false;
169             }
170         }
171 
172         // The COLLADA Node
173         COLLADASW::Node* colladaSceneNode = NULL;
174 
175         // Flag if the node was exported
176         bool nodeExported = false;
177 
178         // Export the transform
179 		SceneElement::Type sceneElementType = sceneElement->getType();
180 		bool isTransform = dagPath.hasFn ( MFn::kTransform );
181 
182 		bool doExport = true;
183 
184 		// Do export LOD Group Node only during "NO_PASS" (in library_visual_scenes)
185 		if ((mDocumentExporter->mExportPass != VISUAL_SCENE_PASS && sceneElementType == SceneElement::LOD))
186 			doExport = false;
187 
188 		mLODIndexCounter1 = 1;
189 
190 		if (sceneElement->getParentCount())
191 		{
192 			SceneElement::Type sceneParentElementType = sceneElement->getParent()->getType();
193 			if ((mDocumentExporter->mExportPass == VISUAL_SCENE_PASS && sceneParentElementType == SceneElement::LOD))
194 			{
195 
196 				std::map<SceneElement*, int>::iterator iterator = lodCounterMap.find(sceneElement->getParent());
197 				if (iterator != lodCounterMap.end())
198 					mLODIndexCounter1 = ++iterator->second;
199 				else
200 					lodCounterMap.insert(std::make_pair(sceneElement->getParent(), mLODIndexCounter1));
201 			}
202 
203 
204 			if (mDocumentExporter->mExportPass == SECOND_LOD_PASS && sceneParentElementType == SceneElement::LOD)
205 				mLODIndexCounter2++;
206 		}
207 
208 		bool ContinueExport = false;
209 
210 		// DO export only from second LOD Node during "LOD second Pass" (in library_nodes)
211 		if (mDocumentExporter->mExportPass == SECOND_LOD_PASS && mLODIndexCounter2 > 1)
212 			ContinueExport = true;
213 
214 		// Do export only first LOD Node during "NO_PASS" (in library_visual_scenes)
215 		if ((ExportOptions::exportLOD() && (mDocumentExporter->mExportPass != SECOND_LOD_PASS && isTransform && doExport && mLODIndexCounter1 < 2)) || (!ExportOptions::exportLOD() && isTransform))
216 			ContinueExport = true;
217 
218 		if (ContinueExport)
219 	    {
220             // Taken out of unvisible transforms.
221 			if ((!ExportOptions::exportInvisibleNodes() && !isVisible && !isExportNode) || (ExportOptions::exportPhysics() && isPhysicsNode)) return false;
222 
223             // Export the scene graph node for all transform-derivatives
224             if ( dagPath.hasFn ( MFn::kJoint ) )
225             {
226                 sceneElement->setHasJoint(true);
227 				if (ExportOptions::exportJoints())
228                 {
229                     if ( animationExport )
230                     {
231                         colladaSceneNode = new COLLADASW::Node ( mDocumentExporter->getStreamWriter(), hasPreviousInstance );
232                         nodeExported = exportJointVisualSceneNode ( colladaSceneNode, sceneElement );
233 
234                         // Push it into the list of the exported elements
235                         sceneGraph->addExportedElement ( sceneElement );
236                     }
237                     else
238                     {
239                         isLocal = true;
240                     }
241                 }
242                 else
243                 {
244                     isTransform = false; // we didn't do anything to this node
245                 }
246             }
247             else
248             {
249                 // Just local export
250 				if (!isForced && !isLocal && !ExportOptions::exportXRefs()) return false;
251 
252                 if ( animationExport )
253                 {
254                     COLLADASW::StreamWriter* streamWriter = mDocumentExporter->getStreamWriter();
255                     colladaSceneNode = new COLLADASW::Node ( streamWriter, hasPreviousInstance );
256                     nodeExported = exportNodeVisualSceneNode ( colladaSceneNode, sceneElement );
257 
258                     // push it into the list of the exported elements
259                     sceneGraph->addExportedElement ( sceneElement );
260                 }
261                 else
262                 {
263                     isLocal = true;
264                 }
265             }
266         }
267 
268         // Export type-specific information
269         MFn::Type type = dagPath.apiType();
270         switch (type)
271         {
272         case MFn::kLookAt:
273         case MFn::kParentConstraint:
274         case MFn::kOrientConstraint:
275         case MFn::kConstraint:
276         case MFn::kAimConstraint:
277         case MFn::kPoleVectorConstraint:
278         case MFn::kPointConstraint:
279         case MFn::kNormalConstraint:
280             MGlobal::displayError ( "Export of constraints not supported: "
281                 + MString ( sceneElement->getNodeName ().c_str () ) );
282             break;
283 
284         case MFn::kAmbientLight:
285         case MFn::kSpotLight:
286         case MFn::kPointLight:
287         case MFn::kDirectionalLight:
288             break;
289 
290         case MFn::kMesh:
291             break;
292 
293         case MFn::kIkHandle:
294 			if (ExportOptions::exportJoints())
295             {
296                 MGlobal::displayError ( "Export of ik handles not supported: "
297                     + MString ( sceneElement->getNodeName ().c_str () ) );
298             }
299             break;
300 
301         case MFn::kCamera:
302             break;
303 
304         case MFn::kRigid:
305             //if ( ExportOptions::exportPhysics() )
306             {
307                 MGlobal::displayError ( "Export of physics not supported: "
308                     + MString ( sceneElement->getNodeName ().c_str () ) );
309             }
310             break;
311 
312         case MFn::kNurbsCurve:
313             {
314                 MGlobal::displayError ( "Export of spline not supported: "
315                     + MString ( sceneElement->getNodeName ().c_str () ) );
316             }
317             break;
318         case MFn::kNurbsSurface:
319             {
320                 MGlobal::displayError ( "Export of nurbs not supported: "
321                     + MString ( sceneElement->getNodeName ().c_str () ) );
322             }
323             break;
324         case MFn::kEmitter:
325             {
326                 MGlobal::displayError ( "Export of emitters not supported: "
327                     + MString ( sceneElement->getNodeName ().c_str () ) );
328             }
329             break;
330         case MFn::kAir:
331         case MFn::kDrag:
332         case MFn::kField:
333         case MFn::kGravity:
334         case MFn::kNewton:
335         case MFn::kRadial:
336         case MFn::kTurbulence:
337         case MFn::kUniform:
338         case MFn::kVortex:
339         case MFn::kVolumeAxis:
340             {
341                 MGlobal::displayError ( "Could not export. Unknown node type: "
342                     + MString ( sceneElement->getNodeName ().c_str () ) );
343             }
344             break;
345         default: break;
346         }
347 
348         // Check if the element is a local element and isn't already exported.
349         if ( isLocal && !hasPreviousInstance )
350         {
351             // Recursive call for all the child elements
352             for ( uint i=0; i<sceneElement->getChildCount(); ++i )
353             {
354                 SceneElement* childElement = sceneElement->getChild ( i );
355                 exportVisualSceneNodes ( childElement );
356             }
357         }
358 
359         // Close the visual scene tag in the collada document
360         if ( colladaSceneNode != NULL )
361         {
362             if ( nodeExported )
363             {
364                 // Close the current scene node
365                 colladaSceneNode->end();
366             }
367             delete ( colladaSceneNode );
368 
369             colladaSceneNode = NULL;
370         }
371 
372         return nodeExported;
373     }
374 
375     //------------------------------------------------------
exportJointVisualSceneNode(COLLADASW::Node * sceneNode,SceneElement * sceneElement)376     bool VisualSceneExporter::exportJointVisualSceneNode (
377         COLLADASW::Node *sceneNode,
378         SceneElement* sceneElement )
379     {
380         // Set the type of the node to a joint
381         sceneNode->setType ( COLLADASW::Node::JOINT );
382 
383         // Get the current dag path
384         MDagPath dagPath = sceneElement->getPath();
385         MObject node = dagPath.node();
386 
387         // Generate a COLLADA sid for the new object
388         String nodeSid = mDocumentExporter->dagPathToColladaSid(dagPath);
389         sceneNode->setNodeSid( nodeSid );
390 
391 //         // Export the segment-scale-compensate flag.
392 //         bool segmentScaleCompensate;
393 //         DagHelper::getPlugValue ( dagPath.transform(),
394 //                                   ATTR_SEGMENT_SCALE_COMPENSATE,
395 //                                   segmentScaleCompensate );
396 //
397 //         // Not animateable
398 //         sceneNode->addExtraTechniqueParameter ( PROFILE_MAYA,
399 //                                                 MAYA_SEGMENTSCALECOMP_PARAMETER,
400 //                                                 segmentScaleCompensate );
401 
402         // Export the node
403         return exportVisualSceneNode ( sceneNode, sceneElement );
404     }
405 
406     //------------------------------------------------------
exportNodeVisualSceneNode(COLLADASW::Node * sceneNode,SceneElement * sceneElement)407     bool VisualSceneExporter::exportNodeVisualSceneNode (
408         COLLADASW::Node *sceneNode,
409         SceneElement* sceneElement )
410     {
411         // Set the type of the node
412         sceneNode->setType ( COLLADASW::Node::NODE );
413 
414         // Export the node
415         return exportVisualSceneNode ( sceneNode, sceneElement );
416     }
417 
418     //---------------------------------------------------------------
exportVisualSceneNode(COLLADASW::Node * sceneNode,SceneElement * sceneElement)419     bool VisualSceneExporter::exportVisualSceneNode (
420         COLLADASW::Node* sceneNode,
421         SceneElement* sceneElement )
422     {
423         // Set the visual scene node
424         mVisualSceneNode = sceneNode;
425 
426         // Get the dagPath from the scene element
427         MDagPath dagPath = sceneElement->getPath();
428 
429         // Flag, if the node is already instantiated
430         bool isInstanceNode = mVisualSceneNode->getIsInstanceNode();
431 
432         // False, if the node has a external reference.
433         bool isLocal = sceneElement->getIsLocal();
434 
435 
436         // Do all the stuff if we export a full node.
437 		if (!isInstanceNode || mDocumentExporter->mExportPass == SECOND_LOD_PASS)
438         {
439             // Initialize the member variables
440             if ( !initializeTransform ( sceneElement ) )
441             {
442                 MString pathName = dagPath.fullPathName();
443                 MString message = "Could not initialize the transform object of the path " + pathName;
444                 MGlobal::displayError( message );
445                 return false;
446             }
447         }
448 
449         // Prepares the visual scene node
450         // (open the visual scene node o a node instance, if we need this).
451 		if (!openVisualSceneNode(sceneElement))
452 			return false;
453 
454 
455 		bool exportTransformation = false;
456 		if (mDocumentExporter->mExportPass == VISUAL_SCENE_PASS)
457 		{
458 			if (!isLocal || !isInstanceNode)
459 				exportTransformation = true;
460 		}
461 		else
462 		{
463 			if (sceneElement->getType() != SceneElement::LOD)
464 			{
465 				// Do export Transformation for LOD node only during 2nd Pass Library node
466 				SceneElement::Type sceneParentElementType = sceneElement->getParent()->getType();
467 				if ((mDocumentExporter->mExportPass == SECOND_LOD_PASS && sceneParentElementType == SceneElement::LOD))
468 					exportTransformation = false;
469 				else
470 					exportTransformation = true;
471 			}
472 		}
473 
474 		if (exportTransformation)
475 		{
476 			// Export the transformation information
477 			if (ExportOptions::bakeTransforms())
478 			{
479 				exportMatrixTransform();
480 			}
481 			else if (ExportOptions::exportCameraAsLookat() && dagPath.hasFn(MFn::kCamera))
482 			{
483 				exportLookatTransform();
484 			}
485 			else
486 			{
487 				exportDecomposedTransform();
488 			}
489 
490 			// Exports the visibility technique tag and the visibility animation.
491 			exportVisibility(sceneNode);
492 		}
493 
494 
495 		if (!isLocal || mDocumentExporter->mExportPass == SECOND_LOD_PASS ||
496 			(mDocumentExporter->mExportPass == VISUAL_SCENE_PASS && (ExportOptions::exportLOD() && (sceneElement->getParentCount() > 0 && sceneElement->getParent()->getType() == SceneElement::LOD))))
497         {
498             // Export the node external reference
499             exportInstanceNode ( sceneElement );
500         }
501         else if ( !isInstanceNode )
502         {
503             // Write the instance urls of the geometries, controllers
504             // and lights into the collada document.
505             exportInstanceChildNodes ( sceneElement );
506         }
507 
508         return true;
509     }
510 
511     //---------------------------------------------------------------
exportInstanceMaterial(COLLADASW::InstanceMaterialList & instanceMaterialList,const MDagPath & dagPath)512     void VisualSceneExporter::exportInstanceMaterial (
513         COLLADASW::InstanceMaterialList &instanceMaterialList,
514         const MDagPath &dagPath )
515     {
516         MaterialExporter* materialExporter = mDocumentExporter->getMaterialExporter ();
517         EffectExporter* effectExporter = mDocumentExporter->getEffectExporter ();
518 
519         // Find how many shaders are used by this instance of the mesh
520         const MObject& meshNode = dagPath.node();
521         MFnMesh fnMesh ( meshNode );
522 
523         // Get the connected shaders of the main mesh instance (we will take always the zero).
524         // This is a COLLADA workaround to get the symbolic material name.
525         // This is used to share a pointer in the geometry, but to use different materials in the node.
526         MObjectArray shaders;
527         MIntArray shaderIndices;
528         fnMesh.getConnectedShaders ( 0, shaders, shaderIndices );
529 
530         uint realShaderCount = ( uint ) shaders.length();
531         uint numShaders = ( uint ) std::max ( ( size_t ) 1, ( size_t ) shaders.length() );
532         for ( uint shaderPosition = 0; shaderPosition < numShaders; ++shaderPosition )
533         {
534             if ( shaderPosition < realShaderCount )
535             {
536                 // Add shader-specific parameters (TexCoords sets).
537                 // Add symbolic name for the material used on this polygon set.
538                 MObject shadingEngine = shaders[shaderPosition];
539                 MFnDependencyNode shadingEngineFn ( shadingEngine );
540                 String shadingEngineName = DocumentExporter::mayaNameToColladaName ( shadingEngineFn.name() );
541 
542                 // Check if the current mesh has some polygons for the connected shader.
543                 // If not, we don't need to write the current material instance.
544                 if ( !meshContainsShaderPolygons ( meshNode, shaders, shaderIndices, shaderPosition ) ) continue;
545 
546                 // To get the right shader name, we have to take the correct mesh instance.
547                 MStatus status;
548                 uint instanceNumber = dagPath.instanceNumber( &status ); CHECK_STAT( status );
549                 if ( instanceNumber > 0 )
550                 {
551                     MObjectArray instanceShaders;
552                     MIntArray instanceShaderIndices;
553                     fnMesh.getConnectedShaders ( instanceNumber, instanceShaders, instanceShaderIndices );
554                     shadingEngine = instanceShaders[shaderPosition];
555                 }
556 
557                 // This object contains a reference to a shader, or material, so we might call
558                 // our own function to write that material to our own data structure for later export.
559                 MObject shader = DagHelper::getSourceNodeConnectedTo ( shadingEngine, ATTR_SURFACE_SHADER );
560                 MFnDependencyNode shaderNode ( shader );
561                 String mayaMaterialId = DocumentExporter::mayaNameToColladaName ( shaderNode.name(), true );
562                 const String& colladaMaterialId = materialExporter->findColladaMaterialId ( mayaMaterialId );
563 
564                 // Create the material instance object.
565 				COLLADASW::InstanceMaterial materialInstance(shadingEngineName, COLLADASW::URI(EMPTY_STRING, colladaMaterialId));
566 
567                 // Retrieve all the file textures with the blend modes, if exist.
568                 MObjectArray fileTextures;
569                 MIntArray blendModes;
570                 effectExporter->getShaderTextures ( shader, ATTR_OUT_COLOR, fileTextures, blendModes );
571                 effectExporter->getShaderTextures ( shader, ATTR_INCANDESCENCE, fileTextures, blendModes );
572                 effectExporter->getShaderTextures ( shader, ATTR_AMBIENT_COLOR, fileTextures, blendModes );
573                 effectExporter->getShaderTextures ( shader, ATTR_COLOR, fileTextures, blendModes );
574                 effectExporter->getShaderTextures ( shader, ATTR_NORMAL_CAMERA, fileTextures, blendModes );
575                 effectExporter->getShaderTextures ( shader, ATTR_SPECULAR_COLOR, fileTextures, blendModes );
576                 effectExporter->getShaderTextures ( shader, ATTR_REFLECTED_COLOR, fileTextures, blendModes );
577                 effectExporter->getShaderTextures ( shader, ATTR_OUT_TRANSPARENCY, fileTextures, blendModes );
578                 effectExporter->getShaderTextures ( shader, ATTR_TRANSPARENCY, fileTextures, blendModes );
579                 uint fileTextureCount = fileTextures.length();
580 
581                 // Check if the current material instance uses a texcoord binding.
582                 MPlug uvSetMainPlug = MFnDependencyNode ( meshNode ).findPlug ( ATTR_UV_SET );
583                 for (uint i = 0; i < fileTextureCount; ++i)
584                 {
585                     // Get the current file texture.
586                     const MObject& fileTexture = fileTextures[i];
587 
588                     // Retrieve the UV set index for this texture
589                     uint uvSetIndex = ShaderHelper::getAssociatedUVSet ( meshNode, fileTexture );
590 
591                     // Retrieve the name for this UV set and match it with a DAE source.
592                     MPlug uvSetPlug = uvSetMainPlug.elementByPhysicalIndex ( uvSetIndex, &status );
593                     if (status != MStatus::kSuccess) continue;
594                     MPlug uvSetNamePlug = DagHelper::getChildPlug ( uvSetPlug, ATTR_UV_SET_NAME ); // "uvSetName"
595                     MString uvSetName; uvSetNamePlug.getValue(uvSetName);
596                     if (uvSetName.length() == 0) continue;
597 
598                     // Generate the name of the texture coordinates.
599                     String texCoordName = EffectExporter::TEXCOORD_BASE + COLLADASW::Utils::toString ( i );
600                     COLLADASW::BindVertexInput bindVertexInput ( texCoordName, COLLADASW::CSWC::CSW_SEMANTIC_TEXCOORD, uvSetIndex );
601                     materialInstance.push_back ( bindVertexInput );
602                 }
603 
604                 instanceMaterialList.push_back ( materialInstance );
605             }
606         }
607     }
608 
609     //---------------------------------------------------------------
meshContainsShaderPolygons(const MObject & mesh,const MObjectArray & shaders,const MIntArray & shaderIndices,const uint shaderPosition)610     const bool VisualSceneExporter::meshContainsShaderPolygons (
611         const MObject& mesh,
612         const MObjectArray& shaders,
613         const MIntArray& shaderIndices,
614         const uint shaderPosition )
615     {
616         // Iterate through all polygons of the current mesh.
617         MItMeshPolygon meshPolygonsIter ( mesh );
618         for ( meshPolygonsIter.reset(); !meshPolygonsIter.isDone(); meshPolygonsIter.next() )
619         {
620             // Is this polygon shaded by this shader?
621             int polyIndex = meshPolygonsIter.index();
622             uint realShaderCount = ( uint ) shaders.length();
623             if ( shaderPosition < realShaderCount &&
624                 ( uint ) shaderIndices[polyIndex] != shaderPosition ) continue;
625             if ( shaderPosition >= realShaderCount &&
626                 ( shaderIndices[polyIndex] >= 0 &&
627                 shaderIndices[polyIndex] < ( int ) realShaderCount ) ) continue;
628 
629             // Polygons for the current shader found.
630             return true;
631         }
632 
633         // No polygons for the current shader.
634         return false;
635     }
636 
GetThresholdPlugValue(const SceneElement * sceneElement,int indexLOD)637 	static float GetThresholdPlugValue(const SceneElement* sceneElement, int indexLOD)
638 	{
639 
640 		// Add Threshold value To switch to Next LOD Node
641 		double threshold = -1;
642 		MDagPath dagPath;
643 
644 		SceneElement::Type sceneElementType = sceneElement->getType();
645 		if (sceneElementType == SceneElement::LOD)
646 			dagPath = sceneElement->getPath();
647 		else
648 			dagPath = sceneElement->getParent()->getPath();
649 
650 		MStatus status;
651 		MObject transformNode = dagPath.transform(&status);
652 
653 		MPlug plugThreshold = MFnDependencyNode(transformNode).findPlug(ATTR_THRESHOLD, &status);
654 		if (status == MStatus::kSuccess)
655 		{
656 
657 			char indexLODString[50];
658 			sprintf(indexLODString, "%d", indexLOD);
659 
660 			MPlug plug = plugThreshold.elementByPhysicalIndex(indexLOD, &status);
661 
662 			String thresholdLOD = String(ATTR_THRESHOLD) + String("[") + String(indexLODString) + String("]");
663 			plug.getValue(threshold);
664 			threshold = MDistance::internalToUI(threshold);
665 		}
666 
667 		return (float)threshold;
668 	}
669 
670     //---------------------------------------------------------------
openVisualSceneNode(const SceneElement * sceneElement)671     bool VisualSceneExporter::openVisualSceneNode ( const SceneElement* sceneElement )
672     {
673         // Get the dagPath from the scene element
674         const MDagPath dagPath = sceneElement->getPath();
675 
676         // Add the visual scene, if not done before
677 		if (mDocumentExporter->mExportPass == VISUAL_SCENE_PASS)
678 		{
679 			if (!mVisualSceneAdded)
680 			{
681 				MString sceneName;
682 				MGlobal::executeCommand(MString("file -q -ns"), sceneName);
683 				if (sceneName.length() != 0) mSceneId = sceneName.asChar();
684 
685 				// There is always just one visual scene. Give it a valid unique id.
686 				String visualSceneName = COLLADABU::Utils::checkNCName(mSceneId);
687 				openVisualScene(VISUAL_SCENE_NODE_ID, visualSceneName);
688 				mVisualSceneAdded = true;
689 			}
690 		}
691 
692         bool isInstanceNode = mVisualSceneNode->getIsInstanceNode();
693         if ( isInstanceNode )
694         {
695             String mayaNodeId;
696 
697             // Get the URL of the instantiated visual scene node
698             SceneElement* instantiatedSceneElement = sceneElement->getInstantiatedSceneElement();
699             if ( instantiatedSceneElement != 0 )
700             {
701                 MDagPath instantiatedDagPath = instantiatedSceneElement->getPath();
702                 mayaNodeId = mDocumentExporter->dagPathToColladaId ( instantiatedDagPath );
703             }
704             else
705             {
706                 // The maya node id.
707                 mayaNodeId = mDocumentExporter->dagPathToColladaId ( dagPath );
708             }
709 
710             String colladaNodeId = findColladaNodeId ( mayaNodeId );
711             if ( colladaNodeId.empty () )
712             {
713                 colladaNodeId = getColladaNodeId ( dagPath );
714             }
715 
716             mVisualSceneNode->setNodeURL ( COLLADASW::URI ( EMPTY_STRING, colladaNodeId ) );
717 
718 			if (mDocumentExporter->mExportPass == SECOND_LOD_PASS)
719 			{
720 				// Get the dag node.
721 				MFnDagNode node(dagPath.node());
722 
723 				// The maya node id.
724 				String mayaNodeId = mDocumentExporter->dagPathToColladaId(dagPath);
725 
726 				// Export the original maya name.
727 				mVisualSceneNode->setNodeId(String("LOD__") + mayaNodeId);
728 				mVisualSceneNode->setNodeName(mayaNodeId);
729 
730 				//mVisualSceneNode->addExtraTechniqueParameter(PROFILE_MAYA, PARAMETER_MAYA_ID, mayaNodeId);
731 			}
732         }
733         else
734         {
735 			// Get the dag node.
736 			MFnDagNode node(dagPath.node());
737 
738 			// The maya node id.
739 			String mayaNodeId = mDocumentExporter->dagPathToColladaId(dagPath);
740 
741 			// Generate a COLLADA id for the new object.
742 			String colladaNodeId = getColladaNodeId(dagPath);
743 
744 			// Make the id unique and store it in a map.
745 			colladaNodeId = mNodeIdList.addId(colladaNodeId, mDocumentExporter->mExportPass == VISUAL_SCENE_PASS ? false : true);
746 
747 			mMayaIdColladaNodeId[mayaNodeId] = colladaNodeId;
748 
749 			// Set the node id and the name.
750 			mVisualSceneNode->setNodeId(colladaNodeId);
751 			String nodeName = mDocumentExporter->dagPathToColladaName(dagPath);
752 
753 			mVisualSceneNode->setNodeName(nodeName);
754 
755 			mVisualSceneNode->addExtraTechniqueParameter(PROFILE_MAYA, PARAMETER_MAYA_ID, nodeName);
756         }
757 
758 		exportExtraAttributes(sceneElement);
759 
760         // TODO Export the imported extra tags, if there exist some.
761 
762 
763         // open the scene node
764 
765 		bool lodPass = false;
766 		if (mDocumentExporter->mExportPass == SECOND_LOD_PASS || mDocumentExporter->mExportPass == FIRST_LOD_PASS)
767 			lodPass = true;
768 
769 		if (mDocumentExporter->mExportPass == SECOND_LOD_PASS)
770 		{
771 			int indexLOD;
772 			String proxy = findNextColladaNodeId(sceneElement, indexLOD);
773 			if (proxy.compare(EMPTY_STRING) == 0)
774 				return false;
775 
776 		}
777 
778 		mVisualSceneNode->start(lodPass);
779 		return true;
780     }
781 
782     //---------------------------------------------------------------
initializeTransform(SceneElement * sceneElement)783     bool VisualSceneExporter::initializeTransform ( SceneElement* sceneElement )
784     {
785         // Get the dagPath from the scene element
786         MDagPath dagPath = sceneElement->getPath();
787         mDagPath = dagPath;
788 
789         MStatus status;
790         MObject transformNode = dagPath.transform ( &status );
791         if ( ( status != MS::kSuccess ) && status.statusCode () == MStatus::kInvalidParameter ) return false;
792 
793         mTransformObject = transformNode;
794         MFnDagNode transform ( transformNode, &status );
795         if ( !status )
796         {
797             status.perror ( "MFnDagNode constructor" );
798             return false;
799         }
800 
801         // Get the transforms local translation
802         MFnTransform fn ( transformNode );
803         mTransformMatrix = fn.transformation();
804         if ( fn.parentCount() > 0 )
805         {
806             MFnTransform t ( fn.parent ( 0 ) );
807             if ( t.hasObj ( MFn::kClusterFilter ) || t.hasObj ( MFn::kSkinClusterFilter ) )
808             {
809                 mTransformMatrix = MTransformationMatrix ( mTransformMatrix.asMatrix() * t.transformationMatrix() );
810             }
811         }
812 
813         // Skins being exported from maya need to have the bindpose matrix
814         // subtracted from the instance matrix.
815         bool oneSkinAlready = false;
816 
817         // Check the child instances, which use this visual scene node.
818         size_t childCount = sceneElement->getChildCount();
819         for ( size_t i=0; i<childCount && !oneSkinAlready; ++i )
820         {
821             // Check if the child element is a mesh object and an export node
822             SceneElement* childElement = sceneElement->getChild ( i );
823             if ( childElement->getType() == SceneElement::MESH &&
824                 childElement->getIsExportNode() )
825             {
826                 // Get the controller library
827                 ControllerExporter* controller = mDocumentExporter->getControllerExporter();
828                 MObject childNode = childElement->getPath().node();
829                 bool hasSkinController = controller->hasSkinController ( childNode );
830                 if ( hasSkinController )
831                 {
832                     // Skins being exported from maya need to have the bindpose matrix
833                     // subtracted from the instance matrix.
834                     MMatrix bindShapeMatrix = childElement->getBindShapeMatrix ();
835                     MMatrix transformMatrix = mTransformMatrix.asMatrix ();
836 
837                     // Calculate the world transform of the node.
838                     MMatrix transformMx = bindShapeMatrix.inverse () * transformMatrix;
839 
840                     // Set the new calculated transform matrix
841                     mTransformMatrix = transformMx;
842                     mTransformObject = MObject::kNullObj;
843 
844                     // Do it just once.
845                     oneSkinAlready = true;
846                 }
847             }
848         }
849 
850         return true;
851     }
852 
853     //---------------------------------------------------------------
exportDecomposedTransform()854     void VisualSceneExporter::exportDecomposedTransform()
855     {
856         MVector translation = mTransformMatrix.translation ( MSpace::kTransform );
857         MPoint rotatePivotTranslation = mTransformMatrix.rotatePivotTranslation ( MSpace::kTransform );
858         MPoint rotatePivot = mTransformMatrix.rotatePivot ( MSpace::kTransform, NULL );
859         MVector scalePivotTranslation = mTransformMatrix.scalePivotTranslation ( MSpace::kTransform );
860         MVector scalePivot = mTransformMatrix.scalePivot ( MSpace::kTransform );
861         double shear[3] = {0, 0, 0};
862         mTransformMatrix.getShear ( shear, MSpace::kTransform );
863 
864         MEulerRotation jointOrientation, rotation, rotationAxis;
865         if ( mTransformObject != MObject::kNullObj )
866         {
867             mIsJoint = DagHelper::getPlugValue ( mTransformObject, ATTR_JOINT_ORIENT, jointOrientation );
868 
869             if ( !DagHelper::getPlugValue ( mTransformObject, ATTR_ROTATE, rotation ) ) rotation.setValue ( 0, 0, 0 );
870             if ( !DagHelper::getPlugValue ( mTransformObject, ATTR_ROTATE_AXIS, rotationAxis ) ) rotationAxis.setValue ( 0, 0, 0 );
871 
872             rotation.order = ( MEulerRotation::RotationOrder ) ( ( int ) mTransformMatrix.rotationOrder() - MTransformationMatrix::kXYZ + MEulerRotation::kXYZ );
873             rotationAxis.order = jointOrientation.order = MEulerRotation::kXYZ;
874         }
875         else
876         {
877             rotation = mTransformMatrix.eulerRotation();
878             rotation.order = ( MEulerRotation::RotationOrder ) ( ( int ) mTransformMatrix.rotationOrder() - MTransformationMatrix::kXYZ + MEulerRotation::kXYZ );
879             mIsJoint = false;
880         }
881 
882         // This is the order of the transforms:
883         //
884         // matrix = [SP-1 * S * SH * SP * ST] * [RP-1 * RA * R * JO * RP * RT] * T
885         //          [        scale          ] * [          rotation          ] * translation
886         //
887         // Where SP is scale pivot translation, S is scale, SH is shear, ST is scale pivot translation
888         // RP is rotation pivot, RA is rotation axis, R is rotation, RP is rotation pivot,
889         // RT is rotation pivot translation, T is translation, JO is joint orientation
890         //
891         // references: Maya documentation - transform node, Maya documentation - joint node
892         // NOTE: Left multiplying, column-order matrices
893         //
894         exportTranslation ( ATTR_TRANSLATE, translation, true );
895         exportTranslation ( ATTR_ROTATE_PIVOT_TRANSLATION, rotatePivotTranslation, false );
896         exportTranslation ( ATTR_ROTATE_PIVOT, rotatePivot, false );
897 
898         if ( mIsJoint ) exportRotation ( ATTR_JOINT_ORIENT, jointOrientation );
899         exportRotation ( ATTR_ROTATE, rotation );
900         if ( mIsJoint ) exportRotation ( ATTR_ROTATE_AXIS, rotationAxis );
901 
902         exportTranslation ( ATTR_ROTATE_PIVOT_INVERSE, rotatePivot * -1, false );
903         exportTranslation ( ATTR_SCALE_PIVOT_TRANSLATION, scalePivotTranslation, false );
904         exportTranslation ( ATTR_SCALE_PIVOT, scalePivot, false );
905 
906         exportSkew ( shear );
907 
908         // get the transforms scale
909         exportScale();
910 
911         exportTranslation ( ATTR_SCALE_PIVOT_INVERSE, scalePivot * -1, false );
912     }
913 
914     //---------------------------------------------------------------
exportSkew(double * shear)915     void VisualSceneExporter::exportSkew ( double* shear )
916     {
917         // From my derivation, it is easier to split the shear into three.
918         // This forces the hard coded axises and the angle becomes simply:
919         // skewAngle = arctan(shearValue);
920         //
921 
922         float xAxis[] = {1.0f, 0.0f, 0.0f};
923         float yAxis[] = {0.0f, 1.0f, 0.0f};
924         float zAxis[] = {0.0f, 0.0f, 1.0f};
925 
926         if ( !COLLADABU::Math::Utils::equalsZero ( shear[0], getTolerance () ) )
927         {
928             double angle = COLLADABU::Math::Utils::radToDeg ( atan ( shear[0] ) );
929             angle = COLLADABU::Math::Utils::equalsZero ( angle, getTolerance () ) ? 0 : angle;
930             float* rotateAxis ( xAxis );
931             float* aroundAxis ( yAxis );
932 
933             mVisualSceneNode->addSkew ( SKEW_XY_SID, (float) angle, rotateAxis, aroundAxis );
934 
935 //             // Set the animation, if the skew is animated.
936 //             AnimationExporter* animationExporter = mDocumentExporter->getAnimationExporter();
937 //             animationExporter->addNodeAnimation ( mTransformObject, ATTR_SKEW, ( SampleType ) ( kSingle | kQualifiedAngle ), XY_PARAMETER );
938         }
939 
940         if ( !COLLADABU::Math::Utils::equalsZero ( shear[1], getTolerance () ) )
941         {
942             double angle = COLLADABU::Math::Utils::radToDeg ( atan ( shear[1] ) );
943             angle = COLLADABU::Math::Utils::equalsZero( angle, getTolerance () ) ? 0 : angle;
944             float* rotateAxis ( xAxis );
945             float* aroundAxis ( zAxis );
946 
947             mVisualSceneNode->addSkew ( SKEW_XZ_SID, (float) angle, rotateAxis, aroundAxis );
948 
949 //             // Set the animation, if the skew is animated.
950 //             AnimationExporter* animationExporter = mDocumentExporter->getAnimationExporter();
951 //             animationExporter->addNodeAnimation ( mTransformObject, ATTR_SKEW, ( SampleType ) ( kSingle | kQualifiedAngle ), XZ_PARAMETER );
952         }
953 
954         if ( !COLLADABU::Math::Utils::equalsZero ( shear[2], getTolerance () ) )
955         {
956             double angle = MAngle::internalToUI ( atan ( shear[2] ) );
957             angle = COLLADABU::Math::Utils::equalsZero( angle, getTolerance () ) ? 0 : angle;
958             float* rotateAxis ( yAxis );
959             float* aroundAxis ( zAxis );
960 
961             mVisualSceneNode->addSkew ( SKEW_YZ_SID, (float) angle, rotateAxis, aroundAxis );
962 
963 //             // Set the animation, if the skew is animated.
964 //             AnimationExporter* animationExporter = mDocumentExporter->getAnimationExporter();
965 //             animationExporter->addNodeAnimation ( mTransformObject, ATTR_SKEW, ( SampleType ) ( kSingle | kQualifiedAngle ), YZ_PARAMETER );
966         }
967     }
968 
969     //---------------------------------------------------------------
exportScale()970     void VisualSceneExporter::exportScale()
971     {
972         // Get the scale.
973         double scale[3] = {1, 1, 1};
974         mTransformMatrix.getScale ( scale, MSpace::kTransform );
975 
976         // Check if all fields in the std::vector are ones
977         bool isOneVector = true;
978         for ( int i=0; i<3 && isOneVector; ++i )
979         {
980             if ( !COLLADABU::Math::Utils::equals( scale[i], 1.0, getTolerance () ) ) isOneVector = false;
981         }
982 
983         // Check if the scale is animated.
984         AnimationExporter* animationExporter = mDocumentExporter->getAnimationExporter();
985         bool isAnimated = animationExporter->addNodeAnimation ( mTransformObject, ATTR_SCALE, kVector, XYZ_PARAMETERS );
986 
987         if ( mTransformObject != MObject::kNullObj || ( !isOneVector || isAnimated ) )
988         {
989             mVisualSceneNode->addScale (
990                 ATTR_SCALE,
991                 COLLADABU::Math::Utils::equalsZero ( scale[0], getTolerance () ) ? 0 : scale[0],
992                 COLLADABU::Math::Utils::equalsZero ( scale[1], getTolerance () ) ? 0 : scale[1],
993                 COLLADABU::Math::Utils::equalsZero ( scale[2], getTolerance () ) ? 0 : scale[2] );
994         }
995     }
996 
997     //---------------------------------------------------------------
exportTranslation(const String name,const MPoint & translation,bool animation)998     void VisualSceneExporter::exportTranslation (
999         const String name,
1000         const MPoint& translation,
1001         bool animation )
1002     {
1003         exportTranslation ( name, MVector ( translation ), animation );
1004     }
1005 
1006     //---------------------------------------------------------------
exportTranslation(const String name,const MVector & translation,bool animation)1007     void VisualSceneExporter::exportTranslation (
1008         const String name,
1009         const MVector& translation,
1010         bool animation )
1011     {
1012         bool isZero = true;
1013         for ( int i=0; i<3 && isZero; ++i )
1014         {
1015             if ( translation[i] != 0 ) isZero = false;
1016         }
1017 
1018         if ( animation || !isZero )
1019         {
1020             // Convert the  maya internal unit type from centimeters
1021             // into the working units of the current scene!
1022             mVisualSceneNode->addTranslate (
1023                 name,
1024                 COLLADABU::Math::Utils::equalsZero( translation.x, getTolerance () ) ? 0 : MDistance::internalToUI ( translation.x ),
1025                 COLLADABU::Math::Utils::equalsZero( translation.y, getTolerance () ) ? 0 : MDistance::internalToUI ( translation.y ),
1026                 COLLADABU::Math::Utils::equalsZero( translation.z, getTolerance () ) ? 0 : MDistance::internalToUI ( translation.z ) );
1027 
1028             if ( animation )
1029             {
1030                 AnimationExporter* animationExporter = mDocumentExporter->getAnimationExporter();
1031                 animationExporter->addNodeAnimation ( mDagPath.node(), ATTR_TRANSLATE, name, ( SampleType ) ( kVector | kLength ), XYZ_PARAMETERS, true );
1032             }
1033         }
1034     }
1035 
1036     //---------------------------------------------------------------
exportRotation(const String name,const MEulerRotation & rotation)1037     void VisualSceneExporter::exportRotation (
1038         const String name,
1039         const MEulerRotation& rotation )
1040     {
1041         RotateHelper rotateHelper ( rotation );
1042         std::vector<std::vector<double> >& matrixRotate = rotateHelper.getRotationMatrix ();
1043         std::vector<String>& rotateParams = rotateHelper.getRotationParameters ();
1044 
1045         // Set zero flags, where the rotation is zero. The order of rotation is ZYX.
1046         bool isZero[3] = {  COLLADABU::Math::Utils::equalsZero ( matrixRotate[0][3], getTolerance () ),
1047                             COLLADABU::Math::Utils::equalsZero ( matrixRotate[1][3], getTolerance () ),
1048                             COLLADABU::Math::Utils::equalsZero ( matrixRotate[2][3], getTolerance () ) };
1049 
1050         // Get a pointer to the animation exporter.
1051         AnimationExporter* animationExporter = mDocumentExporter->getAnimationExporter();
1052 
1053         // The array for the animations.
1054         bool isAnimated[3] = { false, false, false };
1055 
1056         // Go through the axes for the animations.
1057         for ( uint i=0; i<3; ++i )
1058         {
1059             // Add the animation in the order XYZ
1060             isAnimated[i] = animationExporter->addNodeAnimation ( mTransformObject, name + rotateParams[i], ( SampleType ) ( kSingle | kQualifiedAngle ), ANGLE_PARAMETER );
1061         }
1062 
1063         // Go through the axes for the rotations.
1064         for ( uint i=0; i<3; ++i )
1065         {
1066             bool rotationIsNecessary = false;
1067 
1068             // Check, if we have to write the rotation.
1069             if ( mIsJoint && COLLADABU::Utils::equalsIgnoreCase ( name, ATTR_JOINT_ORIENT ))
1070             {
1071                 // A joint must always have a rotation.
1072                 rotationIsNecessary = true;
1073             }
1074             else
1075             {
1076                 // You have to write the rotation, if the element is animated.
1077                 rotationIsNecessary = ( isAnimated[i] || !( !mIsFirstRotation && isZero[i] ));
1078             }
1079 
1080             if ( mTransformObject != MObject::kNullObj && rotationIsNecessary )
1081             {
1082                 // Add the rotation in the order ZYX
1083                 mVisualSceneNode->addRotate (
1084                     name + rotateParams[i],
1085                     COLLADABU::Math::Utils::equalsZero( matrixRotate[i][0], getTolerance () ) ? 0 : matrixRotate[i][0],
1086                     COLLADABU::Math::Utils::equalsZero( matrixRotate[i][1], getTolerance () ) ? 0 : matrixRotate[i][1],
1087                     COLLADABU::Math::Utils::equalsZero( matrixRotate[i][2], getTolerance () ) ? 0 : matrixRotate[i][2],
1088                     COLLADABU::Math::Utils::equalsZero( matrixRotate[i][3], getTolerance () ) ? 0 : matrixRotate[i][3] );
1089             }
1090         }
1091 
1092         mIsFirstRotation = false;
1093     }
1094 
1095     //---------------------------------------------------------------
exportMatrixTransform()1096     void VisualSceneExporter::exportMatrixTransform()
1097     {
1098         MMatrix mayaSceneMatrix = mTransformMatrix.asMatrix();
1099         double sceneMatrix[4][4] ;
1100         convertMayaMatrixToTransposedDouble4x4 ( sceneMatrix, mayaSceneMatrix, getTolerance () );
1101 
1102         // Convert the  maya internal unit type of the transform part of the
1103         // matrix from centimeters into the working units of the current scene!
1104         for ( uint i=0; i<3; ++i)
1105             sceneMatrix [i][3] = MDistance::internalToUI ( sceneMatrix [i][3] );
1106 
1107         mVisualSceneNode->addMatrix ( ATTR_TRANSFORM, sceneMatrix );
1108 
1109         // For animations, sampling is always enforced for baked transforms.
1110         MPlug plug = MFnDagNode ( mTransformObject ).findPlug ( ATTR_MATRIX );
1111         mDocumentExporter->getAnimationCache()->cachePlug ( plug, true );
1112 
1113 		MEulerRotation rotation;
1114 		rotation.order = (MEulerRotation::RotationOrder) ((int)mTransformMatrix.rotationOrder() - MTransformationMatrix::kXYZ + MEulerRotation::kXYZ);
1115 
1116         // Export the animations
1117         AnimationExporter* animationExporter = mDocumentExporter->getAnimationExporter();
1118 		animationExporter->addPlugAnimation(plug, ATTR_TRANSFORM, kMatrix, rotation.order, TRANSFORM_PARAMETER, true );
1119     }
1120 
1121     //---------------------------------------------------------------
exportLookatTransform()1122     void VisualSceneExporter::exportLookatTransform()
1123     {
1124         // Compute local space parameters and export them. These parameters are:
1125         // - Eye position
1126         // - Interest point
1127         // - Up-axis direction
1128         //
1129         // TODO: camera animations for look-at transform are not implemented yet.
1130         //
1131 
1132         // attach the function set to the object
1133         MFnTransform transformFunctionSet ( mTransformObject );
1134 
1135         // Locate the camera in the dagPath
1136         MObject cameraObject ( MObject::kNullObj );
1137         uint pathChildCount = transformFunctionSet.childCount();
1138         for ( uint i = 0; i < pathChildCount; ++i )
1139         {
1140             MObject child = transformFunctionSet.child ( i );
1141             if ( child.hasFn ( MFn::kCamera ) )
1142             {
1143                 cameraObject = child;
1144                 break;
1145             }
1146         }
1147 
1148         if ( cameraObject == MObject::kNullObj )
1149         {
1150             // Revert to using decomposed transforms.
1151             exportDecomposedTransform();
1152         }
1153         else
1154         {
1155             // Positioning and orienting a camera or object in the scene is often
1156             // complicated when using a matrix. A lookat transform is an intuitive
1157             // way to specify an eye position, interest point, and orientation.
1158 
1159             // Get the camera matrix from which the other parameters are computed.
1160             MFnCamera camera ( cameraObject );
1161             MMatrix matrix = transformFunctionSet.transformationMatrix();
1162             matrix.homogenize();
1163 
1164             // Get the position of the camera in local space.
1165             MVector eye(matrix[3][0], matrix[3][1], matrix[3][2]);
1166             float eyePosition[3] = {
1167                 COLLADABU::Math::Utils::equalsZero( matrix[3][0], getTolerance () ) ? 0.0f : (float) matrix[3][0],
1168                 COLLADABU::Math::Utils::equalsZero( matrix[3][1], getTolerance () ) ? 0.0f : (float) matrix[3][1],
1169                 COLLADABU::Math::Utils::equalsZero( matrix[3][2], getTolerance () ) ? 0.0f : (float) matrix[3][2] };
1170 
1171             // Compute center of interest.
1172             double centerOfInterestDistance = camera.centerOfInterestPoint ( MSpace::kObject ).z;
1173             MVector front ( matrix[2][0], matrix[2][1], matrix[2][2] );
1174             MVector centerOfInterest = eye + ( front * centerOfInterestDistance );
1175             float interestPosition[3] = {
1176                 COLLADABU::Math::Utils::equalsZero( centerOfInterest.x, getTolerance () ) ? 0.0f : (float) centerOfInterest.x,
1177                 COLLADABU::Math::Utils::equalsZero( centerOfInterest.y, getTolerance () ) ? 0.0f : (float) centerOfInterest.y,
1178                 COLLADABU::Math::Utils::equalsZero( centerOfInterest.z, getTolerance () ) ? 0.0f : (float) centerOfInterest.z };
1179 
1180             // Extract the up direction, which corresponds to the second row.
1181             float upPosition[3] = {
1182                 COLLADABU::Math::Utils::equalsZero( matrix[1][0], getTolerance () ) ? 0.0f : (float) matrix[1][0],
1183                 COLLADABU::Math::Utils::equalsZero( matrix[1][1], getTolerance () ) ? 0.0f : (float) matrix[1][1],
1184                 COLLADABU::Math::Utils::equalsZero( matrix[1][2], getTolerance () ) ? 0.0f : (float) matrix[1][2] };
1185 
1186             // Add the camera lookat
1187             mVisualSceneNode->addLookat ( eyePosition, interestPosition, upPosition );
1188         }
1189     }
1190 
1191     //---------------------------------------------------------------
exportVisibility(COLLADASW::Node * sceneNode)1192     void VisualSceneExporter::exportVisibility ( COLLADASW::Node* sceneNode )
1193     {
1194         bool isVisible;
1195 
1196         if ( mTransformObject != MObject::kNullObj )
1197         {
1198             // Get the visibility value, if it exist
1199             if ( DagHelper::getPlugValue ( mTransformObject, ATTR_VISIBILITY, isVisible ) )
1200             {
1201                 AnimationSampleCache* animationCache = mDocumentExporter->getAnimationCache();
1202                 AnimationResult animationResult;
1203                 animationResult = AnimationHelper::isAnimated( animationCache, mTransformObject, ATTR_VISIBILITY );
1204 
1205                 // Write out the visibility of this node, if it is not visible or if it is animated.
1206                 if ( !isVisible || animationResult != kISANIM_None )
1207                 {
1208                     // Add an <extra> node with a visibility parameters that the animation can target
1209                     sceneNode->addExtraTechniqueParameter ( PROFILE_MAYA, ATTR_VISIBILITY, isVisible );
1210 
1211                     AnimationExporter* animationExporter = mDocumentExporter->getAnimationExporter();
1212                     animationExporter->addNodeAnimation ( mTransformObject, ATTR_VISIBILITY, kBoolean );
1213                 }
1214             }
1215         }
1216     }
1217 
1218 	//---------------------------------------------------------------
exportExtraAttributes(const SceneElement * sceneElement)1219 	void VisualSceneExporter::exportExtraAttributes(const SceneElement* sceneElement)
1220 	{
1221 		class ExtraAttributeExporter : public AttributeParser
1222 		{
1223 		public:
1224             ExtraAttributeExporter(COLLADASW::Node & visualSceneNode)
1225                 : mVisualSceneNode(visualSceneNode)
1226 			{}
1227 
1228 		private:
1229 			COLLADASW::Node & mVisualSceneNode;
1230 
1231 		protected:
1232 			virtual bool onBeforePlug(MPlug & plug) override
1233 			{
1234 				MStatus status;
1235 
1236 				MObject attr = plug.attribute(&status);
1237 				if (!status) return false;
1238 
1239 				MFnAttribute fnAttr(attr, &status);
1240 				if (!status) return false;
1241 
1242 				MString attrName = fnAttr.name(&status);
1243 				if (!status) return false;
1244 
1245 				bool isDynamic = fnAttr.isDynamic(&status);
1246 				if (!status) return false;
1247 
1248 				if (!isDynamic)
1249 					return false;
1250 
1251 				bool isHidden = fnAttr.isHidden(&status);
1252 				if (!status) return false;
1253 
1254 				if (isHidden)
1255 					return false;
1256 
1257 				return true;
1258 			}
1259 
1260             virtual void onBoolean(MPlug & plug, const MString & name, bool value) override
1261 			{
1262 				mVisualSceneNode.addExtraTechniqueParameter(PROFILE_MAYA, name.asChar(), value, "", COLLADASW::CSWC::CSW_ELEMENT_PARAM);
1263 			}
1264 
1265             virtual void onInteger(MPlug & plug, const MString & name, int value) override
1266 			{
1267 				mVisualSceneNode.addExtraTechniqueParameter(PROFILE_MAYA, name.asChar(), value, "", COLLADASW::CSWC::CSW_ELEMENT_PARAM);
1268 			}
1269 
1270             virtual void onInteger2(MPlug & plug, const MString & name, int value[2]) override
1271 			{
1272 				mVisualSceneNode.addExtraTechniqueParameter(PROFILE_MAYA, name.asChar(), value[0], value[1], "", COLLADASW::CSWC::CSW_ELEMENT_PARAM);
1273 			}
1274 
1275             virtual void onInteger3(MPlug & plug, const MString & name, int value[3]) override
1276 			{
1277 				mVisualSceneNode.addExtraTechniqueParameter(PROFILE_MAYA, name.asChar(), value[0], value[1], value[2], "", COLLADASW::CSWC::CSW_ELEMENT_PARAM);
1278 			}
1279 
1280             virtual void onFloat(MPlug & plug, const MString & name, float value) override
1281 			{
1282 				mVisualSceneNode.addExtraTechniqueParameter(PROFILE_MAYA, name.asChar(), value, "", COLLADASW::CSWC::CSW_ELEMENT_PARAM);
1283 			}
1284 
1285             virtual void onFloat2(MPlug & plug, const MString & name, float value[2]) override
1286 			{
1287 				mVisualSceneNode.addExtraTechniqueParameter(PROFILE_MAYA, name.asChar(), value[0], value[1], "", COLLADASW::CSWC::CSW_ELEMENT_PARAM);
1288 			}
1289 
1290             virtual void onFloat3(MPlug & plug, const MString & name, float value[3]) override
1291 			{
1292 				mVisualSceneNode.addExtraTechniqueParameter(PROFILE_MAYA, name.asChar(), value[0], value[1], value[2], "", COLLADASW::CSWC::CSW_ELEMENT_PARAM);
1293 			}
1294 
1295             virtual void onDouble(MPlug & plug, const MString & name, double value) override
1296 			{
1297 				mVisualSceneNode.addExtraTechniqueParameter(PROFILE_MAYA, name.asChar(), value, "", COLLADASW::CSWC::CSW_ELEMENT_PARAM);
1298 			}
1299 
1300             virtual void onDouble2(MPlug & plug, const MString & name, double value[2]) override
1301 			{
1302 				mVisualSceneNode.addExtraTechniqueParameter(PROFILE_MAYA, name.asChar(), value[0], value[1], "", COLLADASW::CSWC::CSW_ELEMENT_PARAM);
1303 			}
1304 
1305             virtual void onDouble3(MPlug & plug, const MString & name, double value[3]) override
1306 			{
1307 				mVisualSceneNode.addExtraTechniqueParameter(PROFILE_MAYA, name.asChar(), value[0], value[1], value[2], "", COLLADASW::CSWC::CSW_ELEMENT_PARAM);
1308 			}
1309 
1310             virtual void onDouble4(MPlug & plug, const MString & name, double value[4]) override
1311 			{
1312 				mVisualSceneNode.addExtraTechniqueParameter(PROFILE_MAYA, name.asChar(), value[0], value[1], value[2], value[3], "", COLLADASW::CSWC::CSW_ELEMENT_PARAM);
1313 			}
1314 
1315             virtual void onString(MPlug & plug, const MString & name, const MString & value) override
1316 			{
1317 				mVisualSceneNode.addExtraTechniqueParameter(PROFILE_MAYA, name.asChar(), COLLADABU::StringUtils::translateToXML(String(value.asChar())), "", COLLADASW::CSWC::CSW_ELEMENT_PARAM);
1318 			}
1319 
1320             virtual void onEnum(MPlug & plug, const MString & name, int enumValue, const MString & enumName) override
1321             {
1322                 // TODO export all possible enum values to be able to re-import them?
1323 				mVisualSceneNode.addExtraTechniqueEnumParameter(PROFILE_MAYA, name.asChar(), COLLADABU::StringUtils::translateToXML(String(enumName.asChar())), "", COLLADASW::CSWC::CSW_ELEMENT_PARAM);
1324             }
1325 		};
1326 
1327 		MObject nodeObject = sceneElement->getNode();
1328 
1329 		MStatus status;
1330 		MFnDependencyNode fnNode(nodeObject, &status);
1331 		if (!status) return;
1332 
1333         ExtraAttributeExporter extraAttributeExporter(*mVisualSceneNode);
1334 		AttributeParser::parseAttributes(fnNode, extraAttributeExporter);
1335 	}
1336 
1337     //---------------------------------------------------------------
exportInstanceController(SceneElement * sceneElement,const bool hasSkinController,const bool hasMorphController)1338     void VisualSceneExporter::exportInstanceController(
1339         SceneElement* sceneElement,
1340         const bool hasSkinController,
1341         const bool hasMorphController )
1342     {
1343         MObject childNode = sceneElement->getPath().node();
1344 
1345         // Get the streamWriter from the export document
1346         COLLADASW::StreamWriter* streamWriter = mDocumentExporter->getStreamWriter();
1347         ControllerExporter* controllerExporter = mDocumentExporter->getControllerExporter ();
1348 
1349         // Get the collada id.
1350 //         MDagPath dagPath = sceneElement->getPath();
1351 //         String mayaControllerId = mDocumentExporter->dagPathToColladaId ( dagPath );
1352         String mayaControllerId = sceneElement->getNodeName();
1353         if ( hasMorphController )
1354             mayaControllerId += COLLADASW::LibraryControllers::MORPH_CONTROLLER_ID_SUFFIX;
1355         if ( hasSkinController )
1356             mayaControllerId += COLLADASW::LibraryControllers::SKIN_CONTROLLER_ID_SUFFIX;
1357 
1358         String colladaId = controllerExporter->findColladaControllerId ( mayaControllerId );
1359 
1360         // TODO id preservation
1361         // Create the unique controller ID
1362 //         String colladaId;
1363 //         if ( !sceneElement->getNodeId().empty() )
1364 //             colladaId = sceneElement->getNodeId();
1365 //         else
1366 //           colladaId = sceneElement->getNodeName();
1367 //         if ( hasMorphController )
1368 //             colladaId += COLLADASW::LibraryControllers::MORPH_CONTROLLER_ID_SUFFIX;
1369 //         if ( hasSkinController )
1370 //             colladaId += COLLADASW::LibraryControllers::SKIN_CONTROLLER_ID_SUFFIX;
1371 
1372         // Get the uri of the current scene
1373 		COLLADASW::URI uri;
1374 		if (!ExportOptions::exportSeparateFile() || (ExportOptions::exportSeparateFile() && !ExportOptions::exportAnimationsOnly()))
1375 			uri = getSceneElementURI(sceneElement, colladaId);
1376 		else
1377 		{
1378 			String daeName = ExportOptions::getDAEmodelName().asChar();
1379 
1380 			MString exportedFile = mDocumentExporter->getFilename().c_str();
1381 
1382 			// Make referenced file path relative to exported file directory
1383 			COLLADASW::URI exportedFileURI = exportedFile.asChar();
1384 			COLLADASW::URI exportedFileDirURI = exportedFileURI.getPathDir();
1385 			exportedFileDirURI.setScheme(exportedFileURI.getScheme());
1386 
1387 			COLLADASW::URI referencedFileURI = MString(daeName.c_str()).asChar();
1388 			referencedFileURI.makeRelativeTo(exportedFileDirURI);
1389 
1390 			if (ExportOptions::exportAnimationsOnly() && daeName.compare("") != 0)
1391 			{
1392 				uri = URI(referencedFileURI.getURIString() + String("#") + colladaId);
1393 			}
1394 			else
1395 			{
1396 				MGlobal::displayWarning(MString("Please provide Model DAE path to not lose association between animation and a specific model "));
1397 				return;
1398 			}
1399 		}
1400 
1401         // Create the collada controller instance
1402         COLLADASW::InstanceController instanceController ( streamWriter );
1403         instanceController.setUrl ( uri );
1404 
1405         // Set the skeletonId. It indicates where a skin controller is to start to search for the
1406         // joint nodes it needs. This element is meaningless for morph controllers.
1407         const std::set<URI>& skeletonURIs = sceneElement->getSkeletonURIs ();
1408         if ( skeletonURIs.size () > 0 )
1409         {
1410             std::set<URI>::const_iterator it = skeletonURIs.begin ();
1411             while ( it != skeletonURIs.end () )
1412             {
1413                 instanceController.addSkeleton ( *it );
1414                 ++it;
1415             }
1416         }
1417 
1418         // Write all materials
1419         COLLADASW::InstanceMaterialList& instanceMaterialList =
1420             instanceController.getBindMaterial().getInstanceMaterialList();
1421 
1422         // Export the materials
1423         exportInstanceMaterial ( instanceMaterialList, sceneElement->getPath() );
1424 
1425         instanceController.add();
1426     }
1427 
1428     //---------------------------------------------------------------
exportInstanceGeometry(SceneElement * sceneElement)1429     void VisualSceneExporter::exportInstanceGeometry ( SceneElement* sceneElement )
1430     {
1431         // Get the current dag path
1432         MDagPath dagPath = sceneElement->getPath();
1433 
1434         // Get the collada mesh id.
1435         GeometryExporter* geometryExporter = mDocumentExporter->getGeometryExporter ();
1436         const String& colladaMeshId = geometryExporter->getColladaGeometryId ( dagPath );
1437         if ( colladaMeshId.empty () ) return;
1438 
1439         // Get the uri of the current scene
1440 		COLLADASW::URI uri(getSceneElementURI(sceneElement, colladaMeshId));
1441 
1442         // Get the streamWriter from the export document
1443         COLLADASW::StreamWriter* streamWriter = mDocumentExporter->getStreamWriter();
1444 
1445         // Write the geometry instance
1446         COLLADASW::InstanceGeometry instanceGeometry ( streamWriter );
1447         instanceGeometry.setUrl ( uri );
1448 
1449         // Write all materials
1450         COLLADASW::InstanceMaterialList& instanceMaterialList =
1451             instanceGeometry.getBindMaterial().getInstanceMaterialList();
1452 
1453         // Export the materials
1454         exportInstanceMaterial ( instanceMaterialList, sceneElement->getPath() );
1455 
1456         instanceGeometry.add();
1457     }
1458 
1459     //---------------------------------------------------------------
exportInstanceLightProbe(const SceneElement * sceneElement)1460     void VisualSceneExporter::exportInstanceLightProbe(const SceneElement* sceneElement)
1461     {
1462         // Get the collada light probe id.
1463         MDagPath dagPath = sceneElement->getPath();
1464         String mayaLightProbeId = mDocumentExporter->dagPathToColladaId ( dagPath );
1465         LightProbeExporter* lightProbeExporter = mDocumentExporter->getLightProbeExporter ();
1466         String colladaLightProbeId = lightProbeExporter->findColladaLightProbeId ( mayaLightProbeId );
1467 
1468         // Get the uri of the current scene
1469 		COLLADASW::URI uri(getSceneElementURI(sceneElement, colladaLightProbeId));
1470 
1471         // Create and write the light probe instance
1472         //COLLADASW::StreamWriter* streamWriter = mDocumentExporter->getStreamWriter();
1473         //COLLADASW::InstanceLightProbe instanceLightProbe ( streamWriter, uri );
1474         //instanceLightProbe.add();
1475 
1476 		mVisualSceneNode->addExtraTechniqueElement(COLLADAMaya::PROFILE_MAYA, COLLADAMaya::CSW_ELEMENT_INSTANCE_LIGHT_PROBE, COLLADASW::CSWC::CSW_ATTRIBUTE_URL, uri.getURIString());
1477     }
1478 
1479     //---------------------------------------------------------------
exportInstanceLight(const SceneElement * sceneElement)1480     void VisualSceneExporter::exportInstanceLight( const SceneElement* sceneElement )
1481     {
1482         // Get the collada light id.
1483         MDagPath dagPath = sceneElement->getPath();
1484         String mayaLightId = mDocumentExporter->dagPathToColladaId ( dagPath );
1485         LightExporter* lightExporter = mDocumentExporter->getLightExporter ();
1486         String colladaLightId = lightExporter->findColladaLightId ( mayaLightId );
1487 
1488         // Get the uri of the current scene
1489 		COLLADASW::URI uri(getSceneElementURI(sceneElement, colladaLightId));
1490 
1491         // Create and write the light instance
1492         COLLADASW::StreamWriter* streamWriter = mDocumentExporter->getStreamWriter();
1493         COLLADASW::InstanceLight instanceLight ( streamWriter, uri );
1494         instanceLight.add();
1495     }
1496 
1497     //---------------------------------------------------------------
exportInstanceCamera(const SceneElement * sceneElement)1498     void VisualSceneExporter::exportInstanceCamera( const SceneElement* sceneElement )
1499     {
1500         // Get the collada id.
1501         MDagPath dagPath = sceneElement->getPath();
1502         String mayaId = mDocumentExporter->dagPathToColladaId ( dagPath );
1503         CameraExporter* cameraExporter = mDocumentExporter->getCameraExporter ();
1504         String colladaId = cameraExporter->findColladaCameraId ( mayaId );
1505 
1506         // Get the uri of the current scene
1507 		COLLADASW::URI uri(getSceneElementURI(sceneElement, colladaId));
1508 
1509         // Create and write the camera instance
1510         COLLADASW::StreamWriter* streamWriter = mDocumentExporter->getStreamWriter();
1511         COLLADASW::InstanceCamera instanceCamera ( streamWriter, uri );
1512         instanceCamera.add();
1513     }
1514 
1515     //---------------------------------------------------------------
exportInstanceNode(SceneElement * sceneElement)1516     void VisualSceneExporter::exportInstanceNode ( SceneElement* sceneElement )
1517     {
1518         // Get the collada id.
1519         String mayaNodeId = sceneElement->getNodeId();
1520 		if (mayaNodeId.empty())
1521 		{
1522 			mayaNodeId = mVisualSceneNode->getNodeId();
1523 		}
1524         if ( mayaNodeId.empty() )
1525             mayaNodeId = sceneElement->getNodeName();
1526         String colladaNodeId = findColladaNodeId ( mayaNodeId );
1527 
1528         // Get the uri of the current scene
1529         COLLADASW::URI uri ( getSceneElementURI ( sceneElement, colladaNodeId ) );
1530 
1531         // Create and write the camera instance
1532         COLLADASW::StreamWriter* streamWriter = mDocumentExporter->getStreamWriter();
1533         COLLADASW::InstanceNode instanceNode ( streamWriter, uri );
1534 
1535 		// Add Proxy to Next LOD Node (during Library Node second Pass)
1536 		// Or during Visual Scene Pass only for element inside LOD Group
1537 		if ((mDocumentExporter->mExportPass == SECOND_LOD_PASS) ||
1538 			(ExportOptions::exportLOD() && mDocumentExporter->mExportPass == VISUAL_SCENE_PASS && (sceneElement->getParentCount()>0 && sceneElement->getParent()->getType() == SceneElement::LOD)))
1539 		{
1540 			int indexLOD;
1541 
1542 			SceneElement* element;
1543 
1544 			if (mDocumentExporter->mExportPass == VISUAL_SCENE_PASS)
1545 				element = sceneElement->getParent();
1546 			else
1547 				element = sceneElement;
1548 
1549 			String proxy = findNextColladaNodeId(element, indexLOD);
1550 			if (proxy.compare(EMPTY_STRING) != 0)
1551 			{
1552 				String prefix = "LOD__";
1553 				SceneElement* parent = sceneElement->getParent();
1554 
1555 				if (indexLOD == parent->getChildCount() - 2)
1556 					prefix = "";
1557 
1558 
1559 				const String url = "#" + prefix + proxy;
1560 				instanceNode.addExtraTechniqueParentElement(PROFILE_MAYA, PARAMETER_PROXY, "url", url);
1561 
1562 				const String threshold = String(ATTR_THRESHOLD);
1563 				instanceNode.addExtraTechniqueChildElement(PROFILE_MAYA, PARAMETER_PROXY, threshold, GetThresholdPlugValue(element, indexLOD));
1564 			}
1565 
1566 			if (mDocumentExporter->mExportPass == VISUAL_SCENE_PASS)
1567 				instanceNode.addExtraTechnique();		// Only Add Extra, Instance node has been added before
1568 			else
1569 				instanceNode.add();	// Add Instance Node with proxy if != EMPTY_STRING, Add extra too
1570 		}
1571 		else
1572 			instanceNode.add();
1573     }
1574 
1575     //---------------------------------------------------------------
getSceneElementURI(const SceneElement * sceneElement,const String & elementId)1576     COLLADASW::URI VisualSceneExporter::getSceneElementURI (
1577         const SceneElement* sceneElement,
1578         const String& elementId /** = EMPTY_STRING */)
1579     {
1580 		return getSceneElementURI(sceneElement->getPath(), elementId);
1581     }
1582 
1583     //---------------------------------------------------------------
getSceneElementURI(const MDagPath & dagPath,const String & id)1584 	COLLADASW::URI VisualSceneExporter::getSceneElementURI(const MDagPath& dagPath, const String& id /*= EMPTY_STRING*/)
1585     {
1586         MFnDagNode dagFn(dagPath);
1587         bool isLocal = !dagFn.isFromReferencedFile();
1588 		if (ExportOptions::exportXRefs() && ExportOptions::dereferenceXRefs()) {
1589             isLocal = true;
1590         }
1591 
1592         // Get the Uri of the element.
1593         if (!isLocal)
1594         {
1595             MObject referenceNode;
1596             MStatus status = ReferenceManager::getTopLevelReferenceNode(dagPath, referenceNode);
1597             if (status == MS::kFailure) {
1598                 return COLLADASW::URI();
1599             }
1600 
1601             MString mayaReferenceFilename;
1602             status = ReferenceManager::getReferenceFilename(referenceNode, mayaReferenceFilename);
1603 
1604             String referenceFilename = mayaReferenceFilename.asChar();
1605 
1606             // Replace .mb by .dae
1607             String::size_type dotPos = referenceFilename.rfind('.');
1608             if (dotPos != String::npos) {
1609                 referenceFilename.resize(dotPos);
1610                 referenceFilename.append(".dae");
1611             }
1612             MString exportedFile = MFileIO::currentFile();
1613 
1614             // Make referenced file path relative to exported file directory
1615             COLLADASW::URI exportedFileURI = exportedFile.asChar();
1616             COLLADASW::URI exportedFileDirURI = exportedFileURI.getPathDir();
1617             exportedFileDirURI.setScheme(exportedFileURI.getScheme());
1618             COLLADASW::URI referencedFileURI = referenceFilename;
1619             if (ExportOptions::relativePaths())
1620             {
1621                 referencedFileURI.makeRelativeTo(exportedFileDirURI);
1622             }
1623 
1624             COLLADASW::URI sceneElementURI(referencedFileURI);
1625             const bool removeFirstNamespace = true;
1626             String refNodeId = getColladaNodeId(dagPath, removeFirstNamespace);
1627             sceneElementURI.setFragment(refNodeId);
1628             return sceneElementURI;
1629         }
1630         else
1631         {
1632             // Get the id of the element
1633             if (!id.empty()) {
1634                 return COLLADASW::URI(EMPTY_STRING, id);
1635             }
1636             else {
1637                 return COLLADASW::URI(EMPTY_STRING, mDocumentExporter->dagPathToColladaId(dagPath));
1638             }
1639         }
1640     }
1641 
1642     //---------------------------------------------------------------
exportInstanceChildNodes(const SceneElement * sceneElement)1643     void VisualSceneExporter::exportInstanceChildNodes( const SceneElement* sceneElement )
1644     {
1645         // Check the geometry instances, which use this visual scene
1646         size_t childCount = sceneElement->getChildCount();
1647         for ( size_t i=0; i<childCount; ++i )
1648         {
1649             SceneElement* childElement = sceneElement->getChild ( i );
1650 
1651             // Just export visible export nodes.
1652             if ( !childElement->getIsExportNode() ) continue;
1653             if ( !ExportOptions::exportInvisibleNodes () && !childElement->getIsVisible () ) continue;
1654 
1655             bool exportGeometry = true;
1656             bool physicsExportNode = false;
1657 
1658             const MObject& transformNode = sceneElement->getPath().transform();
1659             DagHelper::getPlugValue(transformNode, ATTR_COLLISION_EXPORT_NODE, physicsExportNode);
1660 
1661             int shape;
1662             if (DagHelper::getPlugValue(transformNode, ATTR_COLLISION_SHAPE, shape) && !physicsExportNode)
1663             {
1664                 if (shape == PhysicsExporter::Box ||
1665                     shape == PhysicsExporter::Capsule)
1666                     exportGeometry = false;
1667             }
1668 
1669             // Check if the child element is a mesh object and an export node
1670             if ( childElement->getType() == SceneElement::MESH && exportGeometry)
1671             {
1672                 // Get the controller library
1673                 ControllerExporter* controller = mDocumentExporter->getControllerExporter();
1674                 MObject childNode = childElement->getPath().node();
1675 
1676                 bool hasSkinController = controller->hasSkinController ( childNode );
1677                 bool hasMorphController = controller->hasMorphController ( childNode );
1678 
1679                 // Check for controllers, otherwise instantiate the geometry.
1680                 // Add the controller and/or geometry to our libraries
1681 				if ((ExportOptions::exportJoints() && hasSkinController) || hasMorphController)
1682                 {
1683 					if (ExportOptions::exportSkin() || ExportOptions::exportSeparateFile())
1684 	                    exportInstanceController ( childElement, hasSkinController, hasMorphController );
1685                 }
1686                 else
1687                 {
1688                     exportInstanceGeometry ( childElement );
1689                 }
1690             }
1691             else if (childElement->getType() == SceneElement::LIGHT_PROBE &&
1692                 childElement->getIsExportNode())
1693             {
1694                 exportInstanceLightProbe(childElement);
1695             }
1696             else if ( childElement->getType() == SceneElement::LIGHT &&
1697                 childElement->getIsExportNode() &&
1698                 ExportOptions::exportLights())
1699             {
1700                 exportInstanceLight ( childElement );
1701             }
1702             else if ( childElement->getType() == SceneElement::CAMERA &&
1703                 childElement->getIsExportNode() &&
1704                 ExportOptions::exportCameras())
1705             {
1706                 exportInstanceCamera ( childElement );
1707             }
1708         }
1709     }
1710 
1711     // ------------------------------------
findColladaNodeId(const String & mayaNodeId)1712     const String VisualSceneExporter::findColladaNodeId ( const String& mayaNodeId )
1713     {
1714         const StringToStringMap::const_iterator it = mMayaIdColladaNodeId.find ( mayaNodeId );
1715         if ( it != mMayaIdColladaNodeId.end () )
1716         {
1717             return it->second;
1718         }
1719         return EMPTY_STRING;
1720     }
1721 
findNextColladaNodeId(const SceneElement * sceneElement,int & indexLOD)1722 	const String VisualSceneExporter::findNextColladaNodeId(const SceneElement* sceneElement, int& indexLOD)
1723 	{
1724 		MDagPath dag;
1725 		int index = 0;
1726 		indexLOD = index;
1727 
1728 		if (mDocumentExporter->mExportPass == VISUAL_SCENE_PASS)
1729 			dag = sceneElement->getChild(1)->getPath();
1730 		else
1731 		{
1732 			SceneElement* parent = sceneElement->getParent();
1733 
1734 			bool found = false;
1735 			for (index = 0; index < parent->getChildCount(); index++)
1736 			{
1737 				if (parent->getChild(index)->getPath() == sceneElement->getPath())
1738 				{
1739 					found = true;
1740 					break;
1741 				}
1742 			}
1743 
1744 			if (!found)
1745 				return EMPTY_STRING;
1746 
1747 			if (index + 1 >= parent->getChildCount())
1748 				return EMPTY_STRING;
1749 			else
1750 				dag = parent->getChild(index + 1)->getPath();
1751 		}
1752 
1753 		indexLOD = index;
1754 
1755 		String mayaNodeId = mDocumentExporter->dagPathToColladaId(dag);
1756 
1757 		const StringToStringMap::iterator it = mMayaIdColladaNodeId.find(mayaNodeId);
1758 
1759 		if (it != mMayaIdColladaNodeId.end())
1760 		{
1761 			return it->second;
1762 		}
1763 		return EMPTY_STRING;
1764 	}
1765 
1766     // ------------------------------------
getColladaNodeId(const MDagPath & dagPath,bool removeFirstNamespace)1767     COLLADAMaya::String VisualSceneExporter::getColladaNodeId (
1768         const MDagPath &dagPath,
1769 		bool removeFirstNamespace)
1770     {
1771         String colladaNodeId;
1772 
1773         // Check if there is an extra attribute "colladaId" and use this as export id.
1774         MString attributeValue;
1775         DagHelper::getPlugValue ( dagPath.node (), COLLADA_ID_ATTRIBUTE_NAME, attributeValue );
1776         if ( attributeValue != EMPTY_CSTRING )
1777         {
1778             // Generate a valid collada name, if necessary.
1779             colladaNodeId = mDocumentExporter->mayaNameToColladaName ( attributeValue, false, removeFirstNamespace );
1780         }
1781         else
1782         {
1783             // Generate a COLLADA id for the new object
1784             //colladaNodeId = mDocumentExporter->mayaNameToColladaName ( node.name ().asChar () );
1785             colladaNodeId = mDocumentExporter->dagPathToColladaId ( dagPath, removeFirstNamespace );
1786         }
1787 
1788         return colladaNodeId;
1789     }
1790 
ResetLODCounter()1791 	void VisualSceneExporter::ResetLODCounter()
1792 	{
1793 		mLODIndexCounter2 = 0;
1794 	}
1795 }
1796