~ubuntu-branches/ubuntu/wily/opencollada/wily-proposed

« back to all changes in this revision

Viewing changes to COLLADAMaya/src/COLLADAMayaControllerExporter.cpp

  • Committer: Package Import Robot
  • Author(s): Matteo F. Vescovi
  • Date: 2015-05-14 17:23:27 UTC
  • Revision ID: package-import@ubuntu.com-20150514172327-f862u8envms01fra
Tags: upstream-0.1.0~20140703.ddf8f47+dfsg1
ImportĀ upstreamĀ versionĀ 0.1.0~20140703.ddf8f47+dfsg1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "COLLADAMayaControllerExporter.h"
 
18
#include "COLLADAMayaDagHelper.h"
 
19
#include "COLLADAMayaShaderHelper.h"
 
20
#include "COLLADAMayaSceneGraph.h"
 
21
#include "COLLADAMayaSyntax.h"
 
22
#include "COLLADAMayaExportOptions.h"
 
23
#include "COLLADAMayaGeometryExporter.h"
 
24
#include "COLLADAMayaConversion.h"
 
25
#include "COLLADAMayaAnimationTools.h"
 
26
#include "COLLADAMayaAnimationExporter.h"
 
27
#include "COLLADAMayaVisualSceneExporter.h"
 
28
 
 
29
#include <assert.h>
 
30
 
 
31
#include "Math/COLLADABUMathUtils.h"
 
32
 
 
33
#include "COLLADASWBaseInputElement.h"
 
34
#include "COLLADASWExtra.h"
 
35
 
 
36
#include <maya/MItDependencyGraph.h>
 
37
#include <maya/MFnDagNode.h>
 
38
#include <maya/MFnTransform.h>
 
39
#include <maya/MFnSkinCluster.h>
 
40
#include <maya/MItGeometry.h>
 
41
#include <maya/MFnWeightGeometryFilter.h>
 
42
#include <maya/MFnPointArrayData.h>
 
43
#include <maya/MFnBlendShapeDeformer.h>
 
44
#include <maya/MFnComponentListData.h>
 
45
 
 
46
 
 
47
namespace COLLADAMaya
 
48
{
 
49
 
 
50
    const String ControllerExporter::PARAM_TYPE_TRANSFORM    = "TRANSFORM";
 
51
    const String ControllerExporter::PARAM_TYPE_JOINT        = "JOINT";
 
52
    const String ControllerExporter::PARAM_TYPE_MORPH_TARGET = "MORPH_TARGET";
 
53
    const String ControllerExporter::PARAM_TYPE_MORPH_WEIGHT = "MORPH_WEIGHT";
 
54
    const String ControllerExporter::PARAM_TYPE_WEIGHT       = "WEIGHT";
 
55
 
 
56
    //------------------------------------------------------
 
57
    ControllerExporter::ControllerExporter ( COLLADASW::StreamWriter* streamWriter,
 
58
                                           DocumentExporter* documentExporter )
 
59
    : COLLADASW::LibraryControllers ( streamWriter )
 
60
    , mDocumentExporter ( documentExporter )
 
61
    , mExportedControllers ( NULL )
 
62
    {}
 
63
 
 
64
    //------------------------------------------------------
 
65
    ControllerExporter::~ControllerExporter()
 
66
    {
 
67
    }
 
68
 
 
69
    //------------------------------------------------------
 
70
    void ControllerExporter::exportControllers()
 
71
    {
 
72
        // Get the list with the transform nodes.
 
73
        SceneGraph* sceneGraph = mDocumentExporter->getSceneGraph();
 
74
        SceneElementsList* exportNodesTree = sceneGraph->getExportNodesTree();
 
75
 
 
76
        // Export all/selected DAG nodes
 
77
        size_t length = exportNodesTree->size();
 
78
        for ( size_t i=0; i<length; ++i )
 
79
        {
 
80
            SceneElement* sceneElement = ( *exportNodesTree ) [i];
 
81
            exportControllers ( sceneElement );
 
82
        }
 
83
 
 
84
        closeLibrary();
 
85
    }
 
86
 
 
87
    //------------------------------------------------------
 
88
    void ControllerExporter::exportControllers( SceneElement* sceneElement )
 
89
    {
 
90
        // If we have a external reference, we don't need to export the data here.
 
91
        if ( !sceneElement->getIsLocal() ) return;
 
92
        if ( !sceneElement->getIsExportNode () ) return;
 
93
 
 
94
        // Check if it is a mesh and an export node
 
95
        SceneElement::Type sceneElementType = sceneElement->getType();
 
96
        if ( sceneElementType == SceneElement::MESH )
 
97
        {
 
98
            // Get the current dag path
 
99
            MDagPath dagPath = sceneElement->getPath();
 
100
            String pathName = dagPath.fullPathName ().asChar ();
 
101
 
 
102
            // Check if the current scene element isn't already exported.
 
103
            if ( findExportedContollerSceneElement ( sceneElement ) ) return;
 
104
 
 
105
            // Check if the current element is an instance. 
 
106
            // We don't need to export instances, because we export the original instanced element.
 
107
            bool isInstance = ( dagPath.isInstanced() && dagPath.instanceNumber() > 0 );
 
108
 
 
109
            // If the original instanced element isn't already exported, we have to export it now.
 
110
            if ( isInstance )
 
111
            {
 
112
                // Get the original instanced element.
 
113
                MDagPath instancedPath;
 
114
                dagPath.getPath ( instancedPath, 0 );
 
115
                SceneGraph* sceneGraph = mDocumentExporter->getSceneGraph();
 
116
                SceneElement* instancedSceneElement = sceneGraph->findElement ( instancedPath );
 
117
 
 
118
                // Check if the controller of the original instanced element is already exported.
 
119
                std::vector<SceneElement*>::const_iterator controllerIter;
 
120
                controllerIter = find ( mExportedControllerSceneElements.begin (), mExportedControllerSceneElements.end (), instancedSceneElement );
 
121
                if ( controllerIter == mExportedControllerSceneElements.end () )
 
122
                {
 
123
                    // Create a skin/morph transform object and export the controller for the 
 
124
                    // the original instanced element.
 
125
                    if ( exportController ( instancedSceneElement ) )
 
126
                    {
 
127
                        // Push the scene element in the list of exported controller elements.
 
128
                        mExportedControllerSceneElements.push_back ( instancedSceneElement );
 
129
                    }
 
130
                }
 
131
            }
 
132
            else
 
133
            {
 
134
                // Create a skin/morph transform object and export the controller.
 
135
                if ( exportController ( sceneElement ) )
 
136
                {
 
137
                    // Push the scene element in the list of exported controller elements.
 
138
                    mExportedControllerSceneElements.push_back ( sceneElement );
 
139
                }
 
140
            }
 
141
        }
 
142
 
 
143
        // Recursive call for all the child elements
 
144
        for ( uint i=0; i<sceneElement->getChildCount(); ++i )
 
145
        {
 
146
            SceneElement* childElement = sceneElement->getChild ( i );
 
147
            exportControllers ( childElement );
 
148
        }
 
149
    }
 
150
 
 
151
    //------------------------------------------------------
 
152
    bool ControllerExporter::exportController( SceneElement* sceneElement )
 
153
    {
 
154
        // Get the current dag path
 
155
        MDagPath dagPath = sceneElement->getPath();
 
156
 
 
157
        // Get the current mesh node.
 
158
        MObject meshNode = dagPath.node();
 
159
 
 
160
        // The stacks of the controllers for the affected nodes.
 
161
        ControllerStack stack;
 
162
        ControllerMeshStack meshStack;
 
163
 
 
164
        // Iterate upstream finding all the nodes which affect the mesh.
 
165
        if ( !findAffectedNodes ( meshNode, stack, meshStack ) )
 
166
        {
 
167
            return false;
 
168
        }
 
169
 
 
170
        // Disable any effects on the nodes.
 
171
        setControllerNodeStatesToNoEffect ( stack );
 
172
        // Set all meshes as visible and not intermediate.
 
173
        setValidMeshParameters ( meshStack );
 
174
 
 
175
        // Exports all the mesh affected nodes in the controller stack.
 
176
        exportControllerStack ( sceneElement, stack );
 
177
 
 
178
        // Reset the intermediate and visibility mesh parameters.
 
179
        resetMeshParameters ( meshStack );
 
180
        // Reset the controller node states.
 
181
        resetControllerNodeStates ( stack );
 
182
        // Delete the controller stack items and clear the stack.
 
183
        deleteControllerStackItems ( stack );
 
184
 
 
185
        return true;
 
186
    }
 
187
 
 
188
    //------------------------------------------------------
 
189
    void ControllerExporter::exportControllerStack(
 
190
        SceneElement *sceneElement,
 
191
        const ControllerStack &stack )
 
192
    {
 
193
        // Get the current path and the mesh node.
 
194
        MDagPath dagPath = sceneElement->getPath();
 
195
        MObject meshNode = dagPath.node();
 
196
 
 
197
        // We cannot express more than one skin per geometry instance...
 
198
        bool alreadyHasSkin = false;
 
199
 
 
200
        // Export the controller stack
 
201
        for ( intptr_t i=stack.size()-1; i>=0; --i )
 
202
        {
 
203
            ControllerStackItem* item = stack[i];
 
204
            if ( item->isSkin )
 
205
            {
 
206
                if ( ExportOptions::exportJointsAndSkin() && !alreadyHasSkin )
 
207
                {
 
208
                    // Correctly avoid chained joint-clusters: only export the first
 
209
                    // joint cluster which exports the subsequent joint-clusters with it.
 
210
                    MObject skinControllerNode = item->skinControllerNode;
 
211
                    if ( !skinControllerNode.hasFn ( MFn::kJointCluster ) ||
 
212
                        i == 0 ||
 
213
                        !stack[i-1]->isSkin ||
 
214
                        !stack[i-1]->skinControllerNode.hasFn ( MFn::kJointCluster ) )
 
215
                    {
 
216
                        exportSkinController ( sceneElement, skinControllerNode, MDagPath::getAPathTo( meshNode ) );
 
217
                        alreadyHasSkin = true;
 
218
                    }
 
219
                }
 
220
            }
 
221
            else
 
222
            {
 
223
                exportMorphController( sceneElement, item->morphControllerNodes );
 
224
            }
 
225
        }
 
226
    }
 
227
 
 
228
    //------------------------------------------------------
 
229
    void ControllerExporter::exportMorphController(
 
230
        SceneElement* sceneElement,
 
231
        MObjectArray& controllerNodes )
 
232
    {
 
233
        // Count the blendShape nodes.
 
234
        uint controllerNodeCount = controllerNodes.length();
 
235
        if ( controllerNodeCount == 0 ) return;        
 
236
 
 
237
        // Get the maya controller name
 
238
        String mayaControllerId = sceneElement->getNodeName() +
 
239
            COLLADASW::LibraryControllers::MORPH_CONTROLLER_ID_SUFFIX;
 
240
 
 
241
        MObject blendShapeNode = controllerNodes[0];
 
242
//         String mayaControllerId = MFnDependencyNode( blendShapeNode ).name().asChar();
 
243
 
 
244
        // Check if the controller isn't already exported
 
245
        if ( !findColladaControllerId ( mayaControllerId ).empty () ) return;
 
246
 
 
247
        // Generate a COLLADA id for the new object
 
248
        String colladaControllerId;
 
249
 
 
250
        // Check if there is an extra attribute "colladaId" and use this as export id.
 
251
        MString attributeValue;
 
252
        DagHelper::getPlugValue ( blendShapeNode, COLLADA_ID_ATTRIBUTE_NAME, attributeValue );
 
253
        if ( attributeValue != EMPTY_CSTRING )
 
254
        {
 
255
            // Generate a valid collada name, if necessary.
 
256
            colladaControllerId = mDocumentExporter->mayaNameToColladaName ( attributeValue, false );
 
257
        }
 
258
        else
 
259
        {
 
260
//             colladaControllerId = mDocumentExporter->dagPathToColladaId ( sceneElement->getPath () ) +
 
261
//                 COLLADASW::LibraryControllers::MORPH_CONTROLLER_ID_SUFFIX;
 
262
            colladaControllerId = sceneElement->getNodeName() +
 
263
                COLLADASW::LibraryControllers::MORPH_CONTROLLER_ID_SUFFIX;
 
264
 
 
265
        }
 
266
 
 
267
        // Make the id unique and store it in a map.
 
268
        colladaControllerId = mControllerIdList.addId ( colladaControllerId );
 
269
        mMayaIdColladaIdMap [ mayaControllerId ] = colladaControllerId;
 
270
 
 
271
        // Create a morph controller to hold the data
 
272
        MorphController morphController( colladaControllerId, mayaControllerId );
 
273
 
 
274
        MorphControllerTargets& blendTargets = morphController.getMorphControllerTargets();
 
275
        std::vector<float>& blendWeights = morphController.getMorphControllerWeights();
 
276
        std::vector<MPlug> weightPlugs;
 
277
 
 
278
        // Retrieve the target informations of the blend shape
 
279
        for (uint i = 0; i < controllerNodeCount; ++i)
 
280
        {
 
281
            MObject controllerNode = controllerNodes[i];
 
282
            MFnDependencyNode controllerFn ( controllerNode );
 
283
 
 
284
            MPlug inputTargetArrayPlug = controllerFn.findPlug( ATTR_INPUT_TARGET ); // "inputTarget"
 
285
            if ( inputTargetArrayPlug.attribute().isNull() ) continue;
 
286
 
 
287
            MPlug weightArrayPlug = controllerFn.findPlug( ATTR_WEIGHT ); // "weight"
 
288
            uint nextIndex = 0;
 
289
 
 
290
            uint inputTargetCount = inputTargetArrayPlug.numElements();
 
291
            for (uint j = 0; j < inputTargetCount; ++j)
 
292
            {
 
293
                MPlug inputTargetPlug = inputTargetArrayPlug.elementByPhysicalIndex(j);
 
294
                if ( inputTargetPlug.attribute().isNull() ) continue;
 
295
 
 
296
                MPlug inputTargetGroupArrayPlug = DagHelper::getChildPlug( inputTargetPlug, ATTR_INPUT_TARGET_GROUP ); // "inputTargetGroup"
 
297
                if ( inputTargetGroupArrayPlug.attribute().isNull() ) continue;
 
298
 
 
299
                uint inputTargetGroupCount = inputTargetGroupArrayPlug.numElements();
 
300
                for (uint k = 0; k < inputTargetGroupCount; ++k)
 
301
                {
 
302
                    MPlug inputTargetGroupPlug = inputTargetGroupArrayPlug.elementByPhysicalIndex( k );
 
303
                    if (inputTargetGroupPlug.attribute().isNull()) continue;
 
304
 
 
305
                    MPlug inputTargetInputArrayPlug = DagHelper::getChildPlug( inputTargetGroupPlug, ATTR_INPUT_TARGET_INPUT ); // "inputTargetInput"
 
306
                    if ( inputTargetInputArrayPlug.attribute().isNull() ) continue;
 
307
 
 
308
                    uint inputTargetInputCount = inputTargetInputArrayPlug.numElements();
 
309
                    for (uint m = 0; m < inputTargetInputCount; ++m)
 
310
                    {
 
311
                        MPlug inputTargetInput = inputTargetInputArrayPlug.elementByPhysicalIndex(m);
 
312
                        if (inputTargetInput.attribute().isNull()) continue;
 
313
 
 
314
                        MPlug inputTargetGeometryPlug = DagHelper::getChildPlug( inputTargetInput, ATTR_INPUT_GEOM_TARGET ); // "inputGeomTarget"
 
315
                        if (inputTargetGeometryPlug.attribute().isNull()) continue;
 
316
 
 
317
                        // We now have a valid Maya blend shape target.
 
318
                        uint currentIndex = nextIndex++;
 
319
                        String blendShapeTargetId;
 
320
                        bool isInstanced = DagHelper::hasConnection( inputTargetGeometryPlug, false, true );
 
321
                        if (isInstanced)
 
322
                        {
 
323
                            // Find the first attached mesh DAG node.
 
324
                            MItDependencyGraph itDG(
 
325
                                inputTargetGeometryPlug,
 
326
                                MFn::kMesh,
 
327
                                MItDependencyGraph::kUpstream,
 
328
                                MItDependencyGraph::kDepthFirst,
 
329
                                MItDependencyGraph::kNodeLevel);
 
330
                            MObject targetObj = itDG.thisNode();
 
331
                            if (targetObj.isNull()) continue;
 
332
 
 
333
                            // This mesh is our morph target.
 
334
                            MDagPath targetPath = MDagPath::getAPathTo ( targetObj );
 
335
                            SceneGraph* sceneGraph = mDocumentExporter->getSceneGraph();
 
336
                            if ( sceneGraph->findExportedElement( targetPath ) == NULL )
 
337
                            {
 
338
                                SceneElement* targetSceneElement = sceneGraph->findElement( targetPath );
 
339
                                // We have to export the geometry
 
340
                                targetSceneElement->setIsForced ( true );
 
341
                                if ( !targetSceneElement->getNodeId().empty() )
 
342
                                    blendShapeTargetId = targetSceneElement->getNodeId();
 
343
                                else blendShapeTargetId = targetSceneElement->getNodeName();
 
344
                            }
 
345
                        }
 
346
                        else
 
347
                        {
 
348
                            // TODO What the hell is this?
 
349
                            MPlug targetVertexListPlug = DagHelper::getChildPlug( inputTargetInput, ATTR_INPUT_POINTS_TARGET ); // "inputPointsTarget"
 
350
                            if (inputTargetInput.attribute().isNull()) continue;
 
351
 
 
352
                            MPlug targetComponentListPlug = DagHelper::getChildPlug( inputTargetInput, ATTR_INPUT_COMPONENT_TARGET ); // "inputComponentTarget"
 
353
                            if (inputTargetInput.attribute().isNull()) continue;
 
354
 
 
355
                            std::cerr << "'exportMorphTarget' not implemented!" << std::endl;
 
356
                            continue;
 
357
                            // We have a dangling geometry: create a FCDGeometry and fill it with the vertex positions.
 
358
//                            blendShapeTargetId = exportMorphTarget(targetVertexListPlug, targetComponentListPlug, currentIndex, baseMesh);
 
359
                        }
 
360
 
 
361
                        if ( !blendShapeTargetId.empty() )
 
362
                        {
 
363
                            MPlug weightPlug = weightArrayPlug.elementByLogicalIndex ( currentIndex );
 
364
                            if (weightPlug.attribute().isNull()) continue;
 
365
 
 
366
                            blendTargets.push_back( blendShapeTargetId );
 
367
                            weightPlugs.push_back( weightPlug );
 
368
                        }
 
369
                    }
 
370
                }
 
371
            }
 
372
        }
 
373
 
 
374
        size_t targetCount = blendTargets.size();
 
375
        if (targetCount == 0) return ;
 
376
 
 
377
        // Set the weights and export the morph target weight animations
 
378
        for ( size_t j=0; j<targetCount; ++j )
 
379
        {
 
380
            MPlug& weightPlug = weightPlugs[j];
 
381
            MPlug enveloppePlug = MFnDependencyNode( weightPlug.node() ).findPlug( ATTR_ENVELOPE );
 
382
            float envelope=1.0f, weight;
 
383
            if ( !enveloppePlug.attribute().isNull() )
 
384
                enveloppePlug.getValue ( envelope );
 
385
            weightPlug.getValue( weight );
 
386
            blendWeights.push_back( envelope * weight );
 
387
 
 
388
            String subId = colladaControllerId + MORPH_WEIGHTS_SOURCE_ID_SUFFIX;
 
389
            AnimationExporter* animExport = mDocumentExporter->getAnimationExporter();
 
390
            animExport->addPlugAnimation( weightPlug, subId, kSingle, XY_PARAMETERS, false, ( int ) j );
 
391
        }
 
392
 
 
393
        // Write the controller data into the COLLADA document
 
394
        writeMorphController ( sceneElement->getNodeName(), morphController );
 
395
    }
 
396
 
 
397
    //------------------------------------------------------
 
398
    void ControllerExporter::exportMorphTarget(
 
399
        MPlug& targetVertexListPlug,
 
400
        MPlug& targetComponentListPlug,
 
401
        uint currentIndex )
 
402
    {
 
403
        MStatus status;
 
404
 
 
405
        // Retrieve the data objects for the vertex list.
 
406
        MObject pointArrayData, componentListData;
 
407
        CHECK_STAT ( targetVertexListPlug.getValue ( pointArrayData ) );
 
408
        if ( pointArrayData.isNull() ) return ;
 
409
 
 
410
        CHECK_STAT ( targetComponentListPlug.getValue ( componentListData ) );
 
411
        if ( componentListData.isNull() ) return ;
 
412
 
 
413
        MFnPointArrayData vlistFn ( pointArrayData, &status ); CHECK_STAT ( status );
 
414
        uint relativePointCount = vlistFn.length(&status); CHECK_STAT ( status );
 
415
        if ( relativePointCount == 0 ) return ;
 
416
 
 
417
        MFnComponentListData componentListFn ( componentListData, &status ); CHECK_STAT ( status );
 
418
        uint componentCount = componentListFn.length ( &status ); CHECK_STAT ( status );
 
419
        if ( componentCount == 0 ) return ;
 
420
    }
 
421
 
 
422
    //------------------------------------------------------
 
423
    void ControllerExporter::exportSkinController(
 
424
        SceneElement* sceneElement,
 
425
        const MObject controllerNode,
 
426
        MDagPath outputShape )
 
427
    {
 
428
        // Get the current path.
 
429
        MDagPath targetDagPath = sceneElement->getPath();
 
430
 
 
431
        // Figure out which type of skin controller we currently have: mesh-centric or joint-centric
 
432
        bool isJointCluster = controllerNode.hasFn(MFn::kJointCluster);
 
433
        bool isSkinCluster = controllerNode.hasFn(MFn::kSkinClusterFilter);
 
434
        if (!isJointCluster && !isSkinCluster) return;
 
435
 
 
436
        // Retrieve the instance information for this skinned character
 
437
        MFnGeometryFilter clusterFn(controllerNode);
 
438
        uint clusterIndex = retrieveInstanceInformation ( clusterFn, outputShape );
 
439
 
 
440
        // Create the controller name
 
441
//         MString mayaControllerName = ( isSkinCluster ) ? clusterFn.name() : outputShape.partialPathName();
 
442
//         String mayaControllerId = mayaControllerName.asChar();
 
443
        bool morphController =  hasMorphController( targetDagPath.node() );
 
444
        String controllerIdSuffix;
 
445
        if ( morphController )
 
446
            controllerIdSuffix = COLLADASW::LibraryControllers::MORPH_CONTROLLER_ID_SUFFIX +
 
447
                COLLADASW::LibraryControllers::SKIN_CONTROLLER_ID_SUFFIX;
 
448
        else controllerIdSuffix = COLLADASW::LibraryControllers::SKIN_CONTROLLER_ID_SUFFIX;
 
449
        String mayaControllerId = sceneElement->getNodeName() + controllerIdSuffix;
 
450
 
 
451
        // Generate a COLLADA id for the new object
 
452
        String colladaControllerId;
 
453
 
 
454
        // Check if there is an extra attribute "colladaId" and use this as export id.
 
455
        MString attributeValue;
 
456
        DagHelper::getPlugValue ( controllerNode, COLLADA_ID_ATTRIBUTE_NAME, attributeValue );
 
457
        if ( attributeValue != EMPTY_CSTRING )
 
458
        {
 
459
            // Generate a valid collada name, if necessary.
 
460
            colladaControllerId = mDocumentExporter->mayaNameToColladaName ( attributeValue, false );
 
461
        }
 
462
        else
 
463
        {
 
464
            //colladaControllerId = mDocumentExporter->dagPathToColladaId ( sceneElement->getPath () ) + controllerIdSuffix;
 
465
            colladaControllerId = sceneElement->getNodeName() + controllerIdSuffix;
 
466
        }
 
467
 
 
468
        // Make the id unique and store it in a map.
 
469
        colladaControllerId = mControllerIdList.addId ( colladaControllerId );
 
470
        mMayaIdColladaIdMap [ mayaControllerId ] = colladaControllerId;
 
471
 
 
472
        // TODO Get the unique skin target id.
 
473
        // If the output shape has a morph controller, the target
 
474
        // is not the shape's geometry, but the morph controller.
 
475
        MObject outputNode = outputShape.node ();
 
476
        MFnDependencyNode fn ( outputNode );
 
477
        
 
478
        String skinTarget = DocumentExporter::mayaNameToColladaName ( fn.name() );
 
479
        if ( hasMorphController ( outputShape.node() ) )
 
480
        {
 
481
            // TODO Get the original collada id from the blend shape.
 
482
            skinTarget += COLLADASW::LibraryControllers::MORPH_CONTROLLER_ID_SUFFIX;
 
483
        }
 
484
        else
 
485
        {
 
486
            // Attach a function set to the mesh node.
 
487
            // We access all of the meshes data through the function set
 
488
            MStatus status;
 
489
            MFnMesh fnMesh ( outputNode, &status );
 
490
            if ( status != MStatus::kSuccess ) return;
 
491
 
 
492
            // Get the scene element by the dag path.
 
493
            MDagPath meshDagPath = fnMesh.dagPath ();
 
494
 
 
495
            // TODO Get the skin controller connected geometry to get the skin target.
 
496
            
 
497
 
 
498
            // TODO Get the original collada id from the geometry.
 
499
            GeometryExporter* geometryExporter = mDocumentExporter->getGeometryExporter ();
 
500
            skinTarget = geometryExporter->generateColladaMeshId ( outputShape );
 
501
        }
 
502
 
 
503
        // Create an skin controller to hold the data
 
504
        SkinController skinController ( colladaControllerId, mayaControllerId );
 
505
 
 
506
        // Get the transform matrix for the shape.
 
507
        getBindShapeTransform ( &skinController, clusterFn, isJointCluster, clusterIndex, sceneElement );
 
508
 
 
509
        // The weight filters to fill in.
 
510
        MObjectArray weightFilters;
 
511
 
 
512
        // Gather the list of joints and write them as the influences in the target controller object.
 
513
        gatherJoints ( &skinController, controllerNode, weightFilters, clusterIndex );
 
514
 
 
515
        // Set the joint entry into the other scene element, which use this joints.
 
516
        MDagPathArray influences = skinController.getInfluences();
 
517
        unsigned int numInfluences = influences.length();
 
518
        for ( unsigned int i=0; i<numInfluences; ++i )
 
519
        {
 
520
            // Get the scene element.
 
521
            MDagPath skeletonPath = influences [i];
 
522
            SceneElement* sceneElement = mDocumentExporter->getSceneGraph ()->findElement ( skeletonPath );
 
523
 
 
524
            // Get the collada id.
 
525
            VisualSceneExporter* visualSceneExporter = mDocumentExporter->getVisualSceneExporter ();
 
526
            String colladaNodeId = visualSceneExporter->getColladaNodeId ( skeletonPath );
 
527
 
 
528
            // Get the uri of the current scene
 
529
            COLLADASW::URI skeletonUri ( visualSceneExporter->getSceneElementURI ( sceneElement, colladaNodeId ) );
 
530
            sceneElement->addSkeletonURI ( skeletonUri );
 
531
 
 
532
            // Set the id on the other instanced nodes.
 
533
            bool isInstanced = targetDagPath.isInstanced ();
 
534
            uint instanceNumber = targetDagPath.instanceNumber ();
 
535
            MDagPathArray pathes;
 
536
            MDagPath::getAllPathsTo( targetDagPath.node(), pathes );
 
537
            for (uint i=0; i<pathes.length(); ++i)
 
538
            {
 
539
                SceneElement* foundElement = mDocumentExporter->getSceneGraph()->findElement ( pathes[i] );
 
540
                if ( foundElement != NULL )
 
541
                    foundElement->addSkeletonURI ( skeletonUri );
 
542
            }
 
543
        }
 
544
 
 
545
        // Gather the bind matrices and write them as the bind poses in the target controller object.
 
546
        gatherBindMatrices ( &skinController, controllerNode );
 
547
 
 
548
        // Collect the vertex weights into the collada skin controller.
 
549
        collectVertexWeights ( &skinController, controllerNode, outputShape, weightFilters, clusterIndex, numInfluences );
 
550
 
 
551
        // Create the joints
 
552
        createJoints ( &skinController );
 
553
 
 
554
        // Write the data into the collada document.
 
555
        writeSkinController ( skinTarget, skinController );
 
556
 
 
557
    }
 
558
 
 
559
    //------------------------------------------------------
 
560
    void ControllerExporter::collectVertexWeights (
 
561
        SkinController* skinController,
 
562
        const MObject &controllerNode,
 
563
        const MDagPath &outputShape,
 
564
        const MObjectArray &weightFilters,
 
565
        const uint clusterIndex,
 
566
        uint numInfluences )
 
567
    {
 
568
        // Attach a function set to the output shape.
 
569
        MFnMesh meshFn( outputShape );
 
570
 
 
571
        // Collect all the weights
 
572
        uint numVertices = meshFn.numVertices();
 
573
        SkinControllerVertices& colladaInfluences = skinController->getVertexInfluences();
 
574
        colladaInfluences.resize(numVertices);
 
575
 
 
576
        if (controllerNode.apiType() == MFn::kSkinClusterFilter)
 
577
        {
 
578
            collectSkinClusterFilterVertexWeights(
 
579
                colladaInfluences, controllerNode, outputShape, numInfluences);
 
580
        }
 
581
        else if (controllerNode.apiType() == MFn::kJointCluster)
 
582
        {
 
583
            collectJointClusterVertexWeights(
 
584
                colladaInfluences, weightFilters, outputShape, clusterIndex );
 
585
        }
 
586
    }
 
587
 
 
588
    //------------------------------------------------------
 
589
    void ControllerExporter::collectSkinClusterFilterVertexWeights (
 
590
        SkinControllerVertices& colladaInfluences,
 
591
        const MObject& controllerNode,
 
592
        const MDagPath& outputShape,
 
593
        uint numInfluences )
 
594
    {
 
595
        MFnSkinCluster skinClusterFn(controllerNode);
 
596
        for (MItGeometry componentIt(outputShape); !componentIt.isDone(); componentIt.next())
 
597
        {
 
598
            int index = componentIt.index();
 
599
            SkinControllerVertex& vertex = colladaInfluences[index];
 
600
 
 
601
            WeightArray weights;
 
602
            MObject component = componentIt.component();
 
603
            if (skinClusterFn.getWeights(outputShape, component, weights, numInfluences) != MS::kSuccess)
 
604
            {
 
605
                weights.clear();
 
606
            }
 
607
 
 
608
            uint weightCount = weights.length();
 
609
            for (uint i = 0; i < weightCount; ++i)
 
610
            {
 
611
                Weight weight = weights[i];
 
612
                if (!COLLADABU::Math::Utils::equals(weight, Weight(0), getTolerance ()))
 
613
                {
 
614
                    vertex[i] = (float)weight;
 
615
                }
 
616
            }
 
617
        }
 
618
    }
 
619
 
 
620
    //------------------------------------------------------
 
621
    void ControllerExporter::collectJointClusterVertexWeights (
 
622
        SkinControllerVertices& colladaInfluences,
 
623
        const MObjectArray &weightFilters,
 
624
        const MDagPath &outputShape,
 
625
        const uint clusterIndex )
 
626
    {
 
627
        // Get the weight for each of the clusters
 
628
        uint weightFilterCount = weightFilters.length();
 
629
        for (uint i = 0; i < weightFilterCount; ++i)
 
630
        {
 
631
            MFnWeightGeometryFilter filterFn(weightFilters[i]);
 
632
            MObject deformSet = filterFn.deformerSet();
 
633
            MFnSet setFn(deformSet);
 
634
 
 
635
            // Get all the components affected by this joint cluster
 
636
            MSelectionList clusterSetList;
 
637
            setFn.getMembers(clusterSetList, true);
 
638
 
 
639
            MDagPath shapePath;
 
640
            MObject components;
 
641
            uint setListCount = clusterSetList.length();
 
642
            for (uint s = 0; s < setListCount; ++s)
 
643
            {
 
644
                clusterSetList.getDagPath(s, shapePath, components);
 
645
                if (shapePath.node() == outputShape.node()) break;
 
646
            }
 
647
 
 
648
            MFloatArray weights;
 
649
            filterFn.getWeights(clusterIndex, components, weights);
 
650
 
 
651
            uint counter = 0;
 
652
            for ( MItGeometry componentIt(shapePath, components);
 
653
                !componentIt.isDone() && counter < weights.length();
 
654
                componentIt.next() )
 
655
            {
 
656
                // append the weight at its correct position: i
 
657
                float weight = weights[counter++];
 
658
                if ( COLLADABU::Math::Utils::equalsZero ( weight, getTolerance () ) )
 
659
                {
 
660
                    SkinControllerVertex& vertex = colladaInfluences[componentIt.index()];
 
661
                    vertex[i] = weight;
 
662
                }
 
663
            }
 
664
        }
 
665
    }
 
666
 
 
667
    //------------------------------------------------------
 
668
    void ControllerExporter::gatherJoints (
 
669
        SkinController* skinController,
 
670
        const MObject &controllerNode,
 
671
        MObjectArray &weightFilters,
 
672
        const uint clusterIndex )
 
673
{
 
674
        // Gather the list of joints
 
675
        MDagPathArray& influences = skinController->getInfluences();
 
676
        if (controllerNode.apiType() == MFn::kSkinClusterFilter)
 
677
        {
 
678
            MStatus status;
 
679
            MFnSkinCluster skinClusterFn( controllerNode );
 
680
            skinClusterFn.influenceObjects(influences, &status);
 
681
        }
 
682
        else if (controllerNode.apiType() == MFn::kJointCluster)
 
683
        {
 
684
            // Support for joint clusters pipeline
 
685
            getJointClusterInfluences(controllerNode, influences, weightFilters, clusterIndex);
 
686
        }
 
687
    }
 
688
 
 
689
    //------------------------------------------------------
 
690
    void ControllerExporter::gatherBindMatrices(
 
691
        SkinController* skinController,
 
692
        const MObject& controllerNode )
 
693
    {
 
694
        // The list of joints
 
695
        MDagPathArray& influences = skinController->getInfluences();
 
696
 
 
697
        // Request a change in capacity
 
698
        uint numInfluences = influences.length();
 
699
        std::vector<MMatrix>& bindPoses = skinController->getBindPoses();
 
700
        bindPoses.reserve(numInfluences);
 
701
 
 
702
        // Gather the bind matrices
 
703
        for (uint i = 0; i < numInfluences; ++i)
 
704
        {
 
705
            MObject influence = influences[i].node();
 
706
            MMatrix mayaBindPoseMatrix = DagHelper::getBindPoseInverse(controllerNode, influence);
 
707
            bindPoses.push_back( mayaBindPoseMatrix );
 
708
        }
 
709
    }
 
710
 
 
711
    //------------------------------------------------------
 
712
    void ControllerExporter::createJoints(
 
713
        SkinController* skinController )
 
714
    {
 
715
        // Gather the list of joints
 
716
        const MDagPathArray& influences = skinController->getInfluences();
 
717
 
 
718
        // Create the joints with their ids.
 
719
        SkinControllerJoints& joints = skinController->getJoints();
 
720
        uint numInfluences = influences.length();
 
721
        joints.resize( numInfluences );
 
722
 
 
723
        for (uint i=0; i<numInfluences; ++i)
 
724
        {
 
725
            MDagPath dagPath = influences[i];
 
726
 
 
727
            SkinControllerJoint &joint = joints[i];
 
728
            joint.first = mDocumentExporter->dagPathToColladaId ( dagPath );
 
729
            joint.second = skinController->getBindPoses()[i];
 
730
        }
 
731
    }
 
732
 
 
733
    //------------------------------------------------------
 
734
    void ControllerExporter::getJointClusterInfluences(
 
735
        const MObject &controllerNode,
 
736
        MDagPathArray &influences,
 
737
        MObjectArray &weightFilters,
 
738
        const uint clusterIndex )
 
739
    {
 
740
        MObject cluster( controllerNode );
 
741
        while ( cluster.apiType() == MFn::kJointCluster )
 
742
        {
 
743
            weightFilters.append(cluster);
 
744
 
 
745
            MObject joint = DagHelper::getNodeConnectedTo( cluster, ATTR_MATRIX );
 
746
            MDagPath jointPath = MDagPath::getAPathTo( joint );
 
747
            influences.append(jointPath);
 
748
 
 
749
            MStatus status;
 
750
            MPlug plug = ShaderHelper::findPlug(MFnDependencyNode(cluster), ATTR_INPUt, &status);
 
751
            if (status != MStatus::kSuccess)
 
752
            { MGlobal::displayError("Unable to get joint cluster input plug."); return; }
 
753
 
 
754
            plug = plug.elementByLogicalIndex(clusterIndex, &status);
 
755
            if (status != MStatus::kSuccess)
 
756
            { MGlobal::displayError("Unable to get joint cluster input plug first element."); return; }
 
757
 
 
758
            plug = DagHelper::getChildPlug(plug, ATTR_INPUT_GEOMETRY, &status); // "inputGeometry"
 
759
            if (status != MStatus::kSuccess)
 
760
            { MGlobal::displayError("Unable to get joint cluster input geometry plug."); return; }
 
761
 
 
762
            cluster = DagHelper::getSourceNodeConnectedTo(plug);
 
763
        }
 
764
    }
 
765
 
 
766
    //------------------------------------------------------
 
767
    void ControllerExporter::getBindShapeTransform(
 
768
        SkinController* skinController,
 
769
        const MFnGeometryFilter &clusterFn,
 
770
        const bool isJointCluster,
 
771
        const uint index, 
 
772
        SceneElement* sceneElement )
 
773
    {
 
774
        // Add the bind-shape bind matrix
 
775
        MMatrix mayaBindShapeMatrix;
 
776
        MPlug bindShapeMatrixPlug = clusterFn.findPlug ( ATTR_GEOM_MATRIX );
 
777
 
 
778
        if ( isJointCluster )
 
779
            bindShapeMatrixPlug = bindShapeMatrixPlug.elementByLogicalIndex ( index );
 
780
 
 
781
        DagHelper::getPlugValue ( bindShapeMatrixPlug, mayaBindShapeMatrix );
 
782
 
 
783
        // Store the bindShapeMatrix of every element in a list.
 
784
        // We need it again for the transformation of the skin controller elements.
 
785
        sceneElement->setBindShapeMatrix ( mayaBindShapeMatrix );
 
786
 
 
787
        // Set the bindShapeMatrix in the skin controller.
 
788
        skinController->setBindShapeTransform ( mayaBindShapeMatrix );
 
789
    }
 
790
 
 
791
    //------------------------------------------------------
 
792
    bool ControllerExporter::hasController ( const MObject& node )
 
793
    {
 
794
        return hasSkinController ( node ) || hasMorphController ( node );
 
795
    }
 
796
 
 
797
    //------------------------------------------------------
 
798
    bool ControllerExporter::hasSkinController ( const MObject& node )
 
799
    {
 
800
        MStatus status;
 
801
        MPlug plug = MFnDependencyNode ( node ).findPlug ( ATTR_IN_MESH, &status );
 
802
 
 
803
        if ( !status || !plug.isConnected() ) return false;
 
804
 
 
805
        MItDependencyGraph dgIt ( plug,
 
806
            MFn::kInvalid,
 
807
            MItDependencyGraph::kUpstream,
 
808
            MItDependencyGraph::kBreadthFirst,
 
809
            MItDependencyGraph::kNodeLevel,
 
810
            &status );
 
811
        if ( status != MS::kSuccess ) return false;
 
812
 
 
813
        dgIt.disablePruningOnFilter();
 
814
 
 
815
        while ( !dgIt.isDone() )
 
816
        {
 
817
            MObject thisNode = dgIt.thisNode();
 
818
            if ( thisNode.hasFn ( MFn::kSkinClusterFilter ) || thisNode.hasFn ( MFn::kJointCluster ) )
 
819
            {
 
820
                return true;
 
821
            }
 
822
 
 
823
            dgIt.next();
 
824
        }
 
825
 
 
826
        return false;
 
827
    }
 
828
 
 
829
    //------------------------------------------------------
 
830
    bool ControllerExporter::hasMorphController ( const MObject& node )
 
831
    {
 
832
        MPlug plug = MFnDependencyNode ( node ).findPlug ( ATTR_IN_MESH );
 
833
        if ( plug.isConnected() )
 
834
        {
 
835
            MItDependencyGraph dgIt ( plug,
 
836
                MFn::kInvalid,
 
837
                MItDependencyGraph::kUpstream,
 
838
                MItDependencyGraph::kDepthFirst,
 
839
                MItDependencyGraph::kPlugLevel );
 
840
            dgIt.disablePruningOnFilter();
 
841
 
 
842
            for ( ; ! dgIt.isDone(); dgIt.next() )
 
843
            {
 
844
                MObject thisNode = dgIt.thisNode();
 
845
                if ( thisNode.hasFn ( MFn::kBlendShape ) ) return true;
 
846
            }
 
847
        }
 
848
 
 
849
        return 0;
 
850
    }
 
851
 
 
852
    //------------------------------------------------------
 
853
    void ControllerExporter::disableBlendShape ( ControllerStack &stack )
 
854
    {
 
855
        // Disable the blend shape
 
856
        for ( size_t i=0; i<stack.size(); ++i )
 
857
        {
 
858
            ControllerStackItem* item = stack[i];
 
859
 
 
860
            // Disable the blend shape node
 
861
            if ( item->skinControllerNode.hasFn ( MFn::kBlendShape ) )
 
862
            {
 
863
                // Attach the function set
 
864
                MFnBlendShapeDeformer fn ( item->skinControllerNode );
 
865
 
 
866
                // get the envelope attribute plug
 
867
                MPlug plug = fn.findPlug ( ATTR_ENVELOPE );
 
868
 
 
869
                // Get the old value
 
870
                float envelope;
 
871
                MStatus status = plug.getValue ( envelope );
 
872
                if ( status != MStatus::kSuccess ) return ;
 
873
                item->envelope = envelope;
 
874
 
 
875
                // set to 0 to disable FFD effect
 
876
                plug.setValue (0.0f) ;
 
877
            }
 
878
        }
 
879
    }
 
880
 
 
881
    //------------------------------------------------------
 
882
    void ControllerExporter::enableBlendShape ( ControllerStack &stack )
 
883
    {
 
884
        // Enable the blend shape
 
885
        for ( size_t i=0; i<stack.size(); ++i )
 
886
        {
 
887
            ControllerStackItem* item = stack[i];
 
888
 
 
889
            // Disable the blend shape node
 
890
            if ( item->skinControllerNode.hasFn ( MFn::kBlendShape ) )
 
891
            {
 
892
                // Attach the function set
 
893
                MFnBlendShapeDeformer fn ( item->skinControllerNode );
 
894
 
 
895
                // get the envelope attribute plug
 
896
                MPlug plug = fn.findPlug ( ATTR_ENVELOPE );
 
897
 
 
898
                // set to 0 to disable FFD effect
 
899
                plug.setValue ( item->envelope );
 
900
            }
 
901
        }
 
902
    }
 
903
 
 
904
    //------------------------------------------------------
 
905
    uint ControllerExporter::retrieveInstanceInformation(
 
906
        const MFnGeometryFilter &clusterFn,
 
907
        MDagPath &outputShape )
 
908
    {
 
909
        MStatus status;
 
910
 
 
911
        // Attach a function set to the controller node.
 
912
        MFnMesh fnMesh ( outputShape, &status );
 
913
        CHECK_STAT (status);
 
914
 
 
915
        uint idx = clusterFn.indexForOutputShape(outputShape.node());
 
916
        if (idx == ~0u)
 
917
        {
 
918
            // Alternate method for retrieving the index?
 
919
            MPlug meshConnection = fnMesh.findPlug( ATTR_IN_MESH );
 
920
            MItDependencyGraph dgIt(
 
921
                meshConnection,
 
922
                MFn::kMesh,
 
923
                MItDependencyGraph::kUpstream,
 
924
                MItDependencyGraph::kBreadthFirst,
 
925
                MItDependencyGraph::kNodeLevel,
 
926
                &status);
 
927
            CHECK_STATUS_AND_RETURN(status, NULL);
 
928
            dgIt.disablePruningOnFilter();
 
929
 
 
930
            for (; ! dgIt.isDone(); dgIt.next())
 
931
            {
 
932
                MObject thisNode = dgIt.thisNode();
 
933
                idx = clusterFn.indexForOutputShape(thisNode);
 
934
                if (idx != ~0u)
 
935
                {
 
936
                    outputShape = MDagPath::getAPathTo(thisNode);
 
937
                    break;
 
938
                }
 
939
            }
 
940
        }
 
941
        return idx;
 
942
    }
 
943
 
 
944
    //------------------------------------------------------
 
945
    void ControllerExporter::writeSkinJointSource( const SkinController &skinController )
 
946
    {
 
947
        COLLADASW::NameSource jointSource( mDocumentExporter->getStreamWriter() );
 
948
        String controllerId = skinController.getControllerId();
 
949
        jointSource.setId ( controllerId + JOINTS_SOURCE_ID_SUFFIX );
 
950
        jointSource.setNodeName ( controllerId + JOINTS_SOURCE_ID_SUFFIX );
 
951
        jointSource.setArrayId ( controllerId + JOINTS_SOURCE_ID_SUFFIX + ARRAY_ID_SUFFIX );
 
952
        jointSource.setAccessorStride ( 1 );
 
953
 
 
954
        // Retrieves the vertex positions.
 
955
        const MDagPathArray& influences = skinController.getInfluences();
 
956
        uint numInfluences = influences.length();
 
957
        jointSource.setAccessorCount ( numInfluences );
 
958
 
 
959
        jointSource.getParameterNameList().push_back ( PARAM_TYPE_JOINT );
 
960
        jointSource.prepareToAppendValues();
 
961
 
 
962
        const SkinControllerJoints& joints = skinController.getJoints();
 
963
        SkinControllerJoints::const_iterator it = joints.begin();
 
964
        for (; it<joints.end(); ++it)
 
965
        {
 
966
            String boneId = (*it).first;
 
967
            jointSource.appendValues ( boneId );
 
968
        }
 
969
        jointSource.finish();
 
970
    }
 
971
 
 
972
    //------------------------------------------------------
 
973
    void ControllerExporter::writeMorphTargetSource( const MorphController &morphController )
 
974
    {
 
975
        COLLADASW::IdRefSource targetSource( mDocumentExporter->getStreamWriter() );
 
976
        String controllerId = morphController.getControllerId();
 
977
        targetSource.setId ( controllerId + TARGETS_SOURCE_ID_SUFFIX );
 
978
        targetSource.setNodeName ( controllerId + TARGETS_SOURCE_ID_SUFFIX );
 
979
        targetSource.setArrayId ( controllerId + TARGETS_SOURCE_ID_SUFFIX + ARRAY_ID_SUFFIX );
 
980
        targetSource.setAccessorStride ( 1 );
 
981
 
 
982
        // Retrieve the morph controller targets.
 
983
        const MorphControllerTargets& morphControllerTargets = morphController.getMorphControllerTargets();
 
984
        size_t numTargets = morphControllerTargets.size();
 
985
        targetSource.setAccessorCount ( ( unsigned long ) numTargets );
 
986
        targetSource.getParameterNameList().push_back ( PARAM_TYPE_MORPH_TARGET );
 
987
        targetSource.prepareToAppendValues();
 
988
        targetSource.appendValues ( morphControllerTargets );
 
989
        targetSource.finish();
 
990
    }
 
991
 
 
992
    //------------------------------------------------------
 
993
    void ControllerExporter::writeSkinBindPosesSource( const SkinController &skinController )
 
994
    {
 
995
        COLLADASW::Float4x4Source bindPosesSource( mDocumentExporter->getStreamWriter() );
 
996
        String controllerId = skinController.getControllerId();
 
997
        bindPosesSource.setId ( controllerId + BIND_POSES_SOURCE_ID_SUFFIX );
 
998
        bindPosesSource.setNodeName ( controllerId + BIND_POSES_SOURCE_ID_SUFFIX );
 
999
        bindPosesSource.setArrayId ( controllerId + BIND_POSES_SOURCE_ID_SUFFIX + ARRAY_ID_SUFFIX );
 
1000
        bindPosesSource.setAccessorStride ( 16 );
 
1001
 
 
1002
        // Retrieves the vertex positions.
 
1003
        const MDagPathArray& influences = skinController.getInfluences();
 
1004
        uint numInfluences = influences.length();
 
1005
        bindPosesSource.setAccessorCount ( numInfluences );
 
1006
 
 
1007
        bindPosesSource.getParameterNameList().push_back ( PARAM_TYPE_TRANSFORM );
 
1008
        bindPosesSource.prepareToAppendValues();
 
1009
 
 
1010
        const std::vector<MMatrix>& bindPosesVec = skinController.getBindPoses();
 
1011
        size_t numBindPoses = bindPosesVec.size();
 
1012
        for (size_t i=0; i<bindPosesVec.size(); ++i)
 
1013
        {
 
1014
            MMatrix mayaBindPoses = bindPosesVec[i];
 
1015
            double bindPoses[4][4];
 
1016
            convertMayaMatrixToTransposedDouble4x4 ( bindPoses, mayaBindPoses, getTolerance () );
 
1017
 
 
1018
            // Convert the  maya internal unit type of the transform part of the
 
1019
            // matrix from centimeters into the working units of the current scene!
 
1020
            for ( uint i=0; i<3; ++i)
 
1021
                bindPoses [i][3] = MDistance::internalToUI ( bindPoses [i][3] );
 
1022
 
 
1023
            bindPosesSource.appendValues ( bindPoses );
 
1024
        }
 
1025
        bindPosesSource.finish();
 
1026
    }
 
1027
 
 
1028
    //------------------------------------------------------
 
1029
    void ControllerExporter::writeSkinWeightSource( const SkinController &skinController )
 
1030
    {
 
1031
        String controllerId = skinController.getControllerId();
 
1032
        COLLADASW::FloatSourceF weightSource( mDocumentExporter->getStreamWriter() );
 
1033
        weightSource.setId ( controllerId + WEIGHTS_SOURCE_ID_SUFFIX );
 
1034
        weightSource.setNodeName ( controllerId + WEIGHTS_SOURCE_ID_SUFFIX );
 
1035
        weightSource.setArrayId ( controllerId + WEIGHTS_SOURCE_ID_SUFFIX + ARRAY_ID_SUFFIX );
 
1036
        weightSource.setAccessorStride ( 1 );
 
1037
 
 
1038
        // Create the vertex list
 
1039
        std::vector<float> vertexVec;
 
1040
 
 
1041
        // Push a single one weight in front of the list. The vertex_weights array
 
1042
        // can always reference to it, if we have a one weight.
 
1043
        vertexVec.push_back(1.0f);
 
1044
        uint numVertexPoints = 1;
 
1045
 
 
1046
        const SkinControllerVertices& vertexes = skinController.getVertexInfluences();
 
1047
        for (uint i=0; i<vertexes.size(); ++i)
 
1048
        {
 
1049
            SkinControllerVertex vertex = vertexes[i];
 
1050
            for (uint j=0; j<vertex.size(); ++j)
 
1051
            {
 
1052
                // We don't need to write the zero weight, cause then there is no
 
1053
                // influence. We don't write the one weights, cause we have written
 
1054
                // (see below) a one weight in front of the vertex_weights array and
 
1055
                // always reference to it from the vertex_weights array.
 
1056
                if ( !COLLADABU::Math::Utils::equalsZero ( vertex[j], getTolerance () ) &&
 
1057
                     !COLLADABU::Math::Utils::equals ( vertex[j], 1.0f, (float)getTolerance () ) )
 
1058
                {
 
1059
                    vertexVec.push_back ( vertex[j] );
 
1060
                    ++numVertexPoints;
 
1061
                }
 
1062
            }
 
1063
        }
 
1064
        weightSource.setAccessorCount ( numVertexPoints );
 
1065
 
 
1066
        weightSource.getParameterNameList().push_back ( PARAM_TYPE_WEIGHT );
 
1067
        weightSource.prepareToAppendValues();
 
1068
        weightSource.appendValues ( vertexVec );
 
1069
        weightSource.finish();
 
1070
    }
 
1071
 
 
1072
    //------------------------------------------------------
 
1073
    void ControllerExporter::writeMorphWeightSource( const MorphController &morphController )
 
1074
    {
 
1075
        String controllerId = morphController.getControllerId();
 
1076
        COLLADASW::FloatSourceF weightSource( mDocumentExporter->getStreamWriter() );
 
1077
        weightSource.setId ( controllerId + MORPH_WEIGHTS_SOURCE_ID_SUFFIX );
 
1078
        weightSource.setNodeName ( controllerId + MORPH_WEIGHTS_SOURCE_ID_SUFFIX );
 
1079
        weightSource.setArrayId ( controllerId + MORPH_WEIGHTS_SOURCE_ID_SUFFIX + ARRAY_ID_SUFFIX );
 
1080
        weightSource.setAccessorStride ( 1 );
 
1081
 
 
1082
        // Get the morph weights
 
1083
        const std::vector<float> morphWeights = morphController.getMorphControllerWeights ();
 
1084
        weightSource.setAccessorCount ( ( unsigned long ) morphWeights.size() );
 
1085
        weightSource.getParameterNameList().push_back ( PARAM_TYPE_MORPH_WEIGHT );
 
1086
        weightSource.prepareToAppendValues();
 
1087
        weightSource.appendValues ( morphWeights );
 
1088
        weightSource.finish();
 
1089
    }
 
1090
 
 
1091
    //------------------------------------------------------
 
1092
    void ControllerExporter::writeSkinBindShapeTransform ( const SkinController &skinController )
 
1093
    {
 
1094
        // Write the bind shape transform matrix in the collada document.
 
1095
        const MMatrix& mayaBindShapeMatrix = skinController.getBindShapeTransform();
 
1096
        double bindShapeMatrix[4][4] ;
 
1097
        convertMayaMatrixToTransposedDouble4x4 ( bindShapeMatrix, mayaBindShapeMatrix, getTolerance () );
 
1098
 
 
1099
        // Convert the  maya internal unit type of the transform part of the
 
1100
        // matrix from centimeters into the working units of the current scene!
 
1101
        for ( uint i=0; i<3; ++i)
 
1102
            bindShapeMatrix [i][3] = MDistance::internalToUI ( bindShapeMatrix [i][3] );
 
1103
 
 
1104
        addBindShapeTransform ( bindShapeMatrix );
 
1105
    }
 
1106
 
 
1107
    //------------------------------------------------------
 
1108
    void ControllerExporter::writeSkinController(
 
1109
        const String skinTarget,
 
1110
        const SkinController &skinController )
 
1111
    {
 
1112
        // Get the unique id and the name of the current controller.
 
1113
        String controllerId = skinController.getControllerId();
 
1114
        String controllerName = skinController.getControllerName();
 
1115
 
 
1116
        // Opens the skin tag in the collada document.
 
1117
        openSkin ( controllerId , controllerName, COLLADASW::URI ( EMPTY_STRING, skinTarget ) );
 
1118
 
 
1119
        writeSkinBindShapeTransform( skinController );
 
1120
        writeSkinJointSource( skinController );
 
1121
        writeSkinBindPosesSource( skinController );
 
1122
        writeSkinWeightSource( skinController );
 
1123
        writeSkinElementJoints( skinController );
 
1124
        writeSkinElementVertexWeights( skinController );
 
1125
 
 
1126
        // Export the original maya name.
 
1127
        COLLADASW::Extra extraSource ( mSW );
 
1128
        extraSource.openExtra();
 
1129
        COLLADASW::Technique techniqueSource ( mSW );
 
1130
        techniqueSource.openTechnique ( PROFILE_MAYA );
 
1131
        techniqueSource.addParameter ( PARAMETER_MAYA_ID, controllerName );
 
1132
        techniqueSource.closeTechnique();
 
1133
        extraSource.closeExtra();
 
1134
 
 
1135
        // Close the opened skin tag.
 
1136
        closeSkin();
 
1137
 
 
1138
        // Close the opened controller tag.
 
1139
        closeController();
 
1140
    }
 
1141
 
 
1142
    //------------------------------------------------------
 
1143
    void ControllerExporter::writeMorphController (
 
1144
        const String morphTarget,
 
1145
        const MorphController &morphController )
 
1146
    {
 
1147
        // Get the unique id and the name of the current controller.
 
1148
        String controllerId = morphController.getControllerId();
 
1149
        String controllerName = morphController.getControllerName();
 
1150
 
 
1151
        // Opens the skin tag in the collada document.
 
1152
        openMorph ( controllerId , controllerName, COLLADASW::URI ( EMPTY_STRING, morphTarget ) );
 
1153
 
 
1154
        writeMorphTargetSource( morphController );
 
1155
        writeMorphWeightSource ( morphController );
 
1156
        writeMorphElementTargets ( morphController );
 
1157
 
 
1158
        // Export the original maya name.
 
1159
        COLLADASW::Extra extraSource ( mSW );
 
1160
        extraSource.openExtra();
 
1161
        COLLADASW::Technique techniqueSource ( mSW );
 
1162
        techniqueSource.openTechnique ( PROFILE_MAYA );
 
1163
        techniqueSource.addParameter ( PARAMETER_MAYA_ID, controllerName );
 
1164
        techniqueSource.closeTechnique();
 
1165
        extraSource.closeExtra();
 
1166
 
 
1167
        // Close the opened morph tag.
 
1168
        closeMorph();
 
1169
 
 
1170
        // Close the opened controller tag.
 
1171
        closeController();
 
1172
 
 
1173
    }
 
1174
 
 
1175
    //------------------------------------------------------
 
1176
    void ControllerExporter::writeSkinElementVertexWeights( const SkinController &skinController )
 
1177
    {
 
1178
        String controllerId = skinController.getControllerId();
 
1179
        String jointSourceId = controllerId + JOINTS_SOURCE_ID_SUFFIX;
 
1180
        String weightSourceId = controllerId + WEIGHTS_SOURCE_ID_SUFFIX;
 
1181
 
 
1182
        uint offset = 0;
 
1183
        COLLADASW::VertexWeightsElement vertexWeightsElement( mDocumentExporter->getStreamWriter() );
 
1184
        COLLADASW::InputList &inputList = vertexWeightsElement.getInputList();
 
1185
        inputList.push_back ( COLLADASW::Input ( COLLADASW::InputSemantic::JOINT, COLLADASW::URI (EMPTY_STRING, jointSourceId ), offset++ ) );        inputList.push_back ( COLLADASW::Input ( COLLADASW::InputSemantic::WEIGHT, COLLADASW::URI (EMPTY_STRING, weightSourceId ), offset++ ) );
 
1186
        // The list for the vertex values.
 
1187
        std::vector<unsigned long> vertexMatches;
 
1188
 
 
1189
        // The input data
 
1190
        const SkinControllerVertices& vertexes = skinController.getVertexInfluences();
 
1191
 
 
1192
        // Counter for the influence counts
 
1193
        size_t influenceCount = vertexes.size();
 
1194
        vertexWeightsElement.setCount( ( unsigned long ) influenceCount );
 
1195
 
 
1196
        // Generate the vertex count and match value strings and export the <v> and <vcount> elements
 
1197
        uint weightOffset = 1;
 
1198
        for (size_t j=0; j<influenceCount; ++j)
 
1199
        {
 
1200
            SkinControllerVertex vertex = vertexes[j];
 
1201
            vertexWeightsElement.getVCountList().push_back( ( unsigned long ) vertex.size() );
 
1202
 
 
1203
            std::map<int, float>::const_iterator it = vertex.begin();
 
1204
            for (; it!=vertex.end(); ++it)
 
1205
            {
 
1206
                vertexMatches.push_back( (*it).first );
 
1207
 
 
1208
                if ( !COLLADABU::Math::Utils::equals( (*it).second, 1.0f, (float)getTolerance () ) )
 
1209
                    vertexMatches.push_back( weightOffset++ );
 
1210
                else
 
1211
                    // There is a one in the first position of the weight source array.
 
1212
                    // We will always reference to this element, if the weight is a one.
 
1213
                    vertexMatches.push_back ( 0 );
 
1214
            }
 
1215
        }
 
1216
        // TODO In FCollada, the last element was erased?!?
 
1217
//        if (!vertexMatches.empty()) vertexMatches.pop_back();
 
1218
 
 
1219
        vertexWeightsElement.prepareToAppendValues();
 
1220
        vertexWeightsElement.appendValues( vertexMatches );
 
1221
        vertexWeightsElement.finish();
 
1222
    }
 
1223
 
 
1224
    //------------------------------------------------------
 
1225
    void ControllerExporter::writeSkinElementJoints( const SkinController &skinController )
 
1226
    {
 
1227
        String controllerId = skinController.getControllerId();
 
1228
        String jointSourceId = controllerId + JOINTS_SOURCE_ID_SUFFIX;
 
1229
        String jointBindSourceId = controllerId + BIND_POSES_SOURCE_ID_SUFFIX;
 
1230
 
 
1231
        COLLADASW::JointsElement jointsElement( mDocumentExporter->getStreamWriter() );
 
1232
        COLLADASW::InputList &jointsInputList = jointsElement.getInputList();
 
1233
        jointsInputList.push_back ( COLLADASW::Input ( COLLADASW::InputSemantic::JOINT, COLLADASW::URI ( EMPTY_STRING, jointSourceId ) ) );
 
1234
        jointsInputList.push_back ( COLLADASW::Input ( COLLADASW::InputSemantic::BINDMATRIX, COLLADASW::URI ( EMPTY_STRING, jointBindSourceId ) ) );
 
1235
        jointsElement.add();
 
1236
    }
 
1237
 
 
1238
    //------------------------------------------------------
 
1239
    void ControllerExporter::writeMorphElementTargets( const MorphController &morphController )
 
1240
    {
 
1241
        String controllerId = morphController.getControllerId();
 
1242
        String targetSourceId = controllerId + TARGETS_SOURCE_ID_SUFFIX;
 
1243
        String morphWeightsSourceId = controllerId + MORPH_WEIGHTS_SOURCE_ID_SUFFIX;
 
1244
 
 
1245
        COLLADASW::TargetsElement targetsElement( mDocumentExporter->getStreamWriter() );
 
1246
        COLLADASW::InputList &targetsInputList = targetsElement.getInputList();
 
1247
        targetsInputList.push_back ( COLLADASW::Input ( COLLADASW::InputSemantic::MORPH_TARGET, COLLADASW::URI ( EMPTY_STRING, targetSourceId ) ) );
 
1248
        targetsInputList.push_back ( COLLADASW::Input ( COLLADASW::InputSemantic::MORPH_WEIGHT, COLLADASW::URI ( EMPTY_STRING, morphWeightsSourceId ) ) );
 
1249
        targetsElement.add();
 
1250
    }
 
1251
 
 
1252
    //------------------------------------------------------
 
1253
    bool ControllerExporter::findAffectedNodes(
 
1254
        const MObject& node,
 
1255
        ControllerStack& stack,
 
1256
        ControllerMeshStack& meshStack )
 
1257
    {
 
1258
        MPlug plug = MFnDependencyNode ( node ).findPlug ( ATTR_IN_MESH );
 
1259
 
 
1260
        if ( plug.isConnected() )
 
1261
        {
 
1262
            MStatus status;
 
1263
            MItDependencyGraph dgIt ( plug,
 
1264
                MFn::kInvalid,
 
1265
                MItDependencyGraph::kUpstream,
 
1266
                MItDependencyGraph::kBreadthFirst,
 
1267
                MItDependencyGraph::kNodeLevel,
 
1268
                &status );
 
1269
            if ( MS::kSuccess != status ) return false;
 
1270
 
 
1271
            dgIt.disablePruningOnFilter();
 
1272
            for ( ; ! dgIt.isDone(); dgIt.next() )
 
1273
            {
 
1274
                MObject thisNode = dgIt.thisNode();
 
1275
 
 
1276
                MFnDependencyNode fn( thisNode );
 
1277
                String nodeName = fn.name().asChar();
 
1278
 
 
1279
                if ( thisNode.hasFn ( MFn::kSkinClusterFilter ) || thisNode.hasFn ( MFn::kJointCluster ) )
 
1280
                {
 
1281
                    // Append the skin controller node.
 
1282
                    ControllerStackItem* item = new ControllerStackItem();
 
1283
                    item->isSkin = true;
 
1284
                    item->skinControllerNode = thisNode;
 
1285
                    stack.push_back ( item );
 
1286
                }
 
1287
                else if ( thisNode.hasFn ( MFn::kBlendShape ) )
 
1288
                {
 
1289
                    // Check for subsequent, multiple blend shape deformers.
 
1290
                    if ( stack.size() > 0 && !stack.back()->isSkin )
 
1291
                    {
 
1292
                        stack.back()->morphControllerNodes.append ( thisNode );
 
1293
                    }
 
1294
                    else
 
1295
                    {
 
1296
                        ControllerStackItem* item = new ControllerStackItem();
 
1297
                        item->isSkin = false;
 
1298
                        item->morphControllerNodes.append ( thisNode );
 
1299
                        stack.push_back ( item );
 
1300
                    }
 
1301
                }
 
1302
                else if ( thisNode.hasFn ( MFn::kMesh ) )
 
1303
                {
 
1304
                    // Queue up this mesh.
 
1305
                    ControllerMeshItem item;
 
1306
                    item.mesh = thisNode;
 
1307
                    meshStack.push_back ( item );
 
1308
                }
 
1309
            }
 
1310
 
 
1311
            return true;
 
1312
        }
 
1313
 
 
1314
        return false;
 
1315
    }
 
1316
 
 
1317
    //------------------------------------------------------
 
1318
    void ControllerExporter::setControllerNodeStatesToNoEffect( ControllerStack &stack )
 
1319
    {
 
1320
        // Set the controller node states
 
1321
        for ( size_t i=0; i<stack.size(); ++i )
 
1322
        {
 
1323
            ControllerStackItem* item = stack[i];
 
1324
 
 
1325
            // Disable the skin controller node
 
1326
            if ( item->isSkin )
 
1327
            {
 
1328
                int nodeState;
 
1329
                DagHelper::getPlugValue ( item->skinControllerNode, ATTR_NODE_STATE, nodeState );
 
1330
                DagHelper::setPlugValue ( item->skinControllerNode, ATTR_NODE_STATE, 1 ); // pass-through.
 
1331
                item->nodeStates.push_back ( nodeState );
 
1332
            }
 
1333
 
 
1334
            // Disable the morph controllers
 
1335
            for ( uint j=0; j<item->morphControllerNodes.length(); ++j )
 
1336
            {
 
1337
                int nodeState;
 
1338
                DagHelper::getPlugValue ( item->morphControllerNodes[j], ATTR_NODE_STATE, nodeState );
 
1339
                DagHelper::setPlugValue ( item->morphControllerNodes[j], ATTR_NODE_STATE, 1 ); // pass-through.
 
1340
                item->nodeStates.push_back( nodeState );
 
1341
            }
 
1342
        }
 
1343
    }
 
1344
 
 
1345
    //------------------------------------------------------
 
1346
    void ControllerExporter::resetControllerNodeStates( ControllerStack &stack )
 
1347
    {
 
1348
        // Reset all the controller node states
 
1349
        for ( size_t i=0; i<stack.size(); ++i )
 
1350
        {
 
1351
            ControllerStackItem* item = stack[i];
 
1352
            if ( item->isSkin )
 
1353
            {
 
1354
                // Reset the skin controller node state.
 
1355
                size_t nodeStateSize = item->nodeStates.size();
 
1356
                                COLLADABU_ASSERT ( nodeStateSize >= 1 );
 
1357
                int nodeState = item->nodeStates.front();
 
1358
                DagHelper::setPlugValue ( item->skinControllerNode, ATTR_NODE_STATE, nodeState );
 
1359
 
 
1360
                // Maybe there are some morph controllers to reset.
 
1361
                for ( uint i=0; i<item->morphControllerNodes.length(); ++i )
 
1362
                {
 
1363
                    COLLADABU_ASSERT ( nodeStateSize < i+1 );
 
1364
                    nodeState = item->nodeStates[i+1];
 
1365
                    DagHelper::setPlugValue ( item->morphControllerNodes[i], ATTR_NODE_STATE, nodeState );
 
1366
                }
 
1367
            }
 
1368
            else
 
1369
            {
 
1370
                // Reset the morph controller node states.
 
1371
                size_t nodeStateSize = item->nodeStates.size();
 
1372
                for ( uint j=0; j<item->morphControllerNodes.length(); ++j )
 
1373
                {
 
1374
                    COLLADABU_ASSERT ( nodeStateSize >= j );
 
1375
                    int nodeState = item->nodeStates[j];
 
1376
                    DagHelper::setPlugValue ( item->morphControllerNodes[j], ATTR_NODE_STATE, nodeState );
 
1377
                }
 
1378
            }
 
1379
        }
 
1380
    }
 
1381
 
 
1382
    //------------------------------------------------------
 
1383
    void ControllerExporter::setValidMeshParameters( ControllerMeshStack &meshStack )
 
1384
    {
 
1385
        // Set valid mesh parameters (visible and not intermediate).
 
1386
        for ( size_t i=0; i<meshStack.size(); ++i )
 
1387
        {
 
1388
            ControllerMeshItem& item = meshStack[i];
 
1389
 
 
1390
            DagHelper::getPlugValue ( item.mesh, ATTR_INTERMEDIATE_OBJECT, item.isIntermediate );
 
1391
            DagHelper::getPlugValue ( item.mesh, ATTR_VISIBILITY, item.isVisible );
 
1392
            DagHelper::setPlugValue ( item.mesh, ATTR_INTERMEDIATE_OBJECT, false );
 
1393
            DagHelper::setPlugValue ( item.mesh, ATTR_VISIBILITY, true );
 
1394
        }
 
1395
    }
 
1396
 
 
1397
    //------------------------------------------------------
 
1398
    void ControllerExporter::resetMeshParameters( ControllerMeshStack &meshStack )
 
1399
    {
 
1400
        // Reset all the intermediate and visibility mesh parameters.
 
1401
        while ( !meshStack.empty() )
 
1402
        {
 
1403
            ControllerMeshItem& item = meshStack.back();
 
1404
 
 
1405
            DagHelper::setPlugValue ( item.mesh, ATTR_INTERMEDIATE_OBJECT, item.isIntermediate );
 
1406
            DagHelper::setPlugValue ( item.mesh, ATTR_VISIBILITY, item.isVisible );
 
1407
 
 
1408
            meshStack.pop_back();
 
1409
        }
 
1410
    }
 
1411
 
 
1412
    //------------------------------------------------------
 
1413
    void ControllerExporter::deleteControllerStackItems( ControllerStack &stack )
 
1414
    {
 
1415
        // Delete the controllerStack items
 
1416
        for ( size_t i=0; i<stack.size(); ++i )
 
1417
        {
 
1418
            ControllerStackItem* item = stack[i];
 
1419
            delete item;
 
1420
        }
 
1421
 
 
1422
        stack.clear();
 
1423
    }
 
1424
 
 
1425
    //------------------------------------------------------
 
1426
    bool ControllerExporter::findExportedContollerSceneElement ( const SceneElement* sceneElement )
 
1427
    {
 
1428
        std::vector<SceneElement*>::const_iterator it = mExportedControllerSceneElements.begin ();
 
1429
        while ( it != mExportedControllerSceneElements.end () )
 
1430
        {
 
1431
            if ( *it == sceneElement )
 
1432
                return true;
 
1433
            ++it;
 
1434
        }
 
1435
        return false;
 
1436
    }
 
1437
 
 
1438
    // ------------------------------------
 
1439
    const String ControllerExporter::findColladaControllerId ( const String& mayaControllerId )
 
1440
    {
 
1441
        const StringToStringMap::const_iterator it = mMayaIdColladaIdMap.find ( mayaControllerId );
 
1442
        if ( it != mMayaIdColladaIdMap.end () )
 
1443
        {
 
1444
            return it->second;
 
1445
        }
 
1446
        return EMPTY_STRING;
 
1447
    }
 
1448
 
 
1449
}
 
1450