#include "util.h"
#include "MeshHelper.h"
#include "NodeIteratorVisitorHelper.h"
#include <maya/MTypes.h>
#include <maya/MString.h>
#include <maya/MFloatPoint.h>
#include <maya/MFloatPointArray.h>
#include <maya/MIntArray.h>
#include <maya/MUintArray.h>
#include <maya/MFnMesh.h>
#include <maya/MFnMeshData.h>
#include <maya/MItMeshPolygon.h>
#include <maya/MItMeshVertex.h>
#include <maya/MFnAttribute.h>
#include <maya/MFnNumericData.h>
#include <maya/MFnNumericAttribute.h>
#include <maya/MGlobal.h>
#include <maya/MVector.h>
namespace
{
    
    {
        unsigned int arrLength = iArray.
length();
 
        for (unsigned int i = 0; i < arrLength; ++i)
        {
            if (iArray[i] == iStr)
            {
                return true;
            }
        }
        return false;
    }
    
    
    {
        if (ptPlug.
isArray() && (numElements > 0))
 
        {
            for (unsigned int i = 0; i < numElements; i++)
            {
                MPlug elementPlug = ptPlug[i];
 
            }
        }
    }
    
    
    void setPolyNormals(
double iFrame, 
MFnMesh & ioMesh,
 
        Alembic::AbcGeom::IN3fGeomParam iNormals)
    {
        
        if (!iNormals)
            return;
        if (iNormals.getScope() != Alembic::AbcGeom::kVertexScope &&
            iNormals.getScope() != Alembic::AbcGeom::kVaryingScope &&
            iNormals.getScope() != Alembic::AbcGeom::kFacevaryingScope)
        {
                " normal vector has an unsupported scope, skipping normals");
            return;
        }
        Alembic::AbcCoreAbstract::index_t index, ceilIndex;
        double alpha = getWeightAndIndex(iFrame,
            iNormals.getTimeSampling(), iNormals.getNumSamples(),
            index, ceilIndex);
        Alembic::AbcGeom::IN3fGeomParam::Sample samp;
        iNormals.getExpanded(samp, Alembic::Abc::ISampleSelector(index));
        Alembic::Abc::N3fArraySamplePtr sampVal = samp.getVals();
        size_t sampSize = sampVal->size();
        Alembic::Abc::N3fArraySamplePtr ceilVals;
        if (alpha != 0 && index != ceilIndex)
        {
            Alembic::AbcGeom::IN3fGeomParam::Sample ceilSamp;
            iNormals.getExpanded(ceilSamp,
                Alembic::Abc::ISampleSelector(ceilIndex));
            ceilVals = ceilSamp.getVals();
            if (sampSize == ceilVals->size())
            {
                Alembic::Abc::N3fArraySamplePtr ceilVal = ceilSamp.getVals();
                for (size_t i = 0; i < sampSize; ++i)
                {
                        simpleLerp<float>(alpha, (*sampVal)[i].x,
                            (*ceilVal)[i].x),
                        simpleLerp<float>(alpha, (*sampVal)[i].y,
                            (*ceilVal)[i].y),
                        simpleLerp<float>(alpha, (*sampVal)[i].z,
                            (*ceilVal)[i].z));
                }
            }
            else
            {
                for (size_t i = 0; i < sampSize; ++i)
                {
                    MVector normal((*sampVal)[i].x, (*sampVal)[i].y,
 
                        (*sampVal)[i].z);
                }
            }
        }
        else
        {
            for (size_t i = 0; i < sampSize; ++i)
            {
                MVector normal((*sampVal)[i].x, (*sampVal)[i].y,
 
                    (*sampVal)[i].z);
            }
        }
        if ((iNormals.getScope() == Alembic::AbcGeom::kVertexScope ||
            iNormals.getScope() == Alembic::AbcGeom::kVaryingScope) &&
        {
            int iEnd = static_cast<int>(sampSize);
            for (int i = 0; i < iEnd; ++i)
            {
            }
        }
            iNormals.getScope() == Alembic::AbcGeom::kFacevaryingScope)
        {
            MIntArray faceList(static_cast<unsigned int>(sampSize));
 
            MIntArray vertexList(static_cast<unsigned int>(sampSize));
 
            
            int nIndex = 0;
            for (int faceIndex = 0; faceIndex < numFaces; faceIndex++)
            {
                int numVertices = polyVerts.
length();
 
                for (int v = numVertices - 1; v >= 0; v--, ++nIndex)
                {
                    faceList[nIndex] = faceIndex;
                    vertexList[nIndex] = polyVerts[v];
                }
            }
        }
        {
                " normal vector scope does not match size of data, " +
                "skipping normals");
        }
    }
        Alembic::Abc::P3fArraySamplePtr iPoints,
        Alembic::Abc::P3fArraySamplePtr iCeilPoints, double alpha)
    {
        unsigned int numPoints = static_cast<unsigned int>(iPoints->size());
        if (alpha == 0 || iCeilPoints == NULL)
        {
            for (unsigned int i = 0; i < numPoints; ++i)
            {
                    (*iPoints)[i].x, (*iPoints)[i].y, (*iPoints)[i].z);
            }
        }
        else
        {
            for (unsigned int i = 0; i < numPoints; ++i)
            {
                    simpleLerp<float>(alpha,
                        (*iPoints)[i].x, (*iCeilPoints)[i].x),
                    simpleLerp<float>(alpha,
                        (*iPoints)[i].y, (*iCeilPoints)[i].y),
                    simpleLerp<float>(alpha,
                        (*iPoints)[i].z, (*iCeilPoints)[i].z));
            }
        }
    }
        Alembic::Abc::Int32ArraySamplePtr iIndices,
        Alembic::Abc::Int32ArraySamplePtr iCounts)
    {
        
        
        unsigned int numPolys = static_cast<unsigned int>(iCounts->size());
        for (unsigned int i = 0; i < numPolys; ++i)
        {
            polyCounts[i] = (*iCounts)[i];
        }
        unsigned int numConnects = static_cast<unsigned int>(iIndices->size());
        unsigned int facePointIndex = 0;
        unsigned int base = 0;
        for (unsigned int i = 0; i < numPolys; ++i)
        {
            
            int curNum = polyCounts[i];
            for (int j = 0; j < curNum; ++j, ++facePointIndex)
                polyConnects[facePointIndex] = (*iIndices)[base+curNum-j-1];
            base += curNum;
        }
        {
                polyCounts, polyConnects);
        }
        else
        {
               polyCounts, polyConnects, iParent);
        }
    }
        const Alembic::Abc::UInt32ArraySamplePtr & iSampIndices,
    {
        
        int nIndex = 0;
        int uvCountsIndex = 0;
        
        {
            for (int faceIndex = 0; faceIndex < numFaces; faceIndex++)
            {
                uvCounts[uvCountsIndex++] = numVertices;
                int curIndex = nIndex;
                for (int v = numVertices - 1; v >= 0; v--, ++nIndex)
                {
                    uvIds[nIndex] = (int)(*iSampIndices)[curIndex + v];
                }
            }
        }
        
        else
        {
            for (int faceIndex = 0; faceIndex < numFaces; faceIndex++)
            {
                uvCounts[uvCountsIndex++] = numVertices;
                for (int v = numVertices - 1; v >= 0; v--, ++nIndex)
                {
                    uvIds[nIndex] =
                        (int)(*iSampIndices)[vertexList[numVertices - v - 1]];
                }
            }
        }
        
        {
        }
        {
            return;
        }
        else
        {
            status = ioMesh.
assignUVs(uvCounts, uvIds, &iUVSetName);
        }
        {
        }
    }
    void setUV2f(
double iFrame, 
MFnMesh & ioMesh,
 
        const Alembic::AbcGeom::IV2fGeomParam & iV2f,
        const Alembic::AbcGeom::IUInt32ArrayProperty & indexProperty,
    {
        
        Alembic::AbcCoreAbstract::index_t index, ceilIndex;
        double alpha = getWeightAndIndex(iFrame, iV2f.getTimeSampling(),
            iV2f.getNumSamples(), index, ceilIndex);
        Alembic::AbcGeom::IV2fGeomParam::Sample samp;
        iV2f.getIndexed(samp, Alembic::Abc::ISampleSelector(index));
        Alembic::Abc::V2fArraySamplePtr sampVal = samp.getVals();
        size_t sampSize = sampVal->size();
            ioMesh.
numVertices() != (int) samp.getIndices()->size())
        {
            MString msg = 
"UV set sample size is: ";
 
            msg += (int) samp.getIndices()->size();
            msg += " expecting: ";
            msg += " or ";
            return;
        }
        {
            return;
        }
        
        
        if ( alpha != 0 && index != ceilIndex &&
            (!indexProperty || indexProperty.isConstant()) )
        {
            Alembic::AbcGeom::IV2fGeomParam::Sample ceilSamp;
            iV2f.getIndexed(ceilSamp,
                    Alembic::Abc::ISampleSelector(ceilIndex));
            Alembic::Abc::V2fArraySamplePtr ceilVal = ceilSamp.getVals();
            
            if (ceilVal->size() == sampSize)
            {
                for (size_t i = 0; i < sampSize; ++i)
                {
                            simpleLerp<float>(alpha, (*sampVal)[i].x,
                                    (*ceilVal)[i].x));
                            simpleLerp<float>(alpha, (*sampVal)[i].y,
                                    (*ceilVal)[i].y));
                }
            }
            else
            {
                for (size_t i = 0; i < sampSize; ++i)
                {
                    uList.
append((*sampVal)[i].x);
                    vList.
append((*sampVal)[i].y);
                }
            }
        }
        else
        {
            for (size_t i = 0; i < sampSize; ++i)
            {
                uList.
append((*sampVal)[i].x);
                vList.
append((*sampVal)[i].y);
            }
        }
        setUVSet(ioMesh, uList, vList, samp.getIndices(), iUVSetName);
    }
    {
        {
        }
    }
        const Alembic::AbcCoreAbstract::MetaData & iMetaData)
    {
        MStatus status = meshIO.
createColorSetDataMesh(iSetName);
 
        {
            if (iMetaData.get("mayaColorSet") == "1")
            {
            }
#if MAYA_API_VERSION > 201200
#endif
        }
    }
        Alembic::Abc::UInt32ArraySamplePtr & iSampIndices,
    {
        
        int nIndex = 0;
        bool isFacevarying =
        if (isFacevarying)
        {
            for (int faceIndex = 0; faceIndex < numFaces; faceIndex++)
            {
                int curIndex = nIndex;
                for (int v = numVertices - 1; v >= 0; v--, ++nIndex)
                {
                    assignmentList[nIndex] = (int)(*iSampIndices)[curIndex + v];
                }
            }
        }
        else
        {
            for (int faceIndex = 0; faceIndex < numFaces; faceIndex++)
            {
                for (int v = numVertices - 1; v >= 0; v--, ++nIndex)
                {
                    assignmentList[nIndex] =
                        (int)(*iSampIndices)[vertexList[v]];
                }
            }
        }
        {
            return;
        }
        else
        {
        }
        {
        }
    }
    void setColor3f(
double iFrame, 
MFnMesh & ioMesh,
 
        Alembic::AbcGeom::IC3fGeomParam & iC3f)
    {
        
        Alembic::AbcCoreAbstract::index_t index, ceilIndex;
        double alpha = getWeightAndIndex(iFrame, iC3f.getTimeSampling(),
            iC3f.getNumSamples(), index, ceilIndex);
        Alembic::AbcGeom::IC3fGeomParam::Sample samp;
        iC3f.getIndexed(samp, Alembic::Abc::ISampleSelector(index));
        Alembic::Abc::C3fArraySamplePtr sampVal = samp.getVals();
        size_t sampSize = sampVal->size();
            ioMesh.
numVertices() != (int) samp.getIndices()->size())
        {
            MString msg = 
"Color sample size is: ";
 
            msg += (int) samp.getIndices()->size();
            msg += " expecting: ";
            msg += " or ";
            return;
        }
        {
            return;
        }
        
        
        if ( alpha != 0 && index != ceilIndex &&
            (!iC3f.getIndexProperty() || iC3f.getIndexProperty().isConstant()) )
        {
            Alembic::AbcGeom::IC3fGeomParam::Sample ceilSamp;
            iC3f.getIndexed(ceilSamp,
                    Alembic::Abc::ISampleSelector(ceilIndex));
            Alembic::Abc::C3fArraySamplePtr ceilVal = ceilSamp.getVals();
            
            if (sampSize == ceilVal->size())
            {
                for (size_t i = 0; i < sampSize; ++i)
                {
                            simpleLerp<float>(alpha, (*sampVal)[i].x,
                                    (*ceilVal)[i].x),
                            simpleLerp<float>(alpha, (*sampVal)[i].y,
                                    (*ceilVal)[i].y),
                            simpleLerp<float>(alpha, (*sampVal)[i].z,
                                    (*ceilVal)[i].z));
                }
            }
            else
            {
                for (size_t i = 0; i < sampSize; ++i)
                {
                    colorList.
append((*sampVal)[i].x, (*sampVal)[i].y,
                            (*sampVal)[i].z);
                }
            }
        }
        else
        {
            for (size_t i = 0; i < sampSize; ++i)
            {
                colorList.
append((*sampVal)[i].x, (*sampVal)[i].y,
                        (*sampVal)[i].z);
            }
        }
        MString colorSetName(iC3f.getName().c_str());
 
        Alembic::Abc::UInt32ArraySamplePtr indices = samp.getIndices();
        setColor(ioMesh, colorList, indices, colorSetName, 
MFnMesh::kRGB);
    }
    void setColor4f(
double iFrame, 
MFnMesh & ioMesh,
 
        Alembic::AbcGeom::IC4fGeomParam & iC4f)
    {
        
        Alembic::AbcCoreAbstract::index_t index, ceilIndex;
        double alpha = getWeightAndIndex(iFrame, iC4f.getTimeSampling(),
            iC4f.getNumSamples(), index, ceilIndex);
        Alembic::AbcGeom::IC4fGeomParam::Sample samp;
        iC4f.getIndexed(samp, Alembic::Abc::ISampleSelector(index));
        Alembic::Abc::C4fArraySamplePtr sampVal = samp.getVals();
        size_t sampSize = sampVal->size();
            ioMesh.
numVertices() != (int) samp.getIndices()->size())
        {
                "Color sample size != num face vertices");
            return;
        }
        
        if ( alpha != 0 && index != ceilIndex &&
            (!iC4f.getIndexProperty() || iC4f.getIndexProperty().isConstant()) )
        {
            Alembic::AbcGeom::IC4fGeomParam::Sample ceilSamp;
            iC4f.getIndexed(ceilSamp,
                    Alembic::Abc::ISampleSelector(ceilIndex));
            Alembic::Abc::C4fArraySamplePtr ceilVal = ceilSamp.getVals();
            
            if (sampSize == ceilVal->size())
            {
                for (size_t i = 0; i < sampSize; ++i)
                {
                            simpleLerp<float>(alpha, (*sampVal)[i].r,
                                    (*ceilVal)[i].r),
                            simpleLerp<float>(alpha, (*sampVal)[i].g,
                                    (*ceilVal)[i].g),
                            simpleLerp<float>(alpha, (*sampVal)[i].b,
                                    (*ceilVal)[i].b),
                            simpleLerp<float>(alpha, (*sampVal)[i].a,
                                    (*ceilVal)[i].a)
                                    );
                }
            }
            else
            {
                for (size_t i = 0; i < sampSize; ++i)
                {
                    colorList.
append((*sampVal)[i].r, (*sampVal)[i].g,
                            (*sampVal)[i].b, (*sampVal)[i].a);
                }
            }
        }
        else
        {
            for (size_t i = 0; i < sampSize; ++i)
            {
                colorList.
append((*sampVal)[i].r, (*sampVal)[i].g,
                        (*sampVal)[i].b, (*sampVal)[i].a);
            }
        }
        MString colorSetName(iC4f.getName().c_str());
 
        Alembic::Abc::UInt32ArraySamplePtr indices = samp.getIndices();
    }
    typedef std::vector< Alembic::AbcGeom::IV2fGeomParam > IV2fGPVec;
    typedef std::vector< Alembic::AbcGeom::IC3fGeomParam > IC3fGPVec;
    typedef std::vector< Alembic::AbcGeom::IC4fGeomParam > IC4fGPVec;
    void setColorsAndUVs(
double iFrame, 
MFnMesh & ioMesh,
 
        Alembic::AbcGeom::IV2fGeomParam iPrimaryV2f,
        IV2fGPVec iV2s, IC3fGPVec iC3s, IC4fGPVec iC4s, bool iSetStatic)
    {
        if (iPrimaryV2f.getNumSamples() < 1 && iV2s.empty() && iC3s.empty() &&
            iC4s.empty())
        {
            return;
        }
        if (iPrimaryV2f.getNumSamples() > 0 &&
            (iSetStatic || !iPrimaryV2f.isConstant()))
        {
                Alembic::Abc::GetSourceName(iPrimaryV2f.getMetaData()).c_str();
            {
                uvSetName = "map1";
            }
            if (!inStrArray(uvSetNames, uvSetName))
            {
                createUVset(ioMesh, uvSetName);
            }
            setUV2f(iFrame, ioMesh, iPrimaryV2f,
                iPrimaryV2f.getIndexProperty(), uvSetName);
        }
        IV2fGPVec::const_iterator v2sEnd = iV2s.end();
        for (IV2fGPVec::iterator v2s = iV2s.begin(); v2s != v2sEnd; ++v2s)
        {
            if (v2s->getNumSamples() > 0 && (iSetStatic || !v2s->isConstant()))
            {
                MString uvSetName(v2s->getName().c_str());
 
                if (!inStrArray(uvSetNames, uvSetName))
                {
                    createUVset(ioMesh, uvSetName);
                }
                setUV2f(iFrame, ioMesh, *v2s, v2s->getIndexProperty(), uvSetName);
            }
        }
        IC3fGPVec::const_iterator c3sEnd = iC3s.end();
        for (IC3fGPVec::iterator c3s = iC3s.begin(); c3s != c3sEnd; ++c3s)
        {
            if (c3s->getNumSamples() > 0 && (iSetStatic || !c3s->isConstant()))
            {
                MString colorSetName(c3s->getName().c_str());
 
                if (!inStrArray(colorSetNames, colorSetName))
                {
                    createColorSet(ioMesh, colorSetName, c3s->getMetaData());
                    colorSetNames.
append(colorSetName);
                }
                setColor3f(iFrame, ioMesh, *c3s);
            }
        }
        IC4fGPVec::const_iterator c4sEnd = iC4s.end();
        for (IC4fGPVec::iterator c4s = iC4s.begin(); c4s != c4sEnd; ++c4s)
        {
            if (c4s->getNumSamples() > 0 && (iSetStatic || !c4s->isConstant()))
            {
                MString colorSetName(c4s->getName().c_str());
 
                if (!inStrArray(colorSetNames, colorSetName))
                {
                    createColorSet(ioMesh, colorSetName, c4s->getMetaData());
                    colorSetNames.
append(colorSetName);
                }
                setColor4f(iFrame, ioMesh, *c4s);
            }
        }
    }
    void fillCreases(
MFnMesh & ioMesh, SubDAndFriends & iNode,
 
                     Alembic::Abc::FloatArraySamplePtr creases,
                     Alembic::Abc::Int32ArraySamplePtr indices,
                     Alembic::Abc::Int32ArraySamplePtr lengths)
    {
        if (!creases || creases->size() == 0)
        {
            return;
        }
        
        
        
        
        typedef std::map<std::pair<int, int>, int> EdgeMap;
        EdgeMap edgeMap;
        for (int i = 0; i < numEdges; i++)
        {
            int vertexList[2];
            if (vertexList[0] > vertexList[1])
            {
                std::swap(vertexList[0], vertexList[1]);
            }
            edgeMap.insert(std::make_pair(
                std::make_pair(vertexList[0], vertexList[1]), i));
        }
        std::size_t numLengths = lengths->size();
        std::size_t curIndex = 0;
        
        for (std::size_t i = 0; i < numLengths; ++i, ++curIndex)
        {
            std::size_t len = (*lengths)[i] - 1;
            float creaseSharpness = (*creases)[i];
            
            
            for (std::size_t j = 0; j < len; ++j, ++curIndex)
            {
                Alembic::Util::int32_t vertA = (*indices)[curIndex];
                Alembic::Util::int32_t vertB = (*indices)[curIndex+1];
                std::pair<int, int> edge = std::make_pair(vertA, vertB);
                if (edge.first > edge.second)
                {
                    std::swap(edge.first, edge.second);
                }
                EdgeMap::iterator iter = edgeMap.find(edge);
                if (iter != edgeMap.end() && iter->second < numEdges)
                {
                    creaseData.
append(creaseSharpness);
                }
            }
        }
        {
            MString warn = 
"Failed to set creases on: ";
 
            warn += iNode.mMesh.getName().c_str();
            printWarning(warn);
        }
    }
    void fillCorners(
MFnMesh & ioMesh, SubDAndFriends & iNode,
 
                     Alembic::Abc::FloatArraySamplePtr corners,
                     Alembic::Abc::Int32ArraySamplePtr cornerVerts)
    {
        if (!corners || corners->size() == 0)
        {
            return;
        }
        unsigned int numCorners = static_cast<unsigned int>(corners->size());
        for (unsigned int i = 0; i < numCorners; ++i)
        {
            cornerData[i] = (*corners)[i];
            vertIds[i] = (*cornerVerts)[i];
        }
        {
            MString warn = 
"Failed to set corners on: ";
 
            warn += iNode.mMesh.getName().c_str();
            printWarning(warn);
        }
    }
    void fillHoles(
MFnMesh & ioMesh, SubDAndFriends & iNode,
 
                   Alembic::Abc::Int32ArraySamplePtr holes)
    {
    #if MAYA_API_VERSION >= 201100
        if (!holes || holes->size() == 0)
        {
            return;
        }
        unsigned int numHoles = (unsigned int)holes->size();
        for (unsigned int i = 0; i < numHoles; ++i)
        {
            holeData[i] = (*holes)[i];
        }
        {
            MString warn = 
"Failed to set holes on: ";
 
            warn += iNode.mMesh.getName().c_str();
            printWarning(warn);
        }
    #endif
    }
    void fillCreasesCornersAndHoles(
MFnMesh & ioMesh, SubDAndFriends & iNode,
 
        Alembic::AbcGeom::ISubDSchema::Sample &samp)
    {
        fillCreases(ioMesh, iNode, samp.getCreaseSharpnesses(),
                    samp.getCreaseIndices(), samp.getCreaseLengths());
        fillCorners(ioMesh, iNode, samp.getCornerSharpnesses(),
                    samp.getCornerIndices());
        fillHoles(ioMesh, iNode, samp.
getHoles());
    }
}  
    PolyMeshAndFriends & iNode, bool iInitialized)
{
    Alembic::AbcGeom::IPolyMeshSchema schema = iNode.mMesh.getSchema();
    Alembic::AbcGeom::MeshTopologyVariance ttype = schema.getTopologyVariance();
    Alembic::AbcCoreAbstract::index_t index, ceilIndex;
    double alpha = getWeightAndIndex(iFrame,
        schema.getTimeSampling(), schema.getNumSamples(), index, ceilIndex);
    Alembic::Abc::P3fArraySamplePtr ceilPoints;
    
    if (ttype != Alembic::AbcGeom::kHeterogenousTopology && iInitialized)
    {
        Alembic::Abc::P3fArraySamplePtr points = schema.getPositionsProperty(
            ).getValue(Alembic::Abc::ISampleSelector(index));
        if (alpha != 0.0)
        {
            ceilPoints = schema.getPositionsProperty().getValue(
                Alembic::Abc::ISampleSelector(ceilIndex) );
        }
        fillPoints(pointArray, points, ceilPoints, alpha);
        setColorsAndUVs(iFrame, ioMesh, schema.getUVsParam(),
            iNode.mV2s, iNode.mC3s, iNode.mC4s, !iInitialized);
        if (schema.getNormalsParam().getNumSamples() > 1)
        {
            setPolyNormals(iFrame, ioMesh, schema.getNormalsParam());
        }
        return;
    }
    
    Alembic::AbcGeom::IPolyMeshSchema::Sample samp;
    schema.get(samp, Alembic::Abc::ISampleSelector(index));
    if (alpha != 0.0 && ttype != Alembic::AbcGeom::kHeterogenousTopology)
    {
        ceilPoints = schema.getPositionsProperty().getValue(
            Alembic::Abc::ISampleSelector(ceilIndex) );
    }
    fillPoints(pointArray, samp.getPositions(), ceilPoints, alpha);
    fillTopology(ioMesh, iParent, pointArray, samp.getFaceIndices(),
        samp.getFaceCounts());
    setPolyNormals(iFrame, ioMesh, schema.getNormalsParam());
    setColorsAndUVs(iFrame, ioMesh, schema.getUVsParam(),
        iNode.mV2s, iNode.mC3s, iNode.mC4s, !iInitialized);
}
    SubDAndFriends & iNode, bool iInitialized)
{
    Alembic::AbcGeom::ISubDSchema schema = iNode.mMesh.getSchema();
    Alembic::AbcGeom::MeshTopologyVariance tv = schema.getTopologyVariance();
    Alembic::AbcCoreAbstract::index_t index, ceilIndex;
    double alpha = getWeightAndIndex(iFrame,
        schema.getTimeSampling(), schema.getNumSamples(), index, ceilIndex);
    Alembic::Abc::P3fArraySamplePtr ceilPoints;
    
    if (tv != Alembic::AbcGeom::kHeterogenousTopology && iInitialized)
    {
        Alembic::Abc::ISampleSelector sampSel(index);
        Alembic::Abc::P3fArraySamplePtr points =
            schema.getPositionsProperty().getValue(sampSel);
        if (alpha != 0.0)
        {
            ceilPoints = schema.getPositionsProperty().getValue(
                Alembic::Abc::ISampleSelector(ceilIndex) );
        }
        fillPoints(pointArray, points, ceilPoints, alpha);
        setColorsAndUVs(iFrame, ioMesh, schema.getUVsParam(), iNode.mV2s,
            iNode.mC3s, iNode.mC4s, !iInitialized);
        return;
    }
    
    Alembic::AbcGeom::ISubDSchema::Sample samp;
    schema.get(samp, Alembic::Abc::ISampleSelector(index));
    if (alpha != 0.0 && tv != Alembic::AbcGeom::kHeterogenousTopology)
    {
        ceilPoints = schema.getPositionsProperty().getValue(
            Alembic::Abc::ISampleSelector(ceilIndex) );
    }
    fillPoints(pointArray, samp.getPositions(), ceilPoints, alpha);
    fillTopology(ioMesh, iParent, pointArray, samp.getFaceIndices(),
        samp.getFaceCounts());
    setColorsAndUVs(iFrame, ioMesh, schema.getUVsParam(),
        iNode.mV2s, iNode.mC3s, iNode.mC4s, !iInitialized);
    fillCreasesCornersAndHoles(ioMesh, iNode, samp);
}
void disconnectMesh(
MObject & iMeshObject,
 
    std::vector<Prop> & iSampledPropList,
    std::size_t iFirstProp)
{
    
    
    disconnectAllPlugsTo(dstPlug);
    disconnectProps(fnMesh, iSampledPropList, iFirstProp);
    clearPt(fnMesh);
    return;
}
MObject createPoly(
double iFrame, PolyMeshAndFriends & iNode, 
MObject & iParent)
 
{
    Alembic::AbcGeom::IPolyMeshSchema schema = iNode.mMesh.getSchema();
    MString name(iNode.mMesh.getName().c_str());
 
    
    if (!schema.isConstant())
    {
        obj = fnMesh.
create(0, 0, emptyPt, emptyInt, emptyInt, iParent);
    }
    else
    {
        Alembic::AbcCoreAbstract::index_t index, ceilIndex;
        double alpha = getWeightAndIndex(iFrame, schema.getTimeSampling(),
            schema.getNumSamples(), index, ceilIndex);
        Alembic::AbcGeom::IPolyMeshSchema::Sample samp;
        schema.get(samp, Alembic::Abc::ISampleSelector(index));
        Alembic::Abc::P3fArraySamplePtr ceilPoints;
        if (index != ceilIndex)
        {
            Alembic::AbcGeom::IPolyMeshSchema::Sample ceilSamp;
            schema.
get(ceilSamp, Alembic::Abc::ISampleSelector(ceilIndex));
            ceilPoints = ceilSamp.getPositions();
        }
        fillPoints(ptArray, samp.getPositions(), ceilPoints, alpha);
        fillTopology(fnMesh, iParent, ptArray, samp.getFaceIndices(),
            samp.getFaceCounts());
        fnMesh.
setName(iNode.mMesh.getName().c_str());
        setPolyNormals(iFrame, fnMesh, schema.getNormalsParam());
        obj = fnMesh.object();
    }
    MString pathName = fnMesh.partialPathName();
 
    setInitialShadingGroup(pathName);
    setColorsAndUVs(iFrame, fnMesh, schema.getUVsParam(),
        iNode.mV2s, iNode.mC3s, iNode.mC4s, true);
    if ( !schema.getNormalsParam().valid() )
    {
    }
    return obj;
}
MObject createSubD(
double iFrame, SubDAndFriends & iNode, 
MObject & iParent)
 
{
    Alembic::AbcGeom::ISubDSchema schema = iNode.mMesh.getSchema();
    Alembic::AbcCoreAbstract::index_t index, ceilIndex;
    getWeightAndIndex(iFrame, schema.getTimeSampling(),
        schema.getNumSamples(), index, ceilIndex);
    Alembic::AbcGeom::ISubDSchema::Sample samp;
    schema.get(samp, Alembic::Abc::ISampleSelector(index));
    MString name(iNode.mMesh.getName().c_str());
 
    Alembic::Abc::P3fArraySamplePtr emptyPtr;
    fillPoints(pointArray, samp.getPositions(), emptyPtr, 0.0);
    fillTopology(fnMesh, iParent, pointArray, samp.getFaceIndices(),
        samp.getFaceCounts());
    fnMesh.setName(iNode.mMesh.getName().c_str());
    setInitialShadingGroup(fnMesh.partialPathName());
    setColorsAndUVs(iFrame, fnMesh, schema.getUVsParam(),
        iNode.mV2s, iNode.mC3s, iNode.mC4s, true);
    
    MString attrName(
"SubDivisionMesh");
 
    MObject attrObj = numAttr.create(attrName, attrName,
 
    numAttr.setKeyable(true);
    numAttr.setHidden(false);
    if (samp.getInterpolateBoundary() > 0)
    {
        attrName = 
MString(
"interpolateBoundary");
            samp.getInterpolateBoundary());
        numAttr.setKeyable(true);
        numAttr.setHidden(false);
    }
    if (samp.getFaceVaryingInterpolateBoundary() > 0)
    {
        attrName = 
MString(
"faceVaryingInterpolateBoundary");
            samp.getFaceVaryingInterpolateBoundary());
        numAttr.setKeyable(true);
        numAttr.setHidden(false);
    }
    if (samp.getFaceVaryingPropagateCorners() > 0)
    {
        attrName = 
MString(
"faceVaryingPropagateCorners");
            samp.getFaceVaryingPropagateCorners());
        numAttr.setKeyable(true);
        numAttr.setHidden(false);
    }
    fillCreasesCornersAndHoles(fnMesh, iNode, samp);
    return obj;
}