// ----------------------------------------
bool GeometryPolygonExporter::verifyPolygonsForHoles(
    const MFnMesh &fnMesh )
{
    // If we want to export triangles, holes aren't of note.
    if ( triangulated ) return false;

    // Iterate through all polygons of the current mesh and
    // verify their polygons for holes.
    MItMeshPolygon meshPolygonsIter ( fnMesh.object() );
    for ( meshPolygonsIter.reset(); !meshPolygonsIter.isDone(); meshPolygonsIter.next() )
    {
        // Is this polygon shaded by this shader?
        int polyIndex = meshPolygonsIter.index();
        uint realShaderCount = ( uint ) mShaders.length();
        if ( mShaderPosition < realShaderCount &&
                ( uint ) mShaderIndices[polyIndex] != mShaderPosition ) continue;
        if ( mShaderPosition >= realShaderCount &&
                ( mShaderIndices[polyIndex] >= 0 &&
                  mShaderIndices[polyIndex] < ( int ) realShaderCount ) ) continue;

        // Look for holes in this polygon
        // ASSUMPTION: Holes are automatically removed by triangulation.
        // ASSUMPTION: The iterator gives the hole vertices at the end of the enumeration.
        // ASSUMPTION: Hole vertices are never used as surface vertices or repeated between holes or inside a hole.
        if ( meshPolygonsIter.isHoled() && !triangulated )
        {
            return true;
        }
    }

    return false;
}
// --------------------------------------------------------
void GeometryPolygonExporter::initializePolygonSource(
    const MFnMesh &fnMesh,
    MItMeshPolygon &meshPolygonsIter,
    PolygonSource &polygon,
    MIntArray &vertexIndices,
    uint &numPolygons,
    uint &numVertices )
{
    // Collect data in order to handle triangle-only export option

    // Retrieve the vertex indices and establish the number of polygons (in case of
    // triangulation more than one is possible) and the number of vertexes in the polygon.
    retrieveVertexIndices (
        vertexIndices,
        meshPolygonsIter,
        numPolygons,
        numVertices );

    // Iterate through the polygons (normally just one polygon,
    // just in case of triangulation it could be more than one)
    for ( uint polygonPosition=0; polygonPosition<numPolygons; ++polygonPosition )
    {
        // Put the current face in the list of faces
        polygon.getFaceVertexCounts().push_back ( numVertices );

        // Get the index of the current polygon
        int polyIndex = meshPolygonsIter.index();

        // Iterate through the vertexes of the current polygon
        for ( uint vertexPosition=0; vertexPosition<numVertices; vertexPosition++ )
        {
            // Handle front face vs back face by walking the vertexes backward on the back-face
            int iteratorVertexIndex = vertexIndices[polygonPosition * numVertices + vertexPosition];
            int vertexIndex = meshPolygonsIter.vertexIndex ( iteratorVertexIndex );

            // Look for holes in this polygon
            // ASSUMPTION: Holes are automatically removed by triangulation.
            // ASSUMPTION: The iterator gives the hole vertices at the end of the enumeration.
            // ASSUMPTION: Hole vertices are never used as surface vertices or repeated between holes or inside a hole.
            if ( meshPolygonsIter.isHoled() && !triangulated )
            {
                handleHoledPolygon(polygon, polyIndex, vertexIndex, numVertices, iteratorVertexIndex);
            }
        }
    }
}
// ----------------------------------------
void GeometryPolygonExporter::writeShaderPolygons(
    COLLADASW::PrimitivesBase* primitivesBasePoly,
    const uint exportType,
    MFnMesh &fnMesh )
{
    // Number of polygons (could also be triangles)
    uint numPolygons = 0;

    // Generate the polygon set inputs.
    Sources polygonSetInputs;
    getVerticesInputAttributes( polygonSetInputs );

    // Iterate through all polygons of the current mesh and create them to export
    MItMeshPolygon meshPolygonsIter ( fnMesh.object() );
    for ( meshPolygonsIter.reset(); !meshPolygonsIter.isDone(); meshPolygonsIter.next() )
    {
        // Is this polygon shaded by this shader?
        uint realShaderCount = ( uint ) mShaders.length();
        int polyIndex = meshPolygonsIter.index();
        if ( mShaderPosition < realShaderCount &&
                ( uint ) mShaderIndices[polyIndex] != mShaderPosition ) continue;
        if ( mShaderPosition >= realShaderCount &&
                ( mShaderIndices[polyIndex] >= 0 &&
                  mShaderIndices[polyIndex] < ( int ) realShaderCount ) ) continue;

        // Create a polygon to store the vertex indexes to export
        PolygonSource polygon ( polygonSetInputs );

        // Create the polygon with the initialization data
        MIntArray vertexIndices;
        uint numPolygons = 0, numVertices = 0;
        initializePolygonSource ( fnMesh, meshPolygonsIter, polygon, vertexIndices, numPolygons, numVertices );

        // If we have polygons to export, push it into the polygon list
        if ( numPolygons > 0 )
        {
            writeElementVertexIndices ( primitivesBasePoly, &polygon, fnMesh, meshPolygonsIter, exportType, vertexIndices, numPolygons, numVertices );
        }
    }

    primitivesBasePoly->finish();
}
// ----------------------------------------
uint GeometryPolygonExporter::getShaderPolygonsCount(
    const MFnMesh &fnMesh )
{
    uint numPolygons = 0;

    // Iterate through all polygons of the current mesh.
    // Check their polygons for holes and retrieve the vertexCountList.
    MItMeshPolygon meshPolygonsIter ( fnMesh.object() );
    for ( meshPolygonsIter.reset(); !meshPolygonsIter.isDone(); meshPolygonsIter.next() )
    {
        // Is this polygon shaded by this shader?
        int polyIndex = meshPolygonsIter.index();
        uint realShaderCount = ( uint ) mShaders.length();
        if ( mShaderPosition < realShaderCount &&
                ( uint ) mShaderIndices[polyIndex] != mShaderPosition ) continue;
        if ( mShaderPosition >= realShaderCount &&
                ( mShaderIndices[polyIndex] >= 0 &&
                  mShaderIndices[polyIndex] < ( int ) realShaderCount ) ) continue;

        // Get the polygon count
        uint numMeshPolygons = 0, numVertices = 0;

        // Get the number of vertices in the current mesh's polygon
        int polygonVertexCount = meshPolygonsIter.polygonVertexCount();
        if ( triangulated && polygonVertexCount > 3 )
        {
            int numTriangles;
            meshPolygonsIter.numTriangles ( numTriangles );
            if ( numTriangles > 0 ) numMeshPolygons = (uint) numTriangles;
        }
        else if ( polygonVertexCount >= 3 )
        {
            numMeshPolygons = 1;
        }

        numPolygons += numMeshPolygons;
    }

    return numPolygons;
}
// ----------------------------------------
bool GeometryPolygonExporter::verifyTriangulation ( MFnMesh &fnMesh )
{
    // Iterate through all polygons of the current mesh
    MItMeshPolygon meshPolygonsIter ( fnMesh.object() );
    for ( meshPolygonsIter.reset(); !meshPolygonsIter.isDone(); meshPolygonsIter.next() )
    {
        // Is this polygon shaded by this shader?
        uint realShaderCount = ( uint ) mShaders.length();
        int polyIndex = meshPolygonsIter.index();
        if ( mShaderPosition < realShaderCount &&
                ( uint ) mShaderIndices[polyIndex] != mShaderPosition ) continue;
        if ( mShaderPosition >= realShaderCount &&
                ( mShaderIndices[polyIndex] >= 0 &&
                  mShaderIndices[polyIndex] < ( int ) realShaderCount ) ) continue;

        // Get the number of vertices in the current mesh's polygon
        if ( meshPolygonsIter.polygonVertexCount() != 3) return false;
    }

    // All polygons are triangles
    return true;
}
// ----------------------------------------
void GeometryPolygonExporter::writeVertexCountList(
    COLLADASW::PrimitivesBase* primitivesBase,
    const MFnMesh &fnMesh )
{
    // Iterate through all polygons of the current mesh.
    // Check their polygons for holes and retrieve the vertexCountList.
    MItMeshPolygon meshPolygonsIter ( fnMesh.object() );
    for ( meshPolygonsIter.reset(); !meshPolygonsIter.isDone(); meshPolygonsIter.next() )
    {
        // Is this polygon shaded by this shader?
        int polyIndex = meshPolygonsIter.index();
        uint realShaderCount = ( uint ) mShaders.length();
        if ( mShaderPosition < realShaderCount &&
                ( uint ) mShaderIndices[polyIndex] != mShaderPosition ) continue;
        if ( mShaderPosition >= realShaderCount &&
                ( mShaderIndices[polyIndex] >= 0 &&
                  mShaderIndices[polyIndex] < ( int ) realShaderCount ) ) continue;

        // Get the polygon count
        unsigned long vertexCount;
        if ( getPolygonVertexCount ( meshPolygonsIter, vertexCount ) )
            primitivesBase->appendValues( vertexCount );
    }
}
// --------------------------------------------------------
void GeometryPolygonExporter::writeElementVertexIndices(
    COLLADASW::PrimitivesBase* primitivesBasePoly,
    PolygonSource* polygon,
    MFnMesh &fnMesh,
    MItMeshPolygon &meshPolygonsIter,
    const uint exportType,
    const MIntArray &vertexIndices,
    const uint numPolygons,
    const uint numVertices )
{
    // Add the open tags for the polygons
    if ( exportType == PolygonSource::POLYGONS )
    {
        if ( polygon->isHoled() )
        {
            ( ( COLLADASW::Polygons* ) primitivesBasePoly )->openPolylistHoleElement();
        }
    }

    // The face index
    uint currentFaceIndex = 0;

    // Check if the current face is a normal polygon or a hole and open the corresponding tag.
    if ( exportType == PolygonSource::POLYGONS )
    {
        openPolygonOrHoleElement (
            primitivesBasePoly,
            polygon,
            currentFaceIndex );
    }

    // Get the index of the current polygon
    int polyIndex = meshPolygonsIter.index();

    // Buffer the face normal indices
    MIntArray normalIndices;
    if ( mHasFaceVertexNormals )
    {
        fnMesh.getFaceNormalIds ( polyIndex, normalIndices );
    }

    // Iterate through the polygons (normally just one polygon,
    // just in case of triangulation it could be more than one)
    for ( uint polygonPosition=0; polygonPosition<numPolygons; ++polygonPosition )
    {
        // Initialize the data for polygons with holes
        size_t numFaceVertices = polygon->getFaceVertexCounts().size();
        uint currentFaceIndex = 0;
        uint faceVertexCounts = polygon->getFaceVertexCounts()[currentFaceIndex];

        // Iterate through the vertexes of the current polygon
        for ( uint vertexPosition=0; vertexPosition<numVertices; ++vertexPosition )
        {
            // Handle front face vs back face by walking the vertexes backward on the back-face
            uint vertexIndexPosition = polygonPosition * numVertices + vertexPosition;
            int iteratorVertexIndex = vertexIndices[vertexIndexPosition];
            int vertexIndex = meshPolygonsIter.vertexIndex ( iteratorVertexIndex );

            // If we write a holed polygon and the actual vertex position is the last
            // position of the current face, then go to the next face in the list.
            if ( exportType == PolygonSource::POLYGONS &&
                    polygon->isHoled() &&
                    vertexPosition == faceVertexCounts )
            {
                // Increment, cause we have found the next face
                ++currentFaceIndex;

                // Close the tag for the last face
                ( ( COLLADASW::Polygons* ) primitivesBasePoly )->closeElement();

                // Get the vertex count of the current face
                uint currentFaceVertexCount = polygon->getFaceVertexCounts()[currentFaceIndex];
                // Add the vertex count of the current face to the sum of face vertexes
                faceVertexCounts += currentFaceVertexCount;

                // Check if the current face is a normal polygon or a hole and open the corresponding tag.
                openPolygonOrHoleElement ( primitivesBasePoly, polygon, currentFaceIndex );
            }

            // Write the vertex indices
            writeVertexIndices ( primitivesBasePoly, polygon, vertexIndex, normalIndices, iteratorVertexIndex, meshPolygonsIter, fnMesh, polyIndex );
        }
    }

    // Add the tags for the polygons
    if ( exportType == PolygonSource::POLYGONS )
    {
        if ( polygon->isHoled() )
            ( ( COLLADASW::Polygons* ) primitivesBasePoly )->closeElement();

        ( ( COLLADASW::Polygons* ) primitivesBasePoly )->closeElement();
    }
}