2
Copyright (c) 2008-2009 NetAllied Systems GmbH
4
This file is part of COLLADAMaya.
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.
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
16
#include "COLLADAMayaStableHeaders.h"
17
#include "COLLADAMayaDocumentExporter.h"
18
#include "COLLADAMayaSceneGraph.h"
19
#include "COLLADAMayaGeometryExporter.h"
20
#include "COLLADAMayaVisualSceneExporter.h"
21
#include "COLLADAMayaEffectExporter.h"
22
#include "COLLADAMayaImageExporter.h"
23
#include "COLLADAMayaMaterialExporter.h"
24
#include "COLLADAMayaAnimationExporter.h"
25
#include "COLLADAMayaAnimationClipExporter.h"
26
#include "COLLADAMayaAnimationSampleCache.h"
27
#include "COLLADAMayaControllerExporter.h"
28
#include "COLLADAMayaLightExporter.h"
29
#include "COLLADAMayaCameraExporter.h"
30
#include "COLLADAMayaDagHelper.h"
31
#include "COLLADAMayaShaderHelper.h"
32
#include "COLLADAMayaConversion.h"
33
#include "COLLADAMayaExportOptions.h"
34
#include "COLLADAMayaSyntax.h"
35
#include "COLLADAMayaReferenceManager.h"
37
#include "COLLADASWAsset.h"
38
#include "COLLADASWScene.h"
39
#include "COLLADASWConstants.h"
41
#include <maya/MFileIO.h>
42
#include <maya/MFnAttribute.h>
48
//---------------------------------------------------------------
49
DocumentExporter::DocumentExporter ( const NativeString& fileName )
50
: mStreamWriter ( fileName, ExportOptions::doublePrecision () )
51
, mFileName ( fileName )
52
, mSceneGraph ( NULL )
54
, mAnimationCache ( NULL )
55
, mMaterialExporter ( NULL )
56
, mEffectExporter ( NULL )
57
, mImageExporter ( NULL )
58
, mGeometryExporter ( NULL )
59
, mVisualSceneExporter ( NULL )
60
, mAnimationExporter ( NULL )
61
, mAnimationClipExporter ( NULL )
62
, mControllerExporter ( NULL )
63
, mLightExporter ( NULL )
64
, mCameraExporter ( NULL )
65
, mSceneId ( "MayaScene" )
66
, mDigitTolerance (FLOAT_TOLERANCE)
68
if ( ExportOptions::doublePrecision () )
70
mDigitTolerance = DOUBLE_TOLERANCE;
74
//---------------------------------------------------------------
75
DocumentExporter::~DocumentExporter()
77
releaseLibraries(); // The libraries should already have been released
80
//---------------------------------------------------------------
81
// Create the parsing libraries: we want access to the libraries only during import/export time.
82
void DocumentExporter::createLibraries()
86
// Get the sceneID (assign a name to the scene)
88
MGlobal::executeCommand ( MString ( "file -q -ns" ), sceneName );
89
if ( sceneName.length() != 0 ) mSceneId = sceneName.asChar();
91
// Initialize the reference manager
92
ReferenceManager::getInstance()->initialize ();
94
// Create the cache for the animations
95
mAnimationCache = new AnimationSampleCache();
97
// Create the basic elements
98
mSceneGraph = new SceneGraph ( this );
99
mMaterialExporter = new MaterialExporter ( &mStreamWriter, this );
100
mEffectExporter = new EffectExporter ( &mStreamWriter, this );
101
mImageExporter = new ImageExporter ( &mStreamWriter );
102
mGeometryExporter = new GeometryExporter ( &mStreamWriter, this );
103
mVisualSceneExporter = new VisualSceneExporter ( &mStreamWriter, this, mSceneId );
104
mAnimationExporter = new AnimationExporter ( &mStreamWriter, this );
105
mAnimationClipExporter = new AnimationClipExporter ( &mStreamWriter );
106
mControllerExporter = new ControllerExporter ( &mStreamWriter, this );
107
mLightExporter = new LightExporter ( &mStreamWriter, this );
108
mCameraExporter = new CameraExporter ( &mStreamWriter, this );
111
//---------------------------------------------------------------
112
void DocumentExporter::releaseLibraries()
114
delete mAnimationCache;
116
delete mMaterialExporter;
117
delete mEffectExporter;
118
delete mImageExporter;
119
delete mGeometryExporter;
120
delete mVisualSceneExporter;
121
delete mAnimationExporter;
122
delete mAnimationClipExporter;
123
delete mControllerExporter;
124
delete mLightExporter;
125
delete mCameraExporter;
129
//---------------------------------------------------------------
130
void DocumentExporter::exportCurrentScene ( bool selectionOnly )
134
// Create the import/export library helpers.
137
mStreamWriter.startDocument();
139
// Build the scene graph
140
if ( mSceneGraph->create ( selectionOnly ) )
142
// Export the asset of the document.
145
if ( !ExportOptions::exportMaterialsOnly () )
147
// Start by caching the expressions that will be sampled
148
mSceneGraph->sampleAnimationExpressions();
150
// Export the lights.
151
mLightExporter->exportLights();
153
// Export the cameras.
154
mCameraExporter->exportCameras();
156
// Export the material URLs and get the material list
157
MaterialMap* materialMap = mMaterialExporter->exportMaterials();
159
// Export the effects (materials)
160
const ImageMap* imageMap = mEffectExporter->exportEffects ( materialMap );
163
mImageExporter->exportImages ( imageMap );
165
// Export the controllers. Must be done before the geometries, to decide, which
166
// geometries have to be exported (for example, if the controller need an invisible
167
// geometry, we also have to export it).
168
mControllerExporter->exportControllers();
170
// Export the geometries
171
mGeometryExporter->exportGeometries();
173
// Export the visual scene
174
bool visualSceneExported = mVisualSceneExporter->exportVisualScenes();
176
// Export the animations
177
const AnimationClipList* animationClips = mAnimationExporter->exportAnimations();
179
// Export the animation clips
180
mAnimationClipExporter->exportAnimationClips ( animationClips );
183
if ( visualSceneExported ) exportScene();
187
// Export the material URLs and get the material list
188
MaterialMap* materialMap = mMaterialExporter->exportMaterials();
190
// Export the effects (materials)
191
const ImageMap* imageMap = mEffectExporter->exportEffects ( materialMap );
194
mImageExporter->exportImages ( imageMap );
198
mStreamWriter.endDocument();
201
//---------------------------------------------------------------
202
void DocumentExporter::exportAsset()
204
COLLADASW::Asset asset ( &mStreamWriter );
206
// Add contributor information
208
char* userName = getenv ( USERNAME );
210
if ( !userName || *userName == 0 )
212
userName = getenv ( USER );
214
if ( userName && *userName != 0 )
216
asset.getContributor().mAuthor = NativeString( userName ).toUtf8String();
219
// Source is the scene we have exported from
220
String currentScene = MFileIO::currentFile().asChar();
221
if ( currentScene.size() > 0 )
223
COLLADASW::URI sourceFileUri ( COLLADASW::URI::nativePathToUri ( currentScene ) );
224
if ( sourceFileUri.getScheme ().empty () )
225
sourceFileUri.setScheme ( COLLADASW::URI::SCHEME_FILE );
226
asset.getContributor().mSourceData = sourceFileUri.getURIString();
229
asset.getContributor().mAuthoringTool = AUTHORING_TOOL_NAME + MGlobal::mayaVersion().asChar();
232
MString optstr = MString ( "\n\t\t\tColladaMaya export options: " )
233
+ "\n\t\t\tbakeTransforms=" + ExportOptions::bakeTransforms()
234
+ ";relativePaths=" + ExportOptions::relativePaths()
235
+ ";copyTextures=" + ExportOptions::copyTextures()
236
+ ";exportTriangles=" + ExportOptions::exportTriangles()
237
+ ";exportCgfxFileReferences=" + ExportOptions::exportCgfxFileReferences()
238
+ ";\n\t\t\tisSampling=" + ExportOptions::isSampling()
239
+ ";curveConstrainSampling=" + ExportOptions::curveConstrainSampling()
240
+ ";removeStaticCurves=" + ExportOptions::removeStaticCurves()
241
+ ";exportPolygonMeshes=" + ExportOptions::exportPolygonMeshes()
242
+ ";exportLights=" + ExportOptions::exportLights()
243
+ ";\n\t\t\texportCameras=" + ExportOptions::exportCameras()
244
+ ";exportJointsAndSkin=" + ExportOptions::exportJointsAndSkin()
245
+ ";exportAnimations=" + ExportOptions::exportAnimations()
246
+ ";exportInvisibleNodes=" + ExportOptions::exportInvisibleNodes()
247
+ ";exportDefaultCameras=" + ExportOptions::exportDefaultCameras()
248
+ ";\n\t\t\texportTexCoords=" + ExportOptions::exportTexCoords()
249
+ ";exportNormals=" + ExportOptions::exportNormals()
250
+ ";exportNormalsPerVertex=" + ExportOptions::exportNormalsPerVertex()
251
+ ";exportVertexColors=" + ExportOptions::exportVertexColors()
252
+ ";exportVertexColorsPerVertex=" + ExportOptions::exportVertexColorsPerVertex()
253
+ ";\n\t\t\texportTexTangents=" + ExportOptions::exportTexTangents()
254
+ ";exportTangents=" + ExportOptions::exportTangents()
255
+ ";exportReferencedMaterials=" + ExportOptions::exportReferencedMaterials()
256
+ ";exportMaterialsOnly=" + ExportOptions::exportMaterialsOnly()
257
+ ";\n\t\t\texportXRefs=" + ExportOptions::exportXRefs()
258
+ ";dereferenceXRefs=" + ExportOptions::dereferenceXRefs()
259
+ ";exportCameraAsLookat=" + ExportOptions::exportCameraAsLookat()
260
+ ";cameraXFov=" + ExportOptions::cameraXFov()
261
+ ";cameraYFov=" + ExportOptions::cameraYFov()
262
+ ";doublePrecision=" + ExportOptions::doublePrecision () + "\n\t\t";
263
asset.getContributor().mComments = optstr.asChar();
266
if ( MGlobal::isYAxisUp() )
267
asset.setUpAxisType ( COLLADASW::Asset::Y_UP );
268
else if ( MGlobal::isZAxisUp() )
269
asset.setUpAxisType ( COLLADASW::Asset::Z_UP );
271
// Retrieve the linear unit name
272
MString mayaLinearUnitName;
273
MGlobal::executeCommand ( "currentUnit -q -linear -fullName;", mayaLinearUnitName );
274
String linearUnitName = mayaLinearUnitName.asChar();
276
// Get the UI unit type (internal units are centimeter, collada want
277
// a number relative to meters).
278
// All transform components with units will be in maya's internal units
279
// (radians for rotations and centimeters for translations).
280
MDistance testDistance ( 1.0f, MDistance::uiUnit() );
282
// Get the conversion factor relative to meters for the collada document.
283
// For example, 1.0 for the name "meter"; 1000 for the name "kilometer";
284
// 0.3048 for the name "foot".
285
double colladaConversionFactor = ( float ) testDistance.as ( MDistance::kMeters );
286
float colladaUnitFactor = float ( 1.0 / colladaConversionFactor );
287
asset.setUnit ( linearUnitName, colladaConversionFactor );
289
// Asset heraus schreiben
293
//---------------------------------------------------------------
294
void DocumentExporter::exportScene()
296
COLLADASW::Scene scene ( &mStreamWriter, COLLADASW::URI ( EMPTY_STRING, VISUAL_SCENE_NODE_ID ) );
300
//---------------------------------------------------------------
301
void DocumentExporter::endExport()
303
// Write out the scene parameters
304
// CDOC->SetStartTime((float) AnimationHelper::AnimationStartTime().as(MTime::kSeconds));
305
// CDOC->SetEndTime((float) AnimationHelper::AnimationEndTime().as(MTime::kSeconds));
308
//---------------------------
309
String DocumentExporter::mayaNameToColladaName ( const MString& str, bool removeNamespace )
311
// Replace characters that are supported in Maya,
312
// but not supported in collada names
313
if ( str == 0 ) return EMPTY_STRING;
315
// NathanM: Strip off namespace prefixes
316
// TODO: Should really be exposed as an option in the Exporter
318
if ( removeNamespace )
320
int prefixIndex = str.rindex ( ':' );
321
mayaName = ( prefixIndex < 0 ) ? str : str.substring ( prefixIndex + 1, str.length() );
325
const char* c = mayaName.asChar();
326
uint length = mayaName.length();
327
char* buffer = new char[length+1];
329
// Replace offending characters by some that are supported within xml:
330
// ':', '|' are replaced by '_'.
331
// Ideally, these should be encoded as '%3A' for ':', etc. and decoded at import time.
333
for ( uint i = 0; i < length; ++i )
337
if ( d == '|' || d == ':' || d == '/' || d == '\\' || d == '(' || d == ')' || d == '[' || d == ']' )
342
buffer[length] = '\0';
344
MString mayaReturnString ( buffer );
347
return COLLADABU::Utils::checkNCName( mayaReturnString.asChar() );
350
//---------------------------
351
String DocumentExporter::dagPathToColladaId ( const MDagPath& dagPath )
353
// Make an unique COLLADA Id from a dagPath.
354
// We are free to use anything we want for Ids. For now use
355
// a honking unique name for readability - but in future we
356
// could just use an incrementing integer
357
return mayaNameToColladaName ( dagPath.partialPathName(), false );
360
//---------------------------
361
String DocumentExporter::dagPathToColladaName ( const MDagPath& dagPath )
363
// Get a COLLADA suitable node name from a DAG path
364
// For import/export symmetry, this should be exactly the
365
// Maya node name. If we include any more of the path, we'll
366
// get viral node names after repeated import/export.
367
MFnDependencyNode node ( dagPath.node() );
368
return mayaNameToColladaName ( node.name(), true );
371
//---------------------------
372
SceneGraph* DocumentExporter::getSceneGraph()
377
//---------------------------
378
const SceneGraph* DocumentExporter::getSceneGraph() const
383
//---------------------------
384
const String& DocumentExporter::getFilename() const
389
//---------------------------
390
COLLADASW::StreamWriter* DocumentExporter::getStreamWriter()
392
return &mStreamWriter;
395
//---------------------------
396
AnimationSampleCache* DocumentExporter::getAnimationCache()
398
return mAnimationCache;
401
//---------------------------
402
MaterialExporter* DocumentExporter::getMaterialExporter()
404
return mMaterialExporter;
407
//---------------------------
408
EffectExporter* DocumentExporter::getEffectExporter()
410
return mEffectExporter;
413
//---------------------------
414
ImageExporter* DocumentExporter::getImageExporter()
416
return mImageExporter;
419
//---------------------------
420
GeometryExporter* DocumentExporter::getGeometryExporter()
422
return mGeometryExporter;
425
//---------------------------
426
VisualSceneExporter* DocumentExporter::getVisualSceneExporter()
428
return mVisualSceneExporter;
431
//---------------------------
432
AnimationExporter* DocumentExporter::getAnimationExporter()
434
return mAnimationExporter;
437
//---------------------------
438
AnimationClipExporter* DocumentExporter::getAnimationClipExporter()
440
return mAnimationClipExporter;
443
//---------------------------
444
ControllerExporter* DocumentExporter::getControllerExporter()
446
return mControllerExporter;
449
//---------------------------
450
LightExporter* DocumentExporter::getLightExporter()
452
return mLightExporter;
455
//---------------------------
456
CameraExporter* DocumentExporter::getCameraExporter()
458
return mCameraExporter;
461
//---------------------------
462
const String& DocumentExporter::getSceneID()
467
//---------------------------
468
const bool DocumentExporter::getExportSelectedOnly () const
470
return getSceneGraph ()->getExportSelectedOnly ();
473
// // --------------------------------------
474
// void DocumentExporter::exportExtraData (
475
// const MObject& node,
477
// const char* secondKey /*= 0*/,
478
// COLLADASW::BaseExtraTechnique* baseExtraTechnique /*= 0*/ )
481
// MFnDependencyNode dependencyNode ( node, &status );
482
// if ( status != MStatus::kSuccess ) return;
484
// MPlug colladaPlug = dependencyNode.findPlug ( COLLADAFW::ExtraKeys::BASEKEY, &status );
485
// if ( status == MStatus::kSuccess )
487
// if ( !colladaPlug.isCompound () )
489
// std::cerr << "There exist another attribute with the name \"COLLADA\". No extra tag preservation possible!" << endl;
493
// // Flag, if the extra source was opened.
494
// bool closeExtraSource = false;
495
// COLLADASW::Extra extraSource ( &mStreamWriter );
497
// size_t numChildren = colladaPlug.numChildren ();
498
// for ( uint i=0; i<numChildren; ++i )
500
// MPlug childPlug = colladaPlug.child ( i, &status );
501
// if ( status != MStatus::kSuccess ) continue;
503
// // Get the collada attribute.
504
// MFnAttribute pathAttribute ( childPlug.attribute() );
505
// String pathAttributeName = pathAttribute.name().asChar ();
506
// if ( !COLLADABU::Utils::equals ( pathAttributeName, key ) ) continue;
508
// if ( exportExtraData ( childPlug, pathAttributeName, baseExtraTechnique, extraSource, secondKey ) )
509
// closeExtraSource = true;
512
// // Close the extra source tag, if it is open.
513
// if ( closeExtraSource )
514
// extraSource.closeExtra();
518
// // --------------------------------------
519
// bool DocumentExporter::exportExtraData (
520
// const MPlug& childPlug,
521
// const String& parentAttributeName,
522
// COLLADASW::BaseExtraTechnique* baseExtraTechnique,
523
// COLLADASW::Extra& extraSource,
524
// const char* secondKey /*= 0*/ )
527
// bool closeExtraSource = false;
529
// // Get the profile name of the child attribute.
530
// size_t numExtraChildren = childPlug.numChildren ();
531
// for ( uint i=0; i<numExtraChildren; ++i )
533
// // Get the extra plug.
534
// MPlug extraPlug = childPlug.child ( i, &status );
535
// if ( status != MStatus::kSuccess ) continue;
536
// MFnAttribute extraAttribute ( extraPlug.attribute() );
538
// // Check if we have an extra tag of an physical index element (primitive element,
539
// // surface, sampler2d or texture). In this case, the current attribute is a compound
540
// // attribute and holds for every index a child element.
541
// if ( extraPlug.isCompound () )
543
// // TODO Recursive call for the child plugs.
544
// String attributeName = extraAttribute.name ().asChar ();
545
// if ( !COLLADABU::Utils::equals ( attributeName, secondKey ) ) continue;
546
// if ( exportExtraData ( extraPlug, attributeName, baseExtraTechnique, extraSource, secondKey ) )
547
// closeExtraSource = true;
553
// // Get the physical index of the element.
554
// String physicalIndexStr = parentAttributeName.substr ( parentAttributeName.length ()-1 );
555
// unsigned int physicalIndex = atoi ( physicalIndexStr.c_str () );
558
// // The attribute with the collada profile name.
559
// // The profile name has always the path attribute name in front.
560
// String profileName = extraAttribute.name ().asChar ();
561
// profileName = profileName.substr ( parentAttributeName.length () + 1 );
563
// // The attribute value.
564
// MString mAttributeValue;
565
// status = extraPlug.getValue ( mAttributeValue );
566
// if ( status != MStatus::kSuccess || mAttributeValue == 0 ) continue;
568
// // Convert the attributeValue back to collada.
569
// String source = mAttributeValue.asChar ();
570
// COLLADABU::Utils::stringFindAndReplace ( source, "\\\"", "\"" );
571
// String encodedSource = COLLADABU::URI::uriDecode ( source );
573
// // If a baseExtraTechnique element is given, use this to write the extra data.
574
// if ( baseExtraTechnique )
575
// baseExtraTechnique->addExtraTechniqueTextblock ( profileName, encodedSource );
578
// // Open the extra source tag, if neccessary.
579
// if ( !closeExtraSource )
581
// extraSource.openExtra();
582
// closeExtraSource = true;
584
// // Create the extra attribute.
585
// COLLADASW::Technique techniqueSource ( &mStreamWriter );
586
// techniqueSource.openTechnique ( profileName );
587
// techniqueSource.addValue ( encodedSource );
588
// techniqueSource.closeTechnique();
592
// return closeExtraSource;