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 #include "COLLADAMayaStableHeaders.h"
16 #include "COLLADAMayaGeometryPolygonExporter.h"
17 #include "COLLADAMayaExportOptions.h"
18 #include "COLLADAMayaSyntax.h"
19 #include "COLLADAMayaSceneGraph.h"
20 #include <algorithm>
21 #include <assert.h>
22 #include <time.h>
23 
24 #include <maya/MItDependencyNodes.h>
25 #include <maya/MFnMesh.h>
26 #include <maya/MItMeshPolygon.h>
27 #include <maya/MItMeshVertex.h>
28 #include <maya/MItDag.h>
29 
30 #include "COLLADASWSource.h"
31 #include "COLLADASWBaseInputElement.h"
32 #include "COLLADASWInputList.h"
33 #include "COLLADASWExtraTechnique.h"
34 
35 
36 namespace COLLADAMaya
37 {
38 
39 #undef VALIDATE_DATA
40 
41 
42     // --------------------------------------------------------
GeometryPolygonExporter(COLLADASW::StreamWriter * _streamWriter,DocumentExporter * _documentExporter)43     GeometryPolygonExporter::GeometryPolygonExporter (
44     	COLLADASW::StreamWriter* _streamWriter,
45         DocumentExporter* _documentExporter )
46         : COLLADASW::LibraryGeometries ( _streamWriter )
47         , mDocumentExporter ( _documentExporter )
48         , mPolygonSources ( NULL )
49         , mVertexSources ( NULL )
50         , triangulated ( false )
51         , holeCount ( 0 )
52         , mHasFaceVertexNormals ( false )
53         , mShaderPosition ( 0 )
54     {
55     }
56 
57     // --------------------------------------------------------
~GeometryPolygonExporter(void)58     GeometryPolygonExporter::~GeometryPolygonExporter ( void ) {}
59 
60     // --------------------------------------------------------
exportPolygonSources(const MObject & mesh,const String & meshId,MStringArray & uvSetNames,MStringArray & colorSetNames,Sources * polygonSources,Sources * vertexSources,const bool hasFaceVertexNorms)61     void GeometryPolygonExporter::exportPolygonSources (
62         const MObject& mesh,
63         const String& meshId,
64         MStringArray& uvSetNames,
65         MStringArray& colorSetNames,
66         Sources* polygonSources,
67         Sources* vertexSources,
68         const bool hasFaceVertexNorms )
69     {
70         MFnMesh fnMesh(mesh);
71         // Initialize the members
72         mMeshId = meshId;
73         mUvSetNames = uvSetNames;
74         mPolygonSources = polygonSources;
75         mVertexSources = vertexSources;
76         mHasFaceVertexNormals = hasFaceVertexNorms;
77         mColorSetNames = colorSetNames;
78 
79         // If triangulation is requested, verify that it is
80         // feasible by checking with all the mesh polygons
81         if ( ExportOptions::exportTriangles() )
82         {
83             triangulated = true;
84 
85             for ( MItMeshPolygon polyIt ( mesh ); triangulated && !polyIt.isDone(); polyIt.next() )
86             {
87                 triangulated = polyIt.hasValidTriangulation();
88             }
89         }
90 
91         // If we have a hole in a polygon, we can't write a <polylist>.
92         // Either we write <polygons> with holes or we write triangles.
93         // Get hole information from the mesh node.
94         // The format for the holes information is explained in the MFnMesh documentation.
95         MStatus status;
96         fnMesh.getHoles ( mHoleInfoArray, mHoleVertexArray, &status );
97         holeCount = ( status != MStatus::kSuccess ) ? 0 : ( mHoleInfoArray.length() / 3 );
98 
99         // Find how many shaders are used by this instance of the mesh.
100         // Each instance may apply a number of different materials to different faces.
101         // We can use the getConnectedShaders member function of MFnMesh to find out
102         // this shader information for each instance.
103         mShaders.clear(); mShaderIndices.clear();
104         fnMesh.getConnectedShaders ( 0, mShaders, mShaderIndices );
105 
106         // Find the polygons that correspond to each materials and export them.
107         uint realShaderCount = ( uint ) mShaders.length();
108         uint numShaders = ( uint ) std::max ( ( size_t ) 1, ( size_t ) mShaders.length() );
109 
110         for ( uint shaderPosition=0; shaderPosition<numShaders; ++shaderPosition )
111         {
112             // Set the current shader position
113             mShaderPosition = shaderPosition;
114 
115             // Export the polygons of the current shader
116             exportShaderPolygons ( mesh );
117         }
118     }
119 
120     //---------------------------------------------------------------
exportShaderPolygons(const MObject & mesh)121     void GeometryPolygonExporter::exportShaderPolygons (
122         const MObject& mesh)
123     {
124         // Get the polygons count.
125         uint numPolygons = getShaderPolygonsCount ( mesh );
126 
127         // Just create a polylist, if there are polygons to export
128         // If we have holes in the polygon, we have to use <polygons> instead of <polylist>.
129         // If we want to export as triangles, we have to use <triangles>.
130         COLLADASW::PrimitivesBase* primitivesBasePoly = NULL;
131 
132         // Just create the polylist, if there are polygons in the shader to export
133         if ( numPolygons > 0 )
134         {
135             // Retrieves the information, if we have a hole in any polygon under the current shape
136             // (then we have to create a polygon element, instead of a polylist element).
137             bool isHoledShape = verifyPolygonsForHoles ( mesh );
138 
139             // Determine the export type (polylist/polygon/triangles)
140             uint exportType = determinePrimitivesBaseExportType ( isHoledShape );
141 
142             // If we should export a polylist and all polygons of the current mesh
143             // are triangles, we will export triangles instead of polygons!
144             if ( exportType == PolygonSource::POLYLIST )
145             {
146                 if ( verifyTriangulation( mesh ) )
147                 {
148                     exportType = PolygonSource::TRIANGLES;
149                     triangulated = true;
150                 }
151             }
152 
153             // Create the polylist/polygon/triangles element and set the
154             // materials and the vertices count list before writing the
155             // list of the polylist/polygon/triangles vertices.
156             primitivesBasePoly = preparePrimitivesBase( mesh, numPolygons, exportType );
157 
158             // Retrieve the shader polygon vertices and write them directly into the collada file.
159             writeShaderPolygons( primitivesBasePoly, exportType, mesh );
160 
161         }
162 
163         // Delete the created primitivesBasePoly
164         if ( primitivesBasePoly != NULL )
165         {
166             delete primitivesBasePoly;
167             primitivesBasePoly = NULL;
168         }
169     }
170 
171     // ----------------------------------------
verifyTriangulation(const MObject & mesh)172     bool GeometryPolygonExporter::verifyTriangulation ( const MObject &mesh )
173     {
174         // Iterate through all polygons of the current mesh
175         MItMeshPolygon meshPolygonsIter ( mesh );
176         for ( meshPolygonsIter.reset(); !meshPolygonsIter.isDone(); meshPolygonsIter.next() )
177         {
178             // Is this polygon shaded by this shader?
179             uint realShaderCount = ( uint ) mShaders.length();
180             uint polyIndex = meshPolygonsIter.index();
181             if ( mShaderPosition < realShaderCount &&
182                 ( uint ) mShaderIndices[polyIndex] != mShaderPosition ) continue;
183             if ( mShaderPosition >= realShaderCount &&
184                 polyIndex < mShaderIndices.length() &&
185                 ( mShaderIndices[polyIndex] >= 0 &&
186                 mShaderIndices[polyIndex] < ( int ) realShaderCount ) ) continue;
187 
188             // Get the number of vertices in the current mesh's polygon
189             if ( meshPolygonsIter.polygonVertexCount() != 3) return false;
190         }
191 
192         // All polygons are triangles
193         return true;
194     }
195 
196     // ----------------------------------------
writeShaderPolygons(COLLADASW::PrimitivesBase * primitivesBasePoly,const uint exportType,const MObject & mesh)197     void GeometryPolygonExporter::writeShaderPolygons(
198         COLLADASW::PrimitivesBase* primitivesBasePoly,
199         const uint exportType,
200         const MObject & mesh )
201     {
202         // Number of polygons (could also be triangles)
203         uint numPolygons = 0;
204 
205         // Generate the polygon set inputs.
206         Sources polygonSetInputs;
207         getVerticesInputAttributes( polygonSetInputs );
208 
209         // Iterate through all polygons of the current mesh and create them to export
210         MItMeshPolygon meshPolygonsIter ( mesh );
211         for ( meshPolygonsIter.reset(); !meshPolygonsIter.isDone(); meshPolygonsIter.next() )
212         {
213             // Is this polygon shaded by this shader?
214             uint realShaderCount = ( uint ) mShaders.length();
215             uint polyIndex = meshPolygonsIter.index();
216             if ( mShaderPosition < realShaderCount &&
217                 ( uint ) mShaderIndices[polyIndex] != mShaderPosition ) continue;
218             if ( mShaderPosition >= realShaderCount &&
219                 polyIndex < mShaderIndices.length() &&
220                 ( mShaderIndices[polyIndex] >= 0 &&
221                 mShaderIndices[polyIndex] < ( int ) realShaderCount ) ) continue;
222 
223             // Create a polygon to store the vertex indexes to export
224             PolygonSource polygon ( polygonSetInputs );
225 
226             // Create the polygon with the initialization data
227             MIntArray vertexIndices;
228             uint numPolygons = 0, numVertices = 0;
229             initializePolygonSource ( mesh, meshPolygonsIter, polygon, vertexIndices, numPolygons, numVertices );
230 
231              // If we have polygons to export, push it into the polygon list
232             if ( numPolygons > 0 )
233             {
234                 writeElementVertexIndices ( primitivesBasePoly, &polygon, mesh, meshPolygonsIter, exportType, vertexIndices, numPolygons, numVertices );
235             }
236         }
237 
238         primitivesBasePoly->finish();
239     }
240 
241     // --------------------------------------------------------
initializePolygonSource(const MObject & mesh,MItMeshPolygon & meshPolygonsIter,PolygonSource & polygon,MIntArray & vertexIndices,uint & numPolygons,uint & numVertices)242     void GeometryPolygonExporter::initializePolygonSource(
243         const MObject& mesh,
244         MItMeshPolygon &meshPolygonsIter,
245         PolygonSource &polygon,
246         MIntArray &vertexIndices,
247         uint &numPolygons,
248         uint &numVertices )
249     {
250         // Collect data in order to handle triangle-only export option
251 
252         // Retrieve the vertex indices and establish the number of polygons (in case of
253         // triangulation more than one is possible) and the number of vertexes in the polygon.
254         retrieveVertexIndices (
255             vertexIndices,
256             meshPolygonsIter,
257             numPolygons,
258             numVertices );
259 
260         // Iterate through the polygons (normally just one polygon,
261         // just in case of triangulation it could be more than one)
262         for ( uint polygonPosition=0; polygonPosition<numPolygons; ++polygonPosition )
263         {
264             // Put the current face in the list of faces
265             polygon.getFaceVertexCounts().push_back ( numVertices );
266 
267             // Get the index of the current polygon
268             int polyIndex = meshPolygonsIter.index();
269 
270             // Iterate through the vertexes of the current polygon
271             for ( uint vertexPosition=0; vertexPosition<numVertices; vertexPosition++ )
272             {
273                 // Handle front face vs back face by walking the vertexes backward on the back-face
274                 int iteratorVertexIndex = vertexIndices[polygonPosition * numVertices + vertexPosition];
275                 int vertexIndex = meshPolygonsIter.vertexIndex ( iteratorVertexIndex );
276 
277                 // Look for holes in this polygon
278                 // ASSUMPTION: Holes are automatically removed by triangulation.
279                 // ASSUMPTION: The iterator gives the hole vertices at the end of the enumeration.
280                 // ASSUMPTION: Hole vertices are never used as surface vertices or repeated between holes or inside a hole.
281                 if ( meshPolygonsIter.isHoled() && !triangulated )
282                 {
283                     handleHoledPolygon(polygon, polyIndex, vertexIndex, numVertices, iteratorVertexIndex);
284                 }
285             }
286         }
287     }
288 
289     // --------------------------------------------------------
writeElementVertexIndices(COLLADASW::PrimitivesBase * primitivesBasePoly,PolygonSource * polygon,const MObject & mesh,MItMeshPolygon & meshPolygonsIter,const uint exportType,const MIntArray & vertexIndices,const uint numPolygons,const uint numVertices)290     void GeometryPolygonExporter::writeElementVertexIndices(
291         COLLADASW::PrimitivesBase* primitivesBasePoly,
292         PolygonSource* polygon,
293         const MObject& mesh,
294         MItMeshPolygon &meshPolygonsIter,
295         const uint exportType,
296         const MIntArray &vertexIndices,
297         const uint numPolygons,
298         const uint numVertices )
299     {
300         MFnMesh fnMesh(mesh);
301 
302         // Add the open tags for the polygons
303         if ( exportType == PolygonSource::POLYGONS )
304         {
305             if ( polygon->isHoled() )
306             {
307                 ( ( COLLADASW::Polygons* ) primitivesBasePoly )->openPolylistHoleElement();
308             }
309         }
310 
311         // The face index
312         uint currentFaceIndex = 0;
313 
314         // Check if the current face is a normal polygon or a hole and open the corresponding tag.
315         if ( exportType == PolygonSource::POLYGONS )
316         {
317             openPolygonOrHoleElement (
318                 primitivesBasePoly,
319                 polygon,
320                 currentFaceIndex );
321         }
322 
323         // Get the index of the current polygon
324         int polyIndex = meshPolygonsIter.index();
325 
326         // Buffer the face normal indices
327         MIntArray normalIndices;
328         if ( mHasFaceVertexNormals )
329         {
330             fnMesh.getFaceNormalIds ( polyIndex, normalIndices );
331         }
332 
333         // Iterate through the polygons (normally just one polygon,
334         // just in case of triangulation it could be more than one)
335         for ( uint polygonPosition=0; polygonPosition<numPolygons; ++polygonPosition )
336         {
337             // Initialize the data for polygons with holes
338             size_t numFaceVertices = polygon->getFaceVertexCounts().size();
339             uint currentFaceIndex = 0;
340             uint faceVertexCounts = polygon->getFaceVertexCounts()[currentFaceIndex];
341 
342             // Iterate through the vertexes of the current polygon
343             for ( uint vertexPosition=0; vertexPosition<numVertices; ++vertexPosition )
344             {
345                 // Handle front face vs back face by walking the vertexes backward on the back-face
346                 uint vertexIndexPosition = polygonPosition * numVertices + vertexPosition;
347                 int iteratorVertexIndex = vertexIndices[vertexIndexPosition];
348                 int vertexIndex = meshPolygonsIter.vertexIndex ( iteratorVertexIndex );
349 
350                 // If we write a holed polygon and the actual vertex position is the last
351                 // position of the current face, then go to the next face in the list.
352                 if ( exportType == PolygonSource::POLYGONS &&
353                      polygon->isHoled() &&
354                      vertexPosition == faceVertexCounts )
355                 {
356                     // Increment, cause we have found the next face
357                     ++currentFaceIndex;
358 
359                     // Close the tag for the last face
360                     ( ( COLLADASW::Polygons* ) primitivesBasePoly )->closeElement();
361 
362                     // Get the vertex count of the current face
363                     uint currentFaceVertexCount = polygon->getFaceVertexCounts()[currentFaceIndex];
364                     // Add the vertex count of the current face to the sum of face vertexes
365                     faceVertexCounts += currentFaceVertexCount;
366 
367                     // Check if the current face is a normal polygon or a hole and open the corresponding tag.
368                     openPolygonOrHoleElement ( primitivesBasePoly, polygon, currentFaceIndex );
369                 }
370 
371                 // Write the vertex indices
372                 writeVertexIndices ( primitivesBasePoly, polygon, vertexIndex, normalIndices, iteratorVertexIndex, meshPolygonsIter, mesh, polyIndex );
373             }
374         }
375 
376         // Add the tags for the polygons
377         if ( exportType == PolygonSource::POLYGONS )
378         {
379             if ( polygon->isHoled() )
380                 ( ( COLLADASW::Polygons* ) primitivesBasePoly )->closeElement();
381 
382             ( ( COLLADASW::Polygons* ) primitivesBasePoly )->closeElement();
383         }
384     }
385 
386     // ----------------------------------------
verifyPolygonsForHoles(const MObject & mesh)387     bool GeometryPolygonExporter::verifyPolygonsForHoles(
388         const MObject &mesh )
389     {
390         // If we want to export triangles, holes aren't of note.
391         if ( triangulated ) return false;
392 
393         // Iterate through all polygons of the current mesh and
394         // verify their polygons for holes.
395         MItMeshPolygon meshPolygonsIter ( mesh );
396         for ( meshPolygonsIter.reset(); !meshPolygonsIter.isDone(); meshPolygonsIter.next() )
397         {
398             // Is this polygon shaded by this shader?
399             uint polyIndex = meshPolygonsIter.index();
400             uint realShaderCount = ( uint ) mShaders.length();
401             if ( mShaderPosition < realShaderCount &&
402                 ( uint ) mShaderIndices[polyIndex] != mShaderPosition ) continue;
403             if ( mShaderPosition >= realShaderCount &&
404                 polyIndex < mShaderIndices.length() &&
405                 ( mShaderIndices[polyIndex] >= 0 &&
406                 mShaderIndices[polyIndex] < ( int ) realShaderCount ) ) continue;
407 
408             // Look for holes in this polygon
409             // ASSUMPTION: Holes are automatically removed by triangulation.
410             // ASSUMPTION: The iterator gives the hole vertices at the end of the enumeration.
411             // ASSUMPTION: Hole vertices are never used as surface vertices or repeated between holes or inside a hole.
412             if ( meshPolygonsIter.isHoled() && !triangulated )
413             {
414                 return true;
415             }
416         }
417 
418         return false;
419     }
420 
421     // ----------------------------------------
writeVertexCountList(COLLADASW::PrimitivesBase * primitivesBase,const MObject & mesh)422     void GeometryPolygonExporter::writeVertexCountList(
423         COLLADASW::PrimitivesBase* primitivesBase,
424         const MObject &mesh )
425     {
426         // Iterate through all polygons of the current mesh.
427         // Check their polygons for holes and retrieve the vertexCountList.
428         MItMeshPolygon meshPolygonsIter ( mesh );
429         for ( meshPolygonsIter.reset(); !meshPolygonsIter.isDone(); meshPolygonsIter.next() )
430         {
431             // Is this polygon shaded by this shader?
432             uint polyIndex = meshPolygonsIter.index();
433             uint realShaderCount = ( uint ) mShaders.length();
434             if ( mShaderPosition < realShaderCount &&
435                 ( uint ) mShaderIndices[polyIndex] != mShaderPosition ) continue;
436             if ( mShaderPosition >= realShaderCount &&
437                 polyIndex < mShaderIndices.length() &&
438                 ( mShaderIndices[polyIndex] >= 0 &&
439                 mShaderIndices[polyIndex] < ( int ) realShaderCount ) ) continue;
440 
441             // Get the polygon count
442             unsigned long vertexCount;
443             if ( getPolygonVertexCount ( meshPolygonsIter, vertexCount ) )
444                 primitivesBase->appendValues( vertexCount );
445         }
446     }
447 
448     // ----------------------------------------
getPolygonVertexCount(MItMeshPolygon & meshPolygonsIter,unsigned long & numVertices)449     bool GeometryPolygonExporter::getPolygonVertexCount(
450         MItMeshPolygon &meshPolygonsIter,
451         unsigned long &numVertices )
452     {
453         bool addVertexCount = false;
454 
455         // Establish the number of vertexes in the polygon.
456         // We don't need the vertex count list for triangulation
457         if ( triangulated ) return addVertexCount;
458 
459         // The number of vertices
460         numVertices = 0;
461 
462         // Retrieve the vertices and increment polygon count
463         // Get the number of vertices in the current mesh's polygon
464         unsigned long polygonVertexCount = meshPolygonsIter.polygonVertexCount();
465         if ( polygonVertexCount >= 3 )
466         {
467 #ifdef VALIDATE_DATA
468             // Skip over any duplicate vertices in this face.
469             // Very rarely, a cunning user manages to corrupt
470             // a face entry on the mesh and somehow configure
471             // a face to include the same vertex multiple times.
472             // This will cause the read-back of this data to
473             // reject the face, and can crash other COLLADA
474             // consumers, so better to lose the data here
475             MIntArray vertexIndices;
476             vertexIndices.setLength ( polygonVertexCount );
477             for ( int pv = 0; pv < polygonVertexCount; ++pv )
478             {
479                 vertexIndices[pv] = pv;
480             }
481 
482             for ( uint n = 0; n < vertexIndices.length() - 1; ++n )
483             {
484                 for ( uint m = n + 1; m < vertexIndices.length(); )
485                 {
486                     if ( vertexIndices[n] == vertexIndices[m] )
487                     {
488                         vertexIndices.remove ( m );
489                     }
490                     else ++m;
491                 }
492             }
493             // Get the number of vertices of the current polygon.
494             numVertices = vertexIndices.length();
495 #else
496             // Get the number of vertices of the current polygon.
497             numVertices = polygonVertexCount;
498 #endif
499 
500             addVertexCount = true;
501         }
502 
503         return addVertexCount;
504     }
505 
506     // ----------------------------------------
getShaderPolygonsCount(const MObject & mesh)507     uint GeometryPolygonExporter::getShaderPolygonsCount(
508         const MObject &mesh )
509     {
510         uint numPolygons = 0;
511 
512         // Iterate through all polygons of the current mesh.
513         // Check their polygons for holes and retrieve the vertexCountList.
514         MItMeshPolygon meshPolygonsIter ( mesh );
515         for ( meshPolygonsIter.reset(); !meshPolygonsIter.isDone(); meshPolygonsIter.next() )
516         {
517             // Is this polygon shaded by this shader?
518             uint polyIndex = meshPolygonsIter.index();
519             uint realShaderCount = ( uint ) mShaders.length();
520             if ( mShaderPosition < realShaderCount &&
521                 ( uint ) mShaderIndices[polyIndex] != mShaderPosition ) continue;
522             if ( mShaderPosition >= realShaderCount &&
523                 polyIndex < mShaderIndices.length() &&
524                 ( mShaderIndices[polyIndex] >= 0 &&
525                 mShaderIndices[polyIndex] < ( int ) realShaderCount ) ) continue;
526 
527             // Get the polygon count
528             uint numMeshPolygons = 0, numVertices = 0;
529 
530             // Get the number of vertices in the current mesh's polygon
531             int polygonVertexCount = meshPolygonsIter.polygonVertexCount();
532             if ( triangulated && polygonVertexCount > 3 )
533             {
534                 int numTriangles;
535                 meshPolygonsIter.numTriangles ( numTriangles );
536                 if ( numTriangles > 0 ) numMeshPolygons = (uint) numTriangles;
537             }
538             else if ( polygonVertexCount >= 3 )
539             {
540                 numMeshPolygons = 1;
541             }
542 
543            numPolygons += numMeshPolygons;
544         }
545 
546         return numPolygons;
547     }
548 
549     // --------------------------------------------------------
retrieveVertexIndices(MIntArray & vertexIndices,MItMeshPolygon & meshPolygonsIter,uint & numPolygons,uint & numVertices)550     void GeometryPolygonExporter::retrieveVertexIndices (
551         MIntArray &vertexIndices,
552         MItMeshPolygon &meshPolygonsIter,
553         uint &numPolygons,
554         uint &numVertices )
555     {
556         // Get the number of vertices in the current mesh's polygon
557         int polygonVertexCount = meshPolygonsIter.polygonVertexCount();
558         if ( triangulated && polygonVertexCount > 3 )
559         {
560             int numTriangles;
561             meshPolygonsIter.numTriangles ( numTriangles );
562             if ( numTriangles > 0 )
563             {
564                 numVertices = 3;
565                 MPointArray vertexPositions;
566                 MIntArray meshVertexIndices;
567                 meshPolygonsIter.getTriangles ( vertexPositions, meshVertexIndices );
568                 vertexIndices.setLength ( meshVertexIndices.length() );
569                 numPolygons = meshVertexIndices.length() / numVertices;
570 
571                 // Map the vertex indices to iterator vertex indices so that we can
572                 // get information from the iterator about normals and such.
573                 uint meshVertexIndexCount = meshVertexIndices.length();
574                 for ( uint mvi = 0; mvi < meshVertexIndexCount; ++mvi )
575                 {
576                     int meshVertexIndex = meshVertexIndices[mvi];
577                     int polygonVertexCount = meshPolygonsIter.polygonVertexCount();
578                     int iteratorVertexIndex = 0;
579                     for ( int pv = 0; pv < polygonVertexCount; ++pv )
580                     {
581                         if ( ( int ) meshPolygonsIter.vertexIndex ( pv ) == meshVertexIndex )
582                         {
583                             iteratorVertexIndex = pv;
584                         }
585                     }
586                     vertexIndices[mvi] = iteratorVertexIndex;
587                 }
588             }
589             else numPolygons = 0;
590         }
591         else if ( polygonVertexCount >= 3 )
592         {
593             numPolygons = 1;
594             vertexIndices.setLength ( polygonVertexCount );
595             for ( int pv = 0; pv < polygonVertexCount; ++pv )
596             {
597                 vertexIndices[pv] = pv;
598             }
599 
600 #ifdef VALIDATE_DATA
601             // Skip over any duplicate vertices in this face.
602             // Very rarely, a cunning user manages to corrupt
603             // a face entry on the mesh and somehow configure
604             // a face to include the same vertex multiple times.
605             // This will cause the read-back of this data to
606             // reject the face, and can crash other COLLADA
607             // consumers, so better to lose the data here
608             for ( uint n = 0; n < vertexIndices.length() - 1; ++n )            {
609                 for ( uint m = n + 1; m < vertexIndices.length(); )
610                 {
611                     if ( vertexIndices[n] == vertexIndices[m] )
612                     {
613                         vertexIndices.remove ( m );
614                     }
615                     else ++m;
616                 }
617             }
618             // Get the number of vertices of the current polygon.
619             numVertices = vertexIndices->length();
620 #else
621             // Get the number of vertices of the current polygon.
622             numVertices = polygonVertexCount;
623 #endif
624         }
625     }
626 
627     // ----------------------------------------------------------------------------------
determinePrimitivesBaseExportType(const bool currentShapeIsHoled)628     uint GeometryPolygonExporter::determinePrimitivesBaseExportType ( const bool currentShapeIsHoled )
629     {
630         uint exportType;
631 
632         // Just create the polylist, if there are polygons to export
633         if ( currentShapeIsHoled && !triangulated )
634         {
635             exportType = PolygonSource::POLYGONS;
636         }
637         else if ( triangulated )
638         {
639             exportType = PolygonSource::TRIANGLES;
640         }
641         else
642         {
643             exportType = PolygonSource::POLYLIST;
644         }
645 
646         return exportType;
647     }
648 
649     // ----------------------------------------------------------------------------------
createPrimitivesBase(const uint baseExportType)650     COLLADASW::PrimitivesBase* GeometryPolygonExporter::createPrimitivesBase ( const uint baseExportType )
651     {
652         COLLADASW::PrimitivesBase* primitivesBasePoly;
653 
654         switch ( baseExportType )
655         {
656         case PolygonSource::POLYGONS:
657             primitivesBasePoly = new COLLADASW::Polygons ( mSW );
658             break;
659         case PolygonSource::TRIANGLES:
660             primitivesBasePoly = new COLLADASW::Triangles ( mSW );
661             break;
662         case PolygonSource::POLYLIST:
663         default:
664             primitivesBasePoly = new COLLADASW::Polylist ( mSW );
665             break;
666         }
667 
668         return primitivesBasePoly;
669     }
670 
671     // ----------------------------------------------------------------------------------
openPolygonOrHoleElement(COLLADASW::PrimitivesBase * polylist,PolygonSource * poly,const uint currentFaceIndex)672     void GeometryPolygonExporter::openPolygonOrHoleElement (
673         COLLADASW::PrimitivesBase* polylist,
674         PolygonSource* poly,
675         const uint currentFaceIndex )
676     {
677         bool currentFaceIsHole = checkForHole ( poly, currentFaceIndex );
678         if ( currentFaceIsHole )
679         {
680             ( ( COLLADASW::Polygons* ) polylist )->openHoleElement();
681         }
682         else
683         {
684             ( ( COLLADASW::Polygons* ) polylist )->openPolylistElement();
685         }
686     }
687 
688     // ----------------------------------------------------------------------------------
checkForHole(const PolygonSource * polygon,const uint currentFaceIndex)689     bool GeometryPolygonExporter::checkForHole ( const PolygonSource* polygon, const uint currentFaceIndex )
690     {
691         // Check if the current face is a normal polygon or a hole
692         bool currentFaceIsHole = false;
693         size_t numHoles = polygon->getHoleFaces().size();
694         for ( size_t holeIndex=0; holeIndex<numHoles && !currentFaceIsHole; ++holeIndex )
695         {
696             uint holeFaceIndex = polygon->getHoleFaces()[holeIndex];
697             if ( holeFaceIndex == currentFaceIndex )
698             {
699                 currentFaceIsHole = true;
700             }
701         }
702 
703         return currentFaceIsHole;
704     }
705 
706     // ---------------------------------------------
handleHoledPolygon(PolygonSource & polygon,const int polyIndex,const int vertexIndex,const int numVertices,const int iteratorVertexIndex)707     void GeometryPolygonExporter::handleHoledPolygon(
708         PolygonSource &polygon,
709         const int polyIndex,
710         const int vertexIndex,
711         const int numVertices,
712         const int iteratorVertexIndex )
713     {
714         // Set the flag to the polygon, that it is a holed one
715         polygon.isHoled(true);
716 
717         // Put the index of the hole in the list of holes and put the face in the list of faces
718         for ( uint holePosition=0; holePosition<holeCount; ++holePosition )
719         {
720             if ( mHoleInfoArray[holePosition*3] == polyIndex )
721             {
722                 uint holeVertexOffset = mHoleInfoArray[holePosition*3+2];
723                 if ( holeVertexOffset <= mHoleVertexArray.length() &&
724                     mHoleVertexArray[holeVertexOffset] == vertexIndex )
725                 {
726                     // Decrement the index of the last face for the index of the hole face
727                     size_t faceIndex = polygon.getFaceVertexCounts().size();
728                     polygon.getFaceVertexCounts()[faceIndex-1] -= ( numVertices - iteratorVertexIndex );
729 
730                     // Put the index of the hole in the list of holes
731                     polygon.getHoleFaces().push_back ( ( uint ) faceIndex );
732 
733                     // put the face in the list of faces
734                     polygon.getFaceVertexCounts().push_back ( numVertices - iteratorVertexIndex );
735                 }
736             }
737         }
738     }
739 
740     // ---------------------------------------------
getVerticesInputAttributes(Sources & vertexAttributes)741     void GeometryPolygonExporter::getVerticesInputAttributes( Sources &vertexAttributes )
742     {
743         // Generate the polygon set inputs.
744         int nextIdx = 1, normalsIdx = -1, textureIdx = -1;
745         int offset = 0; // Offset for the input list
746 
747         size_t inputCount = mPolygonSources->size();
748         for ( size_t p = 0; p < inputCount; ++p )
749         {
750             const SourceInput param = ( *mPolygonSources ) [p];
751             const COLLADASW::SourceBase source = param.getSource();
752             const COLLADASW::InputSemantic::Semantics type = param.getType();
753 
754             // Figure out which idx this parameter will use
755             int foundIdx = -1;
756 
757             // For geometric tangents and bi-normals, use the same idx as the normals.
758             if ( type == COLLADASW::InputSemantic::TANGENT || type == COLLADASW::InputSemantic::BINORMAL )
759             {
760                 foundIdx = normalsIdx;
761             }
762             // For texture tangents and bi-normals, group together for each UV set.
763             if ( type == COLLADASW::InputSemantic::TEXBINORMAL )
764             {
765                 foundIdx = textureIdx;
766             }
767 
768             // Check for duplicate vertex attributes to use their idx
769             if ( foundIdx == -1 )
770             {
771                 size_t vertexAttributeCount = vertexAttributes.size();
772                 for ( size_t v = 0; v < vertexAttributeCount; ++v )
773                 {
774                     if ( vertexAttributes[v].getType() == type &&
775                         vertexAttributes[v].getIdx() == param.getIdx() )
776                     {
777                         foundIdx = ( int ) v;
778                         break;
779                     }
780                 }
781             }
782 
783             // New vertex attribute, so generate a new idx
784             bool newIdx = (foundIdx == -1);
785             if ( newIdx )
786             {
787                 // param for the last time.
788                 vertexAttributes.push_back ( SourceInput(param) );
789             }
790 
791             // For geometric tangents and bi-normals, use the same idx as the normals.
792             if ( type == COLLADASW::InputSemantic::NORMAL )
793             {
794                 normalsIdx = (int)vertexAttributes.size () - 1;
795             }
796             // For texture tangents and bi-normals, group together for each UV set.
797             if ( type == COLLADASW::InputSemantic::TEXTANGENT )
798             {
799                 textureIdx = (int)vertexAttributes.size () - 1;
800             }
801         }
802     }
803 
804     // ---------------------------------------------
getPolygonInputAttributes(COLLADASW::InputList & inputList)805     void GeometryPolygonExporter::getPolygonInputAttributes ( COLLADASW::InputList &inputList )
806     {
807         // Generate the polygon set inputs.
808         int nextIdx = 1, normalsIdx = -1;
809         int offset = 0; // Offset for the input list
810 
811         size_t inputCount = mPolygonSources->size();
812         for ( size_t p = 0; p < inputCount; ++p )
813         {
814             const SourceInput param = ( *mPolygonSources ) [p];
815             const COLLADASW::SourceBase source = param.getSource();
816             const COLLADASW::InputSemantic::Semantics type = param.getType();
817 
818             // Check if the vertex is already registered
819             bool isVertexSource = SourceInput::containsSourceBase ( mVertexSources, &source );
820 
821             // Add the per-face, per-vertex input to the polygons description
822             if ( !isVertexSource )
823             {
824                 // Get the generated id of the source for reference
825                 String sourceId = source.getId();
826 
827                 // The vertex sources must reference to the vertexes element
828                 if ( type == COLLADASW::InputSemantic::VERTEX )
829                 {
830                     String suffix = getSuffixBySemantic ( type );
831                     sourceId = mMeshId + suffix;
832                 }
833 
834                 if ( type == COLLADASW::InputSemantic::TEXCOORD )
835                 {
836                     // For texture coordinate-related inputs: set the 'set' attribute.
837                     if ( param.getIdx () >= 0 )
838                         inputList.push_back ( COLLADASW::Input ( type, COLLADASW::URI ( EMPTY_STRING, sourceId ), offset++, param.getIdx() ) );
839                     else
840                         inputList.push_back ( COLLADASW::Input ( type, COLLADASW::URI ( EMPTY_STRING, sourceId ), offset++ ) );
841                 }
842                 else if ( type == COLLADASW::InputSemantic::TANGENT || type == COLLADASW::InputSemantic::BINORMAL || type == COLLADASW::InputSemantic::TEXBINORMAL )
843                 {
844                     // Tangents and binormals can use the same index than the normals.
845                     // Texture binormals can use the index list of texture tangents.
846                     if ( param.getIdx () >= 0 )
847                         inputList.push_back ( COLLADASW::Input ( type, COLLADASW::URI ( EMPTY_STRING, sourceId ), offset-1, param.getIdx() ) );
848                     else
849                         inputList.push_back ( COLLADASW::Input ( type, COLLADASW::URI ( EMPTY_STRING, sourceId ), offset-1 ) );
850                 }
851                 else
852                 {
853                     if ( param.getIdx () >= 0 )
854                         inputList.push_back ( COLLADASW::Input ( type, COLLADASW::URI ( EMPTY_STRING, sourceId ), offset++, param.getIdx () ) );
855                     else
856                         inputList.push_back ( COLLADASW::Input ( type, COLLADASW::URI ( EMPTY_STRING, sourceId ), offset++ ) );
857                 }
858             }
859         }
860     }
861 
862     // --------------------------------------------------------
addHole(uint index)863     void GeometryPolygonExporter::addHole ( uint index )
864     {
865         // The hole mustn't already be inserted in the hole faces list.
866         std::vector<uint>::iterator searchIter;
867         searchIter = find ( mHoleFaces.begin(), mHoleFaces.end(), index );
868 		COLLADABU_ASSERT ( searchIter != mHoleFaces.end() );
869 
870         // Ordered insert
871         std::vector<uint>::iterator it = mHoleFaces.begin();
872         for ( ; it != mHoleFaces.end(); ++it )
873         {
874             if ( index < ( *it ) ) break;
875         }
876 
877         mHoleFaces.insert ( searchIter, index );
878     }
879 
880     // --------------------------------------------------------
writeVertexIndices(COLLADASW::PrimitivesBase * primitivesBasePoly,PolygonSource * polygon,const int vertexIndex,const MIntArray & normalIndices,const int iteratorVertexIndex,MItMeshPolygon & meshPolygonsIter,const MObject & mesh,const int polyIndex)881     void GeometryPolygonExporter::writeVertexIndices (
882         COLLADASW::PrimitivesBase* primitivesBasePoly,
883         PolygonSource *polygon,
884         const int vertexIndex,
885         const MIntArray &normalIndices,
886         const int iteratorVertexIndex,
887         MItMeshPolygon &meshPolygonsIter,
888         const MObject& mesh,
889         const int polyIndex )
890     {
891         MFnMesh fnMesh(mesh);
892 
893         // Dump the indices
894         size_t numAttributes = polygon->getVertexAttributes().size();
895 
896         // Output each vertex attribute we need
897         for ( size_t kk=0; kk<numAttributes; ++kk )
898         {
899             const SourceInput& vertexAttributes = polygon->getVertexAttributes()[kk];
900             COLLADASW::InputSemantic::Semantics type = vertexAttributes.getType();
901             switch ( vertexAttributes.getType() )
902             {
903             case COLLADASW::InputSemantic::VERTEX:
904             case COLLADASW::InputSemantic::POSITION:
905                 primitivesBasePoly->appendValues ( vertexIndex );
906                 break;
907             case COLLADASW::InputSemantic::NORMAL:
908             case COLLADASW::InputSemantic::TANGENT:
909             case COLLADASW::InputSemantic::BINORMAL:
910                 {
911                     if (mHasFaceVertexNormals)
912                     {
913                         // The tangent and the binormal can use the index of the normal
914                         int currentVertexIndex = normalIndices [iteratorVertexIndex];
915                         primitivesBasePoly->appendValues ( currentVertexIndex );
916                     }
917                     else
918                     {
919                         // Assert, if we don't have initialized the normal indices,
920                         // but want to read them out here!
921                         MGlobal::displayError("No face vertex normals to proceed!");
922                         COLLADABU_ASSERT ( mHasFaceVertexNormals );
923                         return;
924                     }
925                 }
926                 break;
927             case COLLADASW::InputSemantic::TEXTANGENT:
928             case COLLADASW::InputSemantic::TEXBINORMAL:
929                 {
930                     // The texture binormal can use the index of the texture tangent.
931                     unsigned int texTangentIndex2 = meshPolygonsIter.tangentIndex ( iteratorVertexIndex );
932                     primitivesBasePoly->appendValues ( texTangentIndex2 );
933                 }
934                 break;
935             case COLLADASW::InputSemantic::TEXCOORD:
936                 {
937                     int uvIndex = 0;
938                     int idx = vertexAttributes.getIdx();
939                     meshPolygonsIter.getUVIndex ( iteratorVertexIndex, uvIndex, &mUvSetNames[idx] );
940                     primitivesBasePoly->appendValues ( uvIndex );
941                 }
942                 break;
943             case COLLADASW::InputSemantic::COLOR:
944                 {
945                     MString& colorSetName = mColorSetNames[vertexAttributes.getIdx()];
946                     int colorIndex = 0;
947                     {
948 #if MAYA_API_VERSION >= 700
949 						MStatus status = fnMesh.getColorIndex ( polyIndex, iteratorVertexIndex, colorIndex, &colorSetName );
950 						if (status && colorIndex == -1)
951 						{
952 							// if vertex has no color, use default color (last color in color source)
953 							MColorArray colors;
954 							fnMesh.getColors(colors, &colorSetName);
955 							colorIndex = colors.length();
956 						}
957 #else
958                         fnMesh.getFaceVertexColorIndex ( polyIndex, iteratorVertexIndex, colorIndex );
959 #endif
960                     }
961                     primitivesBasePoly->appendValues ( colorIndex );
962                 }
963                 break;
964             case COLLADASW::InputSemantic::UNKNOWN:
965             case COLLADASW::InputSemantic::UV:
966 //            case COLLADASW::EXTRA:
967             default:
968                 break; // Not exported/supported
969             }
970         }
971     }
972 
973     // --------------------------------------------------------
preparePrimitivesBase(const MObject & mesh,const uint numPolygons,const uint exportType)974     COLLADASW::PrimitivesBase* GeometryPolygonExporter::preparePrimitivesBase(
975         const MObject& mesh,
976         const uint numPolygons,
977         const uint exportType )
978     {
979         // Just create a polylist, if there are polygons to export
980         // If we have holes in the polygon, we have to use <polygons> instead of <polylist>.
981         // If we want to export as triangles, we have to use <triangles>.
982         COLLADASW::PrimitivesBase* primitivesBasePoly = createPrimitivesBase ( exportType );
983 
984         // Begin to write.
985         primitivesBasePoly->openPrimitiveElement();
986 
987         // Check if the material should be set
988         uint realShaderCount = ( uint ) mShaders.length();
989         if ( mShaderPosition < realShaderCount )
990         {
991             // Add shader-specific parameters (TexCoords sets).
992             // Add symbolic name for the material used on this polygon set.
993             MFnDependencyNode shaderFn ( mShaders[mShaderPosition] );
994             String shaderName = shaderFn.name().asChar();
995             String materialName = DocumentExporter::mayaNameToColladaName ( shaderFn.name() );
996             primitivesBasePoly->appendMaterial ( materialName );
997         }
998 
999         // Set the number of polygons
1000         primitivesBasePoly->appendCount ( numPolygons );
1001 
1002         // Get the polygon input list
1003         COLLADASW::InputList& inputList = primitivesBasePoly->getInputList();
1004         getPolygonInputAttributes ( inputList );
1005         primitivesBasePoly->appendInputList();
1006 
1007         // Set the vertex count list, if we have a POLYLIST
1008         if ( exportType == PolygonSource::POLYLIST )
1009         {
1010             // Retrieve the vertex count list for the polylist element.
1011             primitivesBasePoly->openVertexCountListElement();
1012             writeVertexCountList ( primitivesBasePoly, mesh );
1013             primitivesBasePoly->closeElement();
1014         }
1015 
1016         if ( exportType != PolygonSource::POLYGONS )
1017         {
1018             // Prepare the list for add the vertex indexes
1019             primitivesBasePoly->openPolylistElement();
1020         }
1021 
1022         return primitivesBasePoly;
1023     }
1024 
1025 }
1026