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