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 "COLLADAMayaMaterialExporter.h"
18 #include "COLLADAMayaEffectExporter.h"
19 #include "COLLADAMayaSceneGraph.h"
20 #include "COLLADAMayaDagHelper.h"
21 #include "COLLADAMayaShaderHelper.h"
22 #include "COLLADAMayaSyntax.h"
23 #include "COLLADAMayaConversion.h"
24 #include "COLLADAMayaExportOptions.h"
25 #include "COLLADAMayaHwShaderExporter.h"
26 
27 #include "COLLADASWNode.h"
28 #include "COLLADASWParamTemplate.h"
29 #include "COLLADASWConstants.h"
30 
31 
32 #include <maya/MItMeshPolygon.h>
33 #include <maya/MItDag.h>
34 #include <maya/MFnSet.h>
35 #include <maya/MFnMesh.h>
36 
37 #if defined(WIN64) && MAYA_API_VERSION >= 201600 && !defined(WIN32)
38 /* define WIN32 to work around CFGX WIN64 compilation */
39 #define WIN32
40 #endif
41 
42 #include "cgfxShaderNode.h"
43 
44 #include <cgfxFindImage.h>
45 
46 namespace COLLADAMaya
47 {
48 
49 	MaterialExporter::SidSet MaterialExporter::mSurfaceSidList;
50 
51     //---------------------------------------------------------------
MaterialExporter(COLLADASW::StreamWriter * streamWriter,DocumentExporter * documentExporter)52     MaterialExporter::MaterialExporter ( COLLADASW::StreamWriter* streamWriter,
53                                          DocumentExporter* documentExporter )
54             : COLLADASW::LibraryMaterials ( streamWriter ),
55             mDocumentExporter ( documentExporter ),
56             mExportedMaterials ( NULL ),
57             mWriteMaterials ( false ),
58             materialMapInitialized ( false )
59     {}
60 
61     //---------------------------------------------------------------
exportMaterials(bool writeMaterials)62     MaterialMap* MaterialExporter::exportMaterials ( bool writeMaterials )
63     {
64         mWriteMaterials = writeMaterials;
65 
66         // Should we only export the selected elements?
67         bool exportSelectedOnly = mDocumentExporter->getExportSelectedOnly ();
68 
69         // Should we only export the referenced (used) materials?
70         bool exportReferencedOnly = ExportOptions::exportReferencedMaterials ();
71 
72         if ( !exportSelectedOnly && !exportReferencedOnly )
73         {
74             // Get all shaders, which are in the default shader list.
75             // Unfortunately, you will not get the default initialShadingGroup elements, which are
76             // directly connected to an object, if no other material (shader) is connected to the object.
77             exportMaterialsByShaderPlug ();
78         }
79 
80         // Now go through scene graph and find all shaders, connected to the meshes.
81         // So you can find the default shaders of an object.
82         exportMaterialsBySceneGraph ();
83 
84         // Set the flag, that the material std::map is initialised
85         materialMapInitialized = true;
86 
87         // Close the tags in the collada document
88         closeLibrary();
89 
90         // Return the material list
91         return &mMaterialMap;
92     }
93 
94     //------------------------------------------------------
exportMaterialsByShaderPlug()95     void MaterialExporter::exportMaterialsByShaderPlug()
96     {
97         // Get all shaders, which are in the default shader list.
98         MObject defaultShaderList = DagHelper::getNode ( ATTR_DEFAULT_SHADER_LIST1 );
99         MPlug defaultShadersPlug = MFnDependencyNode ( defaultShaderList ).findPlug ( ATTR_SHADERS );
100 
101         uint shaderCount = defaultShadersPlug.evaluateNumElements();
102         for ( uint i = 0; i < shaderCount; ++i )
103         {
104             MObject shader = DagHelper::getNodeConnectedTo ( defaultShadersPlug.elementByPhysicalIndex ( i ) );
105             MFnDependencyNode shadingEngineFn ( shader );
106 
107             // Get the name of the current material (this is the maya material id)
108             String mayaMaterialId = DocumentExporter::mayaNameToColladaName ( shadingEngineFn.name(), true );
109 
110             bool doExportMaterial = true;
111             bool isFromReferencedFile = shadingEngineFn.isFromReferencedFile();
112 //            bool isDefaulNode = shadingEngineFn.isDefaultNode();
113 //             if ( isDefaulNode )
114 //             {
115 //                 doExportMaterial = false;
116 //             }
117 //             else if ( isFromReferencedFile )
118             if ( isFromReferencedFile )
119             {
120                 if ( ExportOptions::exportXRefs() && ExportOptions::dereferenceXRefs() ) doExportMaterial = true;
121                 else doExportMaterial = false;
122             }
123 
124             if ( doExportMaterial )
125             {
126                 MObject shadingEngine = ShaderHelper::getShadingEngine ( shader );
127                 exportMaterial ( shadingEngine );
128             }
129         }
130     }
131 
132     //------------------------------------------------------
exportMaterialsBySceneGraph()133     void MaterialExporter::exportMaterialsBySceneGraph ()
134     {
135         // Get the list with the transform nodes.
136         SceneGraph* sceneGraph = mDocumentExporter->getSceneGraph();
137         SceneElementsList* exportNodesTree = sceneGraph->getExportNodesTree();
138 
139         // Now go through scene graph and find all shaders, connected to the meshes.
140         // So you can find the default shaders of an object.
141         size_t length = exportNodesTree->size();
142         for ( size_t i = 0; i < length; ++i )
143         {
144             SceneElement* sceneElement = ( *exportNodesTree ) [i];
145             if ( !sceneElement->getIsLocal() ) continue;
146             if ( !sceneElement->getIsExportNode () ) continue;
147 
148             size_t childCount = sceneElement->getChildCount();
149             for ( size_t i=0; i<childCount; ++i )
150             {
151                 SceneElement* childSceneElement = sceneElement->getChild ( i );
152 
153                 exportConnectedMaterials ( childSceneElement );
154             }
155         }
156     }
157 
158     //------------------------------
exportConnectedMaterials(SceneElement * sceneElement)159     void MaterialExporter::exportConnectedMaterials ( SceneElement* sceneElement )
160     {
161         // If we have a external reference, we don't need to export the data here.
162         if ( !sceneElement->getIsLocal() ) return;
163         if ( !sceneElement->getIsExportNode () ) return;
164 
165         // Check if it is a mesh object and an export node
166         if ( sceneElement->getType() == SceneElement::MESH )
167         {
168             MDagPath dagPath = sceneElement->getPath();
169 
170             // Attach a function set
171             MStatus status;
172             MFnMesh fnMesh ( dagPath.node(), &status );
173             if ( status != MStatus::kSuccess ) return;
174 
175             // Find how many shaders are used by this instance of the mesh
176             MObjectArray shaders;
177             MIntArray shaderIndices;
178             unsigned instanceNumber = dagPath.instanceNumber();
179             fnMesh.getConnectedShaders ( instanceNumber, shaders, shaderIndices );
180 
181             // Find the polygons that correspond to each materials and export them
182             uint realShaderCount = ( uint ) shaders.length();
183             uint numShaders = ( uint ) std::max ( ( size_t ) 1, ( size_t ) shaders.length() );
184             for ( uint shaderPosition = 0; shaderPosition < numShaders; ++shaderPosition )
185             {
186                 if ( shaderPosition < realShaderCount )
187                 {
188                     // Add shader-specific parameters (TexCoords sets).
189                     // Add symbolic name for the material used on this polygon set.
190                     MObject shadingEngine = shaders[shaderPosition];
191                     exportMaterial ( shadingEngine );
192                 }
193             }
194         }
195 
196         // recursive call for all the child elements
197         for ( uint i=0; i<sceneElement->getChildCount(); ++i )
198         {
199             SceneElement* childElement = sceneElement->getChild ( i );
200             exportConnectedMaterials ( childElement );
201         }
202     }
203 
204     //--------------------------------
exportMaterial(MObject shadingEngine)205     void MaterialExporter::exportMaterial ( MObject shadingEngine )
206     {
207         // Get the shader object.
208         MObject shader = DagHelper::getSourceNodeConnectedTo ( shadingEngine, ATTR_SURFACE_SHADER );
209 
210         // Find the actual shader node, since this function received shading sets as input
211         MStatus status;
212         MFnDependencyNode shaderNode ( shader, &status );
213         if ( status != MStatus::kSuccess ) return;
214 
215         // Get the name of the current material (this is the maya material id)
216         String mayaMaterialId = DocumentExporter::mayaNameToColladaName ( shaderNode.name(), true );
217 
218         // Have we seen this shader before, is it already exported?
219         MaterialMap::iterator materialMapIter;
220         materialMapIter = mMaterialMap.find ( mayaMaterialId );
221         if ( materialMapIter != mMaterialMap.end() ) return;
222 
223         // This is a new shading engine
224         mMaterialMap [mayaMaterialId] = shader;
225 
226         // Generate a COLLADA id for the new object
227         String colladaMaterialId;
228 
229         // Check if there is an extra attribute "colladaId" and use this as export id.
230         MString attributeValue;
231         DagHelper::getPlugValue ( shader, COLLADA_MATERIAL_ID_ATTRIBUTE_NAME, attributeValue );
232         if ( attributeValue != EMPTY_CSTRING )
233         {
234             // Generate a valid collada name, if necessary.
235             colladaMaterialId = DocumentExporter::mayaNameToColladaName ( attributeValue, false );
236         }
237         else
238         {
239             // Generate a COLLADA id for the new object
240             colladaMaterialId = DocumentExporter::mayaNameToColladaName ( shaderNode.name(), true );
241         }
242         // Make the id unique and store it.
243         colladaMaterialId = mMaterialIdList.addId ( colladaMaterialId );
244         mMayaIdColladaMaterialIdMap [mayaMaterialId] = colladaMaterialId;
245 
246 //         MFnDependencyNode shadingEngineNode ( shadingEngine, &status );
247 //         if ( status != MStatus::kSuccess ) return;
248 //         String shadingEngineNodeName = shadingEngineNode.name ().asChar (); // initialParticleSE
249 //         String shaderNodeName = shaderNode.name ().asChar (); // lambert1
250 
251         // Check if the material should be written
252         if ( mWriteMaterials )
253         {
254             // Have we exported this shader already?
255             std::vector<String>::iterator exportedMaterialsIter;
256             exportedMaterialsIter = find ( mExportedMaterials.begin(), mExportedMaterials.end(), colladaMaterialId );
257 
258             if ( exportedMaterialsIter == mExportedMaterials.end() )
259             {
260                 // Open a tag for the current material in the collada document
261                 openMaterial ( colladaMaterialId, mayaMaterialId );
262 
263                 // Export the reference to the effect and the hardware shader components.
264                 exportEffectInstance ( mayaMaterialId, colladaMaterialId, shader );
265 
266 //                 // TODO Export the user defined material extra data from import (extra preservation).
267 //                 mDocumentExporter->exportExtraData ( shader, COLLADAFW::ExtraKeys::MATERIAL );
268 
269                 // Closes the current effect tag
270                 closeMaterial();
271 
272                 // Push the id of the exported material into the list for the exported materials
273                 mExportedMaterials.push_back ( colladaMaterialId );
274             }
275         }
276     }
277 
278     //---------------------------------------
getExportedMaterialsMap()279     MaterialMap* MaterialExporter::getExportedMaterialsMap()
280     {
281         if ( !materialMapInitialized ) exportMaterials ( false );
282 
283         return &mMaterialMap;
284     }
285 
286     //---------------------------------------
setSetParam(const cgfxShaderNode * shaderNodeCgfx,const cgfxAttrDef * attribute)287     void MaterialExporter::setSetParam ( const cgfxShaderNode* shaderNodeCgfx, const cgfxAttrDef* attribute )
288     {
289         COLLADASW::StreamWriter* streamWriter = mDocumentExporter->getStreamWriter();
290         String attributeName = attribute->fName.asChar();
291 
292         cgfxAttrDef::cgfxAttrType attributeType = attribute->fType;
293         switch ( attributeType )
294         {
295         case cgfxAttrDef::kAttrTypeBool:
296             {
297 				if (attribute->fNumericDef)
298 				{
299 					COLLADASW::SetParamBool setParam ( streamWriter );
300 					setParam.openParam ( attributeName );
301 					setParam.appendValues ( attribute->fNumericDef[0] != 0.0 );
302 					setParam.closeParam ();
303 				}
304                 break;
305             }
306         case cgfxAttrDef::kAttrTypeInt:
307             {
308 				if (attribute->fNumericDef)
309 				{
310 					COLLADASW::SetParamInt setParam(streamWriter);
311 					setParam.openParam(attributeName);
312 					setParam.appendValues(static_cast<int>(attribute->fNumericDef[0]));
313 					setParam.closeParam();
314 				}
315                 break;
316             }
317         case cgfxAttrDef::kAttrTypeString:
318             {
319 				MGlobal::displayWarning(("CG String Parameter type: ") + MString(attributeName.c_str()) + MString(" not supported!")  );
320 
321 				/*
322 				if (attribute->fStringDef.length() > 0)
323 				{
324 					COLLADASW::SetParamString setParam(streamWriter);
325 					setParam.openParam(attributeName);
326 					setParam.appendValues(String(attribute->fStringDef.asChar()));
327 					setParam.closeParam();
328 				}
329                 break;
330 				*/
331             }
332         case cgfxAttrDef::kAttrTypeFloat:
333             {
334 				if (attribute->fNumericDef)
335 				{
336 					COLLADASW::SetParamFloat setParam(streamWriter);
337 					setParam.openParam(attributeName);
338 					setParam.appendValues(attribute->fNumericDef[0]);
339 					setParam.closeParam();
340 				}
341                 break;
342             }
343         case cgfxAttrDef::kAttrTypeVector2:
344             {
345 				if (attribute->fNumericDef)
346 				{
347 					COLLADASW::SetParamFloat2 setParam(streamWriter);
348 					setParam.openParam(attributeName);
349 					for (int i = 0; i < attribute->fSize; ++i)
350 					{
351 						setParam.appendValues(attribute->fNumericDef[i]);
352 					}
353 					setParam.closeParam();
354 				}
355                 break;
356             }
357         case cgfxAttrDef::kAttrTypeVector3:
358         case cgfxAttrDef::kAttrTypeColor3:
359             {
360 				if (attribute->fNumericDef)
361 				{
362 					COLLADASW::SetParamFloat3 setParam ( streamWriter );
363 					setParam.openParam ( attributeName );
364 					for ( int i=0; i<attribute->fSize; ++i )
365 					{
366 						setParam.appendValues(attribute->fNumericDef[i]);
367 					}
368 					setParam.closeParam();
369 				}
370                 break;
371             }
372         case cgfxAttrDef::kAttrTypeVector4:
373         case cgfxAttrDef::kAttrTypeColor4:
374             {
375 				if (attribute->fNumericDef)
376 				{
377 					COLLADASW::SetParamFloat4 setParam(streamWriter);
378 					setParam.openParam(attributeName);
379 					for (int i = 0; i < attribute->fSize; ++i)
380 					{
381 						setParam.appendValues(attribute->fNumericDef[i]);
382 					}
383 					setParam.closeParam();
384 				}
385                 break;
386             }
387         case cgfxAttrDef::kAttrTypeWorldDir:
388         case cgfxAttrDef::kAttrTypeWorldPos:
389             {
390 				if (attribute->fNumericDef)
391 				{
392 					// Read the value
393 					double tmp[4];
394 					for (int i = 0; i < attribute->fSize; ++i)
395 					{
396 						tmp[i] = attribute->fNumericDef[i];
397 					}
398 					if (attribute->fSize == 3) tmp[3] = 1.0;
399 
400 					// Find the coordinate space, and whether it is a point or a vector
401 					int base = cgfxAttrDef::kAttrTypeFirstPos;
402 					if (attribute->fType <= cgfxAttrDef::kAttrTypeLastDir)
403 						base = cgfxAttrDef::kAttrTypeFirstDir;
404 					int space = attribute->fType - base;
405 
406 					// Compute the transform matrix
407 					MMatrix mat;
408 					switch (space)
409 					{
410 						/* case 0:	object space, handled in view dependent method */
411 					case 1:	/* world space  - do nothing, identity */ break;
412 						/* case 2: eye space, unsupported yet */
413 						/* case 3: clip space, unsupported yet */
414 						/* case 4: screen space, unsupported yet */
415 					}
416 
417 					if (base == cgfxAttrDef::kAttrTypeFirstPos)
418 					{
419 						MPoint point(tmp[0], tmp[1], tmp[2], tmp[3]);
420 						point *= mat;
421 						tmp[0] = point.x;
422 						tmp[1] = point.y;
423 						tmp[2] = point.z;
424 						tmp[3] = point.w;
425 					}
426 					else
427 					{
428 						MVector vec(tmp[0], tmp[1], tmp[2]);
429 						vec *= mat;
430 						tmp[0] = vec.x;
431 						tmp[1] = vec.y;
432 						tmp[2] = vec.z;
433 						tmp[3] = 1;
434 					}
435 
436 					COLLADASW::SetParamFloat4 setParam(streamWriter);
437 					setParam.openParam(attributeName);
438 					setParam.appendValues(tmp[0], tmp[1], tmp[2], tmp[3]);
439 					setParam.closeParam();
440 				}
441                 break;
442             }
443         case cgfxAttrDef::kAttrTypeMatrix:
444         case cgfxAttrDef::kAttrTypeWorldMatrix:
445         case cgfxAttrDef::kAttrTypeViewMatrix:
446         case cgfxAttrDef::kAttrTypeProjectionMatrix:
447         case cgfxAttrDef::kAttrTypeWorldViewMatrix:
448         case cgfxAttrDef::kAttrTypeWorldViewProjectionMatrix:
449             {
450 				if (attribute->fNumericDef)
451 				{
452 					COLLADASW::SetParamFloat4x4 setParam(streamWriter);
453 					setParam.openParam(attributeName);
454 
455 					MMatrix mayaMatrix;
456 					double* p = &mayaMatrix.matrix[0][0];
457 					for (int k = 0; k < attribute->fSize; ++k)
458 					{
459 						p[k] = attribute->fNumericDef[k];
460 					}
461 
462 					MMatrix wMatrix, vMatrix, pMatrix, sMatrix;
463 					MMatrix wvMatrix, wvpMatrix, wvpsMatrix;
464 					{
465 						float tmp[4][4];
466 
467 						wMatrix.setToIdentity();
468 
469 						glGetFloatv(GL_MODELVIEW_MATRIX, &tmp[0][0]);
470 						wvMatrix = MMatrix(tmp);
471 
472 						vMatrix = wMatrix.inverse() * wvMatrix;
473 
474 						glGetFloatv(GL_PROJECTION_MATRIX, &tmp[0][0]);
475 						pMatrix = MMatrix(tmp);
476 
477 						wvpMatrix = wvMatrix * pMatrix;
478 
479 						float vpt[4];
480 						float depth[2];
481 
482 						glGetFloatv(GL_VIEWPORT, vpt);
483 						glGetFloatv(GL_DEPTH_RANGE, depth);
484 
485 						// Construct the NDC -> screen space matrix
486 						//
487 						float x0, y0, z0, w, h, d;
488 
489 						x0 = vpt[0];
490 						y0 = vpt[1];
491 						z0 = depth[0];
492 						w = vpt[2];
493 						h = vpt[3];
494 						d = depth[1] - z0;
495 
496 						// Make a reference to ease the typing
497 						//
498 						double* s = &sMatrix.matrix[0][0];
499 
500 						s[0] = w / 2;	s[1] = 0.0;	s[2] = 0.0;	s[3] = 0.0;
501 						s[4] = 0.0;	s[5] = h / 2;	s[6] = 0.0;	s[7] = 0.0;
502 						s[8] = 0.0;	s[9] = 0.0;	s[10] = d / 2;	s[11] = 0.0;
503 						s[12] = x0 + w / 2;	s[13] = y0 + h / 2;	s[14] = z0 + d / 2;	s[15] = 1.0;
504 
505 						wvpsMatrix = wvpMatrix * sMatrix;
506 					}
507 
508 					switch (attribute->fType)
509 					{
510 					case cgfxAttrDef::kAttrTypeWorldMatrix:
511 						mayaMatrix = wMatrix; break;
512 					case cgfxAttrDef::kAttrTypeViewMatrix:
513 						mayaMatrix = vMatrix; break;
514 					case cgfxAttrDef::kAttrTypeProjectionMatrix:
515 						mayaMatrix = pMatrix; break;
516 					case cgfxAttrDef::kAttrTypeWorldViewMatrix:
517 						mayaMatrix = wvMatrix; break;
518 					case cgfxAttrDef::kAttrTypeWorldViewProjectionMatrix:
519 						mayaMatrix = wvpMatrix; break;
520 					default:
521 						break;
522 					}
523 
524 					if (attribute->fInvertMatrix)
525 						mayaMatrix = mayaMatrix.inverse();
526 
527 					if (!attribute->fTransposeMatrix)
528 						mayaMatrix = mayaMatrix.transpose();
529 
530 					double matrix[4][4];
531 					convertMayaMatrixToTransposedDouble4x4(matrix, mayaMatrix, getTolerance());
532 					setParam.appendValues(matrix);
533 					setParam.closeParam();
534 				}
535                 break;
536             }
537         case cgfxAttrDef::kAttrTypeColor1DTexture:
538         case cgfxAttrDef::kAttrTypeColor2DTexture:
539         case cgfxAttrDef::kAttrTypeColor3DTexture:
540         case cgfxAttrDef::kAttrTypeColor2DRectTexture:
541         case cgfxAttrDef::kAttrTypeNormalTexture:
542         case cgfxAttrDef::kAttrTypeBumpTexture:
543         case cgfxAttrDef::kAttrTypeCubeTexture:
544         case cgfxAttrDef::kAttrTypeEnvTexture:
545         case cgfxAttrDef::kAttrTypeNormalizationTexture:
546             {
547                 CGparameter cgParameter = attribute->fParameterHandle;
548                 HwShaderExporter hwShaderExporter ( mDocumentExporter );
549                 hwShaderExporter.setShaderFxFileUri ( getShaderFxFileUri () );
550 
551                 MObject shaderNode = shaderNodeCgfx->thisMObject();
552                 hwShaderExporter.exportSampler ( shaderNode, cgParameter, false );
553 
554 
555                 // -------------------------------
556 //                 String imageName = attribute->fStringDef.asChar();
557 //
558 //                 MObject oNode = shaderNodeCgfx->thisMObject();
559 //                 MFnDependencyNode oNodeFn ( oNode );
560 //                 String oNodeName = oNodeFn.name().asChar(); // cgfxShader1
561 //
562 //                 MPlug plug;
563 //                 if ( DagHelper::getPlugConnectedTo( oNode, attributeName, plug ) )
564 //                 {
565 //                     String plugName = plug.name().asChar(); // file1.outColor
566 //                     MObject textureNode = plug.node();
567 //
568 //                     //COLLADASW::Surface::SurfaceType surfaceType;
569 //                     COLLADASW::Sampler::SamplerType samplerType;
570 //                     COLLADASW::ValueType::ColladaType samplerValueType;
571 //
572 //                     switch ( attributeType )
573 //                     {
574 //                     case cgfxAttrDef::kAttrTypeColor1DTexture:
575 //                         //surfaceType = COLLADASW::Surface::SURFACE_TYPE_1D;
576 //                         samplerType = COLLADASW::Sampler::SAMPLER_TYPE_1D;
577 //                         samplerValueType = COLLADASW::ValueType::SAMPLER_1D;
578 //                         break;
579 //                     case cgfxAttrDef::kAttrTypeColor2DTexture:
580 //                     case cgfxAttrDef::kAttrTypeNormalTexture:
581 //                     case cgfxAttrDef::kAttrTypeBumpTexture:
582 //                         //surfaceType = COLLADASW::Surface::SURFACE_TYPE_2D;
583 //                         samplerType = COLLADASW::Sampler::SAMPLER_TYPE_2D;
584 //                         samplerValueType = COLLADASW::ValueType::SAMPLER_2D;
585 //                         break;
586 //                     case cgfxAttrDef::kAttrTypeColor3DTexture:
587 //                         //surfaceType = COLLADASW::Surface::SURFACE_TYPE_3D;
588 //                         samplerType = COLLADASW::Sampler::SAMPLER_TYPE_3D;
589 //                         samplerValueType = COLLADASW::ValueType::SAMPLER_3D;
590 //                         break;
591 //                     case cgfxAttrDef::kAttrTypeColor2DRectTexture:
592 //                         //surfaceType = COLLADASW::Surface::SURFACE_TYPE_RECT;
593 //                         samplerType = COLLADASW::Sampler::SAMPLER_TYPE_RECT;
594 //                         samplerValueType = COLLADASW::ValueType::SAMPLER_RECT;
595 //                         break;
596 //                     case cgfxAttrDef::kAttrTypeCubeTexture:
597 //                     case cgfxAttrDef::kAttrTypeEnvTexture:
598 //                     case cgfxAttrDef::kAttrTypeNormalizationTexture:
599 //                         //surfaceType = COLLADASW::Surface::SURFACE_TYPE_CUBE;
600 //                         samplerType = COLLADASW::Sampler::SAMPLER_TYPE_CUBE;
601 //                         samplerValueType = COLLADASW::ValueType::SAMPLER_CUBE;
602 //                         break;
603 //                     default:
604 //                         //surfaceType = COLLADASW::Surface::SURFACE_TYPE_UNTYPED;
605 //                         samplerType = COLLADASW::Sampler::SAMPLER_TYPE_UNSPECIFIED;
606 //                         samplerValueType = COLLADASW::ValueType::VALUE_TYPE_UNSPECIFIED;
607 //                     }
608 //
609 //                     // Write the params elements
610 //                     setSetParamTexture ( attribute, textureNode, samplerType, samplerValueType );
611 //                }
612             }
613         }
614     }
615 
616     //---------------------------------------
setSetParamTexture(const cgfxAttrDef * attribute,MObject texture,COLLADASW::Sampler::SamplerType samplerType,COLLADASW::ValueType::ColladaType samplerValueType)617     void MaterialExporter::setSetParamTexture (
618         const cgfxAttrDef* attribute,
619         MObject texture,
620         COLLADASW::Sampler::SamplerType samplerType,
621         COLLADASW::ValueType::ColladaType samplerValueType )
622     {
623         // Get a pointer to the current stream writer.
624         COLLADASW::StreamWriter* streamWriter = mDocumentExporter->getStreamWriter();
625 
626         // Get the image id
627         MFnDependencyNode textureNode ( texture );
628         String plugName = textureNode.name().asChar(); // file1
629 
630         // Get the file texture name
631         MPlug filenamePlug = textureNode.findPlug ( ATTR_FILE_TEXTURE_NAME );
632         MString mayaFileName;
633         filenamePlug.getValue ( mayaFileName );
634         if ( mayaFileName.length() == 0 ) return;
635         String fileName = mayaFileName.asChar ();
636 
637         // Get the image path
638         // Take the filename for the unique image name
639         COLLADASW::URI sourceFileUri(COLLADASW::URI::nativePathToUri(fileName));
640         if ( sourceFileUri.getScheme ().empty () )
641             sourceFileUri.setScheme ( COLLADASW::URI::SCHEME_FILE );
642         String mayaImageId = DocumentExporter::mayaNameToColladaName ( sourceFileUri.getPathFileBase().c_str () );
643 
644         // Get the image id of the maya image
645         EffectExporter* effectExporter = mDocumentExporter->getEffectExporter ();
646         String colladaImageId = effectExporter->findColladaImageId ( mayaImageId );
647         if ( colladaImageId.empty () )
648         {
649             // Check if there is an extra attribute "colladaId" and use this as export id.
650             MString attributeValue;
651             DagHelper::getPlugValue ( texture, COLLADA_ID_ATTRIBUTE_NAME, attributeValue );
652             if ( attributeValue != EMPTY_CSTRING )
653             {
654                 // Generate a valid collada name, if necessary.
655                 colladaImageId = mDocumentExporter->mayaNameToColladaName ( attributeValue, false );
656             }
657             else
658             {
659                 // Generate a COLLADA id for the new light object
660                 colladaImageId = DocumentExporter::mayaNameToColladaName ( textureNode.name() );
661             }
662             // Make the id unique and store it in a map for refernences.
663             EffectTextureExporter* textureExporter = effectExporter->getTextureExporter ();
664             colladaImageId = textureExporter->getImageIdList ().addId ( colladaImageId );
665             textureExporter->getMayaIdColladaImageId () [mayaImageId] = colladaImageId;
666         }
667 
668         // Export the image
669         EffectTextureExporter* textureExporter = mDocumentExporter->getEffectExporter()->getTextureExporter();
670         COLLADASW::Image* colladaImage = textureExporter->exportImage ( mayaImageId, colladaImageId, sourceFileUri );
671         mayaImageId = colladaImage->getImageId();
672 
673         // Create the sampler and surface sid
674         String samplerSid = mayaImageId + COLLADASW::Sampler::SAMPLER_SID_SUFFIX;
675         String surfaceSid = mayaImageId + COLLADASW::Sampler::SURFACE_SID_SUFFIX;
676 
677         // Avoid export of dublicate sampler params
678         if ( mSamplers.find ( samplerSid ) != mSamplers.end () ) return;
679         mSamplers.insert ( samplerSid );
680 
681         // Create the sampler and add the sampler <setparam>
682         COLLADASW::Sampler sampler ( samplerType, samplerSid, surfaceSid );
683         sampler.setFormat ( EffectTextureExporter::FORMAT );
684         sampler.setImageId ( colladaImage->getImageId() );
685         sampler.addInSetParam ( streamWriter );
686     }
687 
688     //---------------------------------------
exportCustomHwShaderNode(COLLADASW::InstanceEffect & effectInstance,MObject shader)689     void MaterialExporter::exportCustomHwShaderNode(
690         COLLADASW::InstanceEffect &effectInstance,
691         MObject shader )
692     {
693         MFnDependencyNode fnNode ( shader );
694         if ( fnNode.typeId() == cgfxShaderNode::sId )
695         {
696             // Add the technique hint and the effect attributes to the collada document.
697             exportCgfxShaderNode ( effectInstance, (cgfxShaderNode*) fnNode.userNode () );
698         }
699 
700     }
701 
702     //---------------------------------------
exportCgfxShaderNode(COLLADASW::InstanceEffect & effectInstance,cgfxShaderNode * shaderNodeCgfx)703     void MaterialExporter::exportCgfxShaderNode (
704         COLLADASW::InstanceEffect& effectInstance,
705         cgfxShaderNode* shaderNodeCgfx )
706     {
707         // Get the filename of the current cgfx file
708 		MString shaderFxFile = cgfxFindFile(shaderNodeCgfx->shaderFxFile());
709         String shaderFxFileName = shaderFxFile.asChar(); // check3d.cgfx
710         setShaderFxFileUri ( COLLADASW::URI ( COLLADASW::URI::nativePathToUri ( shaderFxFileName ) ) );
711 
712         // Get the current technique name
713         String techniqueName = shaderNodeCgfx->getTechnique().asChar(); // techniqueName.asChar()
714 
715         // Add the technique hint to the collada document.
716         effectInstance.addTechniqueHint ( techniqueName, COLLADASW::CSWC::CSW_PLATFORM_PC_OGL );
717 
718         // Clear the samplers setParam list.
719         mSamplers.clear ();
720 
721 #if MAYA_API_VERSION < 201200
722         // Get the setParams attributes
723         CGeffect cgEffect = shaderNodeCgfx->effect();
724         CGtechnique cgTechnique = cgGetNamedTechnique( cgEffect, techniqueName.c_str() );
725         cgfxAttrDefList* effectAttributes = cgfxAttrDef::attrsFromEffect ( cgEffect, cgTechnique );
726         MString sResult, sTemp;
727         cgfxAttrDefList::iterator effectIt;
728         for ( effectIt=effectAttributes->begin(); effectIt; ++effectIt )
729         {
730             cgfxAttrDef* effectAttribute = *effectIt;
731             setSetParam ( shaderNodeCgfx, effectAttribute );
732         }
733 #else // MAYA_API_VERSION < 201200
734         // Get the setParams attributes
735         const cgfxRCPtr<const cgfxEffect>& cgEffect = shaderNodeCgfx->effect();
736         if( cgEffect.isNull() )
737         {
738             MGlobal::displayError ( "cgEffect is null." );
739             return;
740         }
741 
742         cgfxRCPtr<cgfxAttrDefList> effectAttributes = cgEffect->attrsFromEffect();
743 
744         MString sResult, sTemp;
745         cgfxAttrDefList::iterator effectIt;
746 
747 		MaterialExporter::mSurfaceSidList.clear();
748 
749         for ( effectIt=effectAttributes->begin(); effectIt; ++effectIt )
750         {
751             cgfxAttrDef* effectAttribute = *effectIt;
752             setSetParam ( shaderNodeCgfx, effectAttribute );
753         }
754 #endif // MAYA_API_VERSION < 201200
755     }
756 
757     // --------------------------------------
setShaderFxFileUri(const COLLADASW::URI & shaderFxFileName)758     void MaterialExporter::setShaderFxFileUri( const COLLADASW::URI& shaderFxFileName )
759     {
760         mShaderFxFileUri = shaderFxFileName;
761     }
762 
763     // --------------------------------------
getShaderFxFileUri() const764     const COLLADASW::URI& MaterialExporter::getShaderFxFileUri() const
765     {
766         return mShaderFxFileUri;
767     }
768 
769     // --------------------------------------
exportEffectInstance(const String & mayaMaterialId,const String & colladaMaterialId,MObject & shader)770     void MaterialExporter::exportEffectInstance (
771         const String& mayaMaterialId,
772         const String& colladaMaterialId,
773         MObject &shader )
774     {
775         // Generate a COLLADA id for the new object
776         String colladaEffectId;
777 
778         // Check if there is an extra attribute "colladaId" and use this as export id.
779         MString attributeValue;
780         DagHelper::getPlugValue ( shader, COLLADA_EFFECT_ID_ATTRIBUTE_NAME, attributeValue );
781         if ( attributeValue != EMPTY_CSTRING )
782         {
783             // Generate a valid collada name, if necessary.
784             colladaEffectId = mDocumentExporter->mayaNameToColladaName ( attributeValue, false );
785         }
786         else
787         {
788             // Generate a COLLADA id for the new object
789             colladaEffectId = colladaMaterialId + EffectExporter::EFFECT_ID_SUFFIX;
790         }
791         // Make the id unique and store it in a map.
792         colladaEffectId = mEffectIdList.addId ( colladaEffectId );
793         mMayaIdColladaEffectIdMap [ mayaMaterialId ] = colladaEffectId;
794 
795         // Create the effect instance
796         COLLADASW::StreamWriter* streamWriter = mDocumentExporter->getStreamWriter();
797         COLLADASW::InstanceEffect effectInstance ( streamWriter, COLLADASW::URI ( EMPTY_STRING, colladaEffectId ) );
798 
799         // Opens the current effect instance.
800         effectInstance.open();
801 
802         // Custom hardware shaders derived from MPxHardwareShader (the new stuff)
803         if ( shader.hasFn ( MFn::kPluginHwShaderNode ) )
804         {
805             // Export the effect technique reference and the hardware shader parameters.
806             exportCustomHwShaderNode ( effectInstance, shader );
807         }
808 
809         // TODO
810 //         // Export the user defined instance_effect extra data from import (extra preservation).
811 //         mDocumentExporter->exportExtraData ( shader, COLLADAFW::ExtraKeys::INSTANCE_EFFECT );
812 
813         // Close the current effect element.
814         effectInstance.close();
815     }
816 
817     // --------------------------------------
findColladaEffectId(const String & mayaMaterialId)818     const String MaterialExporter::findColladaEffectId ( const String& mayaMaterialId )
819     {
820         const StringToStringMap::const_iterator it = mMayaIdColladaEffectIdMap.find ( mayaMaterialId );
821         if ( it != mMayaIdColladaEffectIdMap.end () )
822         {
823             return it->second;
824         }
825         return EMPTY_STRING;
826     }
827 
828     // --------------------------------------
findColladaMaterialId(const String & mayaMaterialId)829     const String MaterialExporter::findColladaMaterialId ( const String& mayaMaterialId )
830     {
831         const StringToStringMap::const_iterator it = mMayaIdColladaMaterialIdMap.find ( mayaMaterialId );
832         if ( it != mMayaIdColladaMaterialIdMap.end () )
833         {
834             return it->second;
835         }
836         return EMPTY_STRING;
837     }
838 
839 
840 }
841