#include <math.h>
#include <maya/MIOStream.h>
#include "apiMeshShape.h"
#include "apiMeshShapeUI.h"
#include "apiMeshGeometryOverride.h"
#include "apiMeshSubSceneOverride.h"
#include "apiMeshCreator.h"
#include "apiMeshData.h"
#include <api_macros.h>
#include <maya/MFnDependencyNode.h>
#include <maya/MFnPlugin.h>
#include <maya/MFnPluginData.h>
#include <maya/MDrawRegistry.h>
#include <maya/MMatrix.h>
#include <maya/MAttributeSpecArray.h>
#include <maya/MAttributeSpec.h>
#include <maya/MAttributeIndex.h>
#include <maya/MObjectArray.h>
#include <maya/MFnSingleIndexedComponent.h>
#include <maya/MDagPath.h>
#include <maya/MFnAttribute.h>
#include <maya/MFnNumericAttribute.h>
#include <maya/MFnTypedAttribute.h>
#include <maya/MPointArray.h>
#include <maya/MViewport2Renderer.h>
#include <maya/MPlane.h>
#include <maya/MArrayDataBuilder.h>
namespace
{
bool debug = false;
const char* sPlugConnection = "->-";
                     void *clientData)
{
    apiMesh *pMesh = static_cast<apiMesh *>(clientData);
    {
        pMesh->setMaterialDirty(true);
    }
}
}
MObject apiMesh::useWeightedTransformUsingFunction;
 
MObject apiMesh::useWeightedTweakUsingFunction;
 
apiMesh::apiMesh() {}
apiMesh::~apiMesh()
{
    for(std::map<std::string, MCallbackId>::const_iterator i = fMaterialDirtyCbIds.begin();
        i != fMaterialDirtyCbIds.end(); i++)
    {
    }
}
void apiMesh::postConstructor()
{
    
    
    setRenderable( true );
    
    
    fHasHistoryOnCreate = false;
    
    
    fShapeDirty = true;
    fMaterialDirty = true;
}
{
    if (debug)
        cerr << 
"apiMesh::compute : plug " << plug.
info() << endl;
    if ( plug == outputSurface ) {
        return computeOutputSurface( plug, datablock );
    }
    else if ( plug == cachedSurface ) {
        return computeOutputSurface( plug, datablock );
    }
    else if ( plug == worldSurface ) {
        return computeWorldSurface( plug, datablock );
    }
    else {
    }
}
{
    
    
    if ( plug == inputSurface ||
         plug == mControlPoints ||
         plug == mControlValueX ||
         plug == mControlValueY ||
         plug == mControlValueZ )
    {
        signalDirtyToViewport();
    }
}
{
    bool isOk = true;
    if( (plug == mControlPoints) ||
        (plug == mControlValueX) ||
        (plug == mControlValueY) ||
        (plug == mControlValueZ) )
    {
        
        
        
        
        
        
        
        if ( hasHistory() ) {
        }
        else {
            double val = 0.0;
            if ( (plug == mControlPoints) && !plug.
isArray() ) {
 
                value( index, pnt );
                result.
set( pnt[0], pnt[1], pnt[2] );
            }
            else if ( plug == mControlValueX ) {
                value( index, 0, val );
            }
            else if ( plug == mControlValueY ) {
                value( index, 1, val );
            }
            else if ( plug == mControlValueZ ) {
                value( index, 2, val );
            }
        }
    }
    
    
    
    
    
    
    
    else if ( plug == mHasHistoryOnCreate ) {
        result.
set( fHasHistoryOnCreate );
    }
    else {
    }
    return isOk;
}
{
    bool isOk = true;
    if( (plug == mControlPoints) ||
        (plug == mControlValueX) ||
        (plug == mControlValueY) ||
        (plug == mControlValueZ) )
    {
        
        
        
        
        
        
        
        
        
        if ( hasHistory() ) {
            verticesUpdated();
        }
        else {
            if( plug == mControlPoints && !plug.
isArray()) {
 
                setValue( index, point );
            }
            else if( plug == mControlValueX ) {
                setValue( index, 0, handle.
asDouble() );
            }
            else if( plug == mControlValueY ) {
                setValue( index, 1, handle.
asDouble() );
            }
            else if( plug == mControlValueZ ) {
                setValue( index, 2, handle.
asDouble() );
            }
        }
    }
    
    
    
    
    
    
    
    else if ( plug == mHasHistoryOnCreate ) {
        fHasHistoryOnCreate = handle.
asBool();
    }
    else {
    }
    return isOk;
}
                                 bool asSrc )
{
    if ( plug == inputSurface )
    {
        MPlug historyPlug( thisObj, mHasHistoryOnCreate );
 
        stat = historyPlug.setValue( true );
        MCHECKERROR( stat, "connectionMade: setValue(mHasHistoryOnCreate)" );
    }
    else if ( asSrc )
    {
        {
            setMaterialDirty(true);
                otherNode, MaterialDirtyCb, this, &stat);
            if (stat)
            {
                k += sPlugConnection;
#ifdef _DEBUG
                cout << "apiMesh::connectionMade: " << k << endl;
#endif
                fMaterialDirtyCbIds[k] = cbId;
            }
        }
    }
}
                                   bool asSrc )
{
    if ( plug == inputSurface )
    {
        MPlug historyPlug( thisObj, mHasHistoryOnCreate );
 
        stat = historyPlug.setValue( false );
        MCHECKERROR( stat, "connectionBroken: setValue(mHasHistoryOnCreate)" );
    }
    {
        setMaterialDirty(true);
        k += sPlugConnection;
#ifdef _DEBUG
        cout << "apiMesh::connectionBroken: " << k << endl;
#endif
        if (fMaterialDirtyCbIds.find(k) != fMaterialDirtyCbIds.end())
        {
            fMaterialDirtyCbIds.erase(k);
        }
    }
}
MStatus apiMesh::shouldSave( 
const MPlug& plug, 
bool& result )
 
{
    if( plug == mControlPoints || plug == mControlValueX ||
        plug == mControlValueY || plug == mControlValueZ )
    {
        if( hasHistory() ) {
            
            
            
        }
        else {
            result = false;
        }
    }
    else if ( plug == cachedSurface ) {
        if ( hasHistory() ) {
            result = false;
        }
        else {
            MCHECKERROR( status, "shouldSave: MPlug::getValue" );
        }
    }
    else {
    }
    return status;
}
void apiMesh::componentToPlugs( 
MObject & component,
 
{
        apiMesh* nonConstPtr = (apiMesh*)this;
        MObject vtxComp = nonConstPtr->convertToVertexComponent(component);
 
        MPlug plug( thisNode, mControlPoints );
 
        
        
        
        convertToTweakNodePlug(plug);
        int len = fnVtxComp.elementCount();
        for ( int i = 0; i < len; i++ )
        {
            list.add(plug);
        }
    }
}
{
    
    
    
    
    if ( (1 == spec.
length()) && (dim > 0) && (attrSpec.
name() == 
"vtx") ) {
 
        int numVertices = meshGeom()->vertices.length();
        int upper = 0;
        int lower = 0;
        }
        }
        
        
        if ( (lower > upper) || (upper >= numVertices) ) {
        }
        else {
            for ( int i=lower; i<=upper; i++ )
            {
            }
            list.
add( path, vtxComp );
        }
    }
    else {
        
    }
    return result;
}
{
    bool result = false;
    if( componentList.length() == 0 ) {
    }
    else {
        for ( int i=0; i<(int)componentList.length(); i++ ) {
            ) {
                result = true;
                break;
            }
        }
    }
    return result;
}
{
}
{
    return retVal;
}
MObject apiMesh::createFullVertexGroup() const
 
{
    
    
    
    
    
    int numVertices = ((apiMesh*)this)->meshGeom()->vertices.length();
    return fullComponent;
}
MObject apiMesh::localShapeInAttr() const
 
{
    return inputSurface;
}
MObject apiMesh::localShapeOutAttr() const
 
{
    return outputSurface;
}
MObject apiMesh::worldShapeOutAttr() const
 
{
    return worldSurface;
}
MObject apiMesh::cachedShapeAttr() const
 
{
    return cachedSurface;
}
MObject apiMesh::geometryData() const
 
{
    apiMesh* nonConstThis = (apiMesh*)this;
    MDataBlock datablock = nonConstThis->forceCache();
 
}
void apiMesh:: closestPoint ( 
const MPoint & toThisPoint, \
 
                MPoint & theClosestPoint, 
double tolerance ) 
const 
{
    
    
    
    apiMeshGeom* geomPtr = ((apiMesh*)this)->meshGeom();
    int numVertices = geomPtr->vertices.length();
    for (int ii=0; ii<numVertices; ii++)
    {
        MPoint tryThisOne = geomPtr->vertices[ii];
 
    }
    
    
    theClosestPoint = geomPtr->vertices[0];
}
void apiMesh::transformUsing( 
const MMatrix & mat,
 
{
    
    
    transformUsing( mat,
                    componentList,
                    NULL);
}
void apiMesh::transformUsing( 
const MMatrix & mat,
 
                              MVertexCachingMode cachingMode,
{
    apiMeshGeom* geomPtr = meshGeom();
    
    
    unsigned int i=0,j=0;
    unsigned int len = componentList.
length();
 
    if ( restorePoints ) {
        
        
        unsigned int cacheLen = pointCache->
length();
 
        if (len > 0) {
            
            
            for ( i = 0; i < len && j < cacheLen; i++ )
            {
                MObject comp = convertToVertexComponent(componentList[i]);
 
                int elemCount = fnComp.elementCount();
                for ( int idx=0; idx<elemCount && j < cacheLen; idx++, ++j ) {
                    int elemIndex = fnComp.element( idx );
                    geomPtr->vertices[elemIndex] = (*pointCache)[j];
                }
            }
        } else {
            
            
            
            len = geomPtr->vertices.length();
            for ( unsigned int idx = 0; idx < len && j < cacheLen; ++idx, ++j ) {
                geomPtr->vertices[idx] = (*pointCache)[j];
            }
        }
    } else {
        
        
        
        if (len > 0) {
            
            
            for ( i=0; i<len; i++ )
            {
                MObject comp = convertToVertexComponent(componentList[i]);
 
                int elemCount = fnComp.elementCount();
                if (savePoints && 0 == i) {
                }
                for ( int idx=0; idx<elemCount; idx++ )
                {
                    int elemIndex = fnComp.element( idx );
                    if (savePoints) {
                        pointCache->
append(geomPtr->vertices[elemIndex]);
                    }
                    geomPtr->vertices[elemIndex] *= mat;
                    geomPtr->normals[idx] =
                        geomPtr->normals[idx].transformAsNormal( mat );
                }
            }
        } else {
            
            
            
            len = geomPtr->vertices.length();
            if (savePoints) {
            }
            for ( unsigned int idx = 0; idx < len; ++idx ) {
                if (savePoints) {
                    pointCache->
append(geomPtr->vertices[idx]);
                }
                geomPtr->vertices[idx] *= mat;
                geomPtr->normals[idx] =
                    geomPtr->normals[idx].transformAsNormal( mat );
            }
        }
    }
    
    updateCachedSurface( geomPtr, componentList );
}
void apiMesh::updateCachedSurface( 
const apiMeshGeom* geomPtr, 
const MObjectArray & componentList )
 
{
    unsigned int len = componentList.
length();
 
    
    
    
    
    
    
    
    
    MCHECKERRORNORET( stat, "computeInputSurface error getting cachedSurface")
    apiMeshData* cached = (apiMeshData*) cachedHandle.asPluginData();
    MDataHandle dHandle = datablock.outputValue( mControlPoints, &stat );
 
    MCHECKERRORNORET( stat, "updateCachedSurface get dHandle" )
    
    
    
    if ( hasHistory() && (NULL != cached) ) {
        
        
        
        
        stat = buildControlPoints( datablock, geomPtr->vertices.length() );
        MCHECKERRORNORET( stat, "updateCachedSurface buildControlPoints" )
        MCHECKERRORNORET( stat, "updateCachedSurface get cpHandle" )
        
        
        for ( unsigned int i=0; i<len; i++ )
        {
            MObject comp = convertToVertexComponent(componentList[i]);
 
            int elemCount = fnComp.elementCount();
            for ( int idx=0; idx<elemCount; idx++ )
            {
                int elemIndex = fnComp.element( idx );
                cpHandle.jumpToElement( elemIndex );
                MPoint oldPnt = cached->fGeometry->vertices[elemIndex];
 
                MPoint newPnt = geomPtr->vertices[elemIndex];
 
                MPoint offset = newPnt - oldPnt;
 
                pnt[0] += offset[0];
                pnt[1] += offset[1];
                pnt[2] += offset[2];
            }
        }
    }
    
    
    if ( NULL == cached ) {
        cerr << "NULL cachedSurface data found\n";
    }
    else {
        *(cached->fGeometry) = *geomPtr;
    }
    MPlug pCPs(thisMObject(),mControlPoints);
 
    pCPs.setValue(dHandle);
    
    
    computeBoundingBox( datablock );
    
    
    
    
    signalDirtyToViewport();
}
void
apiMesh::tweakUsing( 
const MMatrix & mat,
                     MVertexCachingMode cachingMode,
{
    apiMeshGeom* geomPtr = meshGeom();
    
    
    unsigned int i=0;
    unsigned int len = componentList.
length();
 
    unsigned int cacheIndex = 0;
    unsigned int cacheLen = (NULL != pointCache) ? pointCache->
length() : 0;
 
    if ( restorePoints ) {
        
        
        if (len > 0) {
            
            
            for ( i=0; i<len; i++ )
            {
                MObject comp = convertToVertexComponent(componentList[i]);
 
                int elemCount = fnComp.elementCount();
                for ( int idx=0; idx<elemCount && cacheIndex < cacheLen; idx++, cacheIndex++) {
                    int elemIndex = fnComp.element( idx );
                    MPoint& cachePt = (*pointCache)[cacheIndex];
 
                }
            }
        } else {
            
            
            
            len = geomPtr->vertices.length();
            for ( unsigned int idx = 0; idx < len && idx < cacheLen; ++idx ) {
                MPoint& cachePt = (*pointCache)[cacheIndex];
 
            }
        }
    } else {
        
        
        
        
        if (len > 0) {
            for ( i=0; i<len; i++ )
            {
                MObject comp = convertToVertexComponent(componentList[i]);
 
                int elemCount = fnComp.elementCount();
                if (savePoints) {
                }
                for ( int idx=0; idx<elemCount; idx++ )
                {
                    int elemIndex = fnComp.element( idx );
                    currPt = newPt = geomPtr->vertices[elemIndex];
                    newPt *= mat;
                    delta.
x = newPt.
x - currPt.
x;
                    delta.
y = newPt.
y - currPt.
y;
                    delta.
z = newPt.
z - currPt.
z;
                    if (savePoints) {
                        
                        
                        pointCache->
append(delta*(-1.0));
                    } else if (updatePoints && cacheIndex < cacheLen) {
                        MPoint& cachePt = (*pointCache)[cacheIndex];
 
                        cacheIndex++;
                    }
                }
            }
        } else {
            
            
            
            len = geomPtr->vertices.length();
            if (savePoints) {
            }
            for ( unsigned int idx = 0; idx < len; ++idx ) {
                currPt = newPt = geomPtr->vertices[idx];
                newPt *= mat;
                delta.
x = newPt.
x - currPt.
x;
                delta.
y = newPt.
y - currPt.
y;
                delta.
z = newPt.
z - currPt.
z;
                if (savePoints) {
                    
                    
                    pointCache->
append(delta*-1.0);
                } else if (updatePoints && idx < cacheLen) {
                    MPoint& cachePt = (*pointCache)[idx];
 
                }
            }
        }
    }
    
    
    
    
    
    
    signalDirtyToViewport();
}
                                        MVertexCachingMode cachingMode,
{
    
    
    
    MPlug plg_useWeightedTransformUsingFunction( thisMObject(), useWeightedTransformUsingFunction );
 
    bool val_useWeightedTransformUsingFunction = plg_useWeightedTransformUsingFunction.asBool();
    if (!val_useWeightedTransformUsingFunction)
    {
        signalDirtyToViewport();
        return;
    }
    
    
    
    if (space) {
    }
    
    
    apiMeshGeom* geomPtr = meshGeom();
    float almostZero = 1.0e-5f; 
    int pointCacheIndex = 0;
    unsigned int len = componentList.
length();
 
    for ( unsigned int i=0; i<len; i++ )
    {
        MObject comp = convertToVertexComponent(componentList[i]);
 
        int elemCount = fnComp.elementCount();
        bool hasWeights = fnComp.hasWeights();
        bool hasSeam = (NULL != freezePlane);
        if (savePoints && (0 == i) ) {
        }
        for ( int idx=0; idx<elemCount; idx++ )
        {
            int elemIndex = fnComp.element( idx );
            float perc = (hasWeights) ? fnComp.weight(idx).influence() : 1.0f;
            
            if (perc > almostZero) { 
                if (restorePoints) {
                    
                    geomPtr->vertices[elemIndex] = 
MVector( (*pointCache)[pointCacheIndex] );
                    pointCacheIndex++;
                }
                else { 
                    
                    if (savePoints) {
                        pointCache->
append( geomPtr->vertices[elemIndex] );
                    }
                    else if ( transformOrigPoints ) { 
                        geomPtr->vertices[elemIndex] = 
MVector( (*pointCache)[pointCacheIndex] );
                    }
                    else if ( updatePoints ) { 
                        (*pointCache)[pointCacheIndex] = geomPtr->vertices[elemIndex];
                    }
                    
                    if (perc == 1.0) {
                    }
                    else {
                        mat = (space) ? (*space) * xform.
asMatrix(perc) * (spaceInv) : xform.
asMatrix(perc) ;
                    }
                    
                    MPoint pt = geomPtr->vertices[elemIndex];  
 
                    newp *= mat;
                    
                    if( hasSeam && fnComp.weight(idx).seam() > 0.0f)
                    {
                    }
                    
                    geomPtr->vertices[elemIndex] = 
MVector( newp );
                    pointCacheIndex++;
                }
            }
        }
    }
    
    updateCachedSurface( geomPtr, componentList );
}
void apiMesh::weightedTweakUsing(
                            MVertexCachingMode cachingMode,
{
    
    
    
    MPlug plg_useWeightedTweakUsingFunction( thisMObject(), useWeightedTweakUsingFunction );
 
    bool val_useWeightedTweakUsingFunction = plg_useWeightedTweakUsingFunction.asBool();
    if (!val_useWeightedTweakUsingFunction) {
    }
    apiMeshGeom* geomPtr = meshGeom();
    
    
    unsigned int i=0;
    unsigned int len = componentList.
length();
 
    unsigned int cacheIndex = 0;
    unsigned int cacheLen = (NULL != pointCache) ? pointCache->
length() : 0;
 
    if ( restorePoints ) {
        
        
        
        
        for ( i=0; i<len; i++ )
        {
            MObject comp = convertToVertexComponent(componentList[i]);
 
            int elemCount = fnComp.elementCount();
            for ( int idx=0; idx<elemCount && cacheIndex < cacheLen; idx++, cacheIndex++) {
                int elemIndex = fnComp.element( idx );
                MPoint& cachePt = (*pointCache)[cacheIndex];
 
            }
        }
    } else {
        
        
        
        
        
        float almostZero = 1.0e-5f; 
        if (space) {
        }
        for ( i=0; i<len; i++ )
        {
            MObject comp = convertToVertexComponent(componentList[i]);
 
            int elemCount = fnComp.elementCount();
            bool hasWeights = fnComp.hasWeights(); 
            bool hasSeam = (NULL != freezePlane);  
            if (savePoints) {
            }
            for ( int idx=0; idx<elemCount; idx++ )
            {
                int elemIndex = fnComp.element( idx );
                float perc = (hasWeights) ? fnComp.weight(idx).influence() : 1.0f; 
                
                if (perc > almostZero) { 
                    
                    
                    if (perc == 1.0) {
                    }
                    else {
                        mat = (space) ? (*space) * xform.
asMatrix(perc) * (spaceInv) : xform.
asMatrix(perc) ;
                    }
                    
                    
                    
                    if ( transformOrigPoints ) {
                        geomPtr->vertices[elemIndex] = 
MVector( (*pointCache)[cacheIndex] );
                    }
                    
                    
                    currPt = newPt = geomPtr->vertices[elemIndex];
                    newPt *= mat;
                    
                    
                    if( hasSeam && fnComp.weight(idx).seam() > 0.0f)
                    {
                    }
                    
                    delta.
x = newPt.
x - currPt.
x;
                    delta.
y = newPt.
y - currPt.
y;
                    delta.
z = newPt.
z - currPt.
z;
                    if (savePoints) {
                        
                        
                        pointCache->
append(delta*(-1.0));
                    } else if (updatePoints && cacheIndex < cacheLen) {
                        MPoint& cachePt = (*pointCache)[cacheIndex];
 
                        cacheIndex++;
                    }
                }
            }
        }
    }
    
    
    
    
    
}
bool apiMesh::vertexOffsetDirection( 
MObject & component,
 
                                     MVertexOffsetMode mode,
                                     bool normalize )
{
    bool offsetOkay = false ;
    MObject vtxComp = convertToVertexComponent(component);
 
        return false;
    }
    offsetOkay = true ;
    apiMeshGeom * geomPtr = meshGeom();
    if ( NULL == geomPtr ) {
        return false;
    }
    
    
    int count = fnComp.elementCount();
    for ( int idx=0; idx<count; idx++ )
    {
        MVector normal = geomPtr->normals[ fnComp.element(idx) ];
 
        }
        else {
            
            
            
            int    i, j, k;
            double a;
            i = 0;  a = fabs( normal[0] );
            if ( a < fabs(normal[1]) ) { i = 1; a = fabs(normal[1]); }
            if ( a < fabs(normal[2]) ) i = 2;
            j = (i+1)%3;  k = (j+1)%3;
            a = sqrt(normal[i]*normal[i] + normal[j]*normal[j]);
            uAxis[i] = -normal[j]/a; uAxis[j] = normal[i]/a; uAxis[k] = 0.0;
            vAxis = normal^uAxis;
            {
            }
            {
            }
            }
        }
    }
    return offsetOkay ;
}
bool apiMesh::isBounded() const
{
    return true;
}
{
    if ( fShapeDirty )
    {
        
        apiMesh *msPtr = (apiMesh *)this;
        
        msPtr->meshDataRef();
    }
    MPlug   c1Plug( thisNode, bboxCorner1 );
 
    MPlug   c2Plug( thisNode, bboxCorner2 );
 
    c1Plug.getValue( corner1Object );
    c2Plug.getValue( corner2Object );
    double3 corner1, corner2;
    fnData.
getData( corner1[0], corner1[1], corner1[2] );
    fnData.
getData( corner2[0], corner2[1], corner2[2] );
    MPoint corner1Point( corner1[0], corner1[1], corner1[2] );
 
    MPoint corner2Point( corner2[0], corner2[1], corner2[2] );
 
}
{
    {
        
        MFn::Type srcComponentType = srcComponent.componentType();
 
        std::set<int> srcIndices;
        for (int i=0; i<srcComponent.elementCount(); ++i)
            srcIndices.insert( srcComponent.element(i) );
        const apiMeshGeom* geomPtr = meshGeom();
        unsigned int base = 0;
        int edgeId = 0;
        for (int faceIdx=0; faceIdx<geomPtr->faceCount; faceIdx++)
        {
            
            int numVerts = geomPtr->face_counts[faceIdx];
            if (numVerts > 2)
            {
                for (int v=0; v<numVerts; v++)
                {
                    {
                        if (srcIndices.count(edgeId))
                        {
                            unsigned int vindex1 = base + (v % numVerts);
                            unsigned int vindex2 = base + ((v+1) % numVerts);
                            int vertexId1 = geomPtr->face_connects[vindex1];
                            int vertexId2 = geomPtr->face_connects[vindex2];
                            vtxComponent.addElement(vertexId1);
                            vtxComponent.addElement(vertexId2);
                        }
                        ++edgeId;
                    }
                    else
                    {
                        
                        if (srcIndices.count(faceIdx))
                        {
                            unsigned int vindex = base + (v % numVerts);
                            int vertexId = geomPtr->face_connects[vindex];
                            vtxComponent.addElement(vertexId);
                        }
                    }
                }
                base += numVerts;
            }
        }
    }
    return retVal;
}
                                                    bool forReadOnly )
{
    apiMeshGeomIterator * result = NULL;
        for ( 
int i=0; i<(int)componentList.
length(); i++ ) 
 
        {
            vtxComponents.
append(convertToVertexComponent(componentList[i]));
        }
        result = new apiMeshGeomIterator( meshGeom(), vtxComponents );
    }
    else {
        MObject vtxComponent = convertToVertexComponent(components);
 
        result = new apiMeshGeomIterator( meshGeom(), vtxComponent );
    }
    return result;
}
bool apiMesh::acceptsGeometryIterator( bool writeable )
{
    return true;
}
bool apiMesh::acceptsGeometryIterator( 
MObject&, 
bool writeable,
 
                                       bool forReadOnly )
{
    return true;
}
bool apiMesh::hasHistory()
{
    return fHasHistoryOnCreate;
}
bool apiMesh::shapeDirty()
{
    return fShapeDirty;
}
void apiMesh::resetShapeDirty()
{
    fShapeDirty = false;
}
bool apiMesh::materialDirty() const
{
    return fMaterialDirty;
}
void apiMesh::setMaterialDirty(bool dirty)
{
    fMaterialDirty = dirty;
}
{
    
    
    apiMeshGeom* geomPtr = meshGeom();
    int cnt = geomPtr->vertices.length();
    if ( cnt == 0 ) return stat;
    
    
    MPoint tmppnt = geomPtr->vertices[0];
 
    lower[0] = tmppnt[0]; lower[1] = tmppnt[1]; lower[2] = tmppnt[2];
    upper[0] = tmppnt[0]; upper[1] = tmppnt[1]; upper[2] = tmppnt[2];
    for ( int i=0; i<cnt; i++ )
    {
        MPoint pnt = geomPtr->vertices[i];
 
        if ( pnt[0] < lower[0] ) lower[0] = pnt[0];
        if ( pnt[1] < lower[1] ) lower[1] = pnt[1];
        if ( pnt[2] > lower[2] ) lower[2] = pnt[2];
        if ( pnt[0] > upper[0] ) upper[0] = pnt[0];
        if ( pnt[1] > upper[1] ) upper[1] = pnt[1];
        if ( pnt[2] < upper[2] ) upper[2] = pnt[2];
    }
    
    
    return stat;
}
{
    
    
    if ( hasHistory() ) {
        MCHECKERROR( stat, "computeInputSurface error getting inputSurface")
            apiMeshData* surf = (apiMeshData*) inputHandle.asPluginData();
        if ( NULL == surf ) {
            cerr << "NULL inputSurface data found\n";
            return stat;
        }
        apiMeshGeom* geomPtr = surf->fGeometry;
        
        
        fnDataCreator.
create( tmpid, &stat );
        MCHECKERROR( stat, "compute : error creating Cached apiMeshData")
            apiMeshData * newCachedData = (apiMeshData*)fnDataCreator.data( &stat );
        MCHECKERROR( stat, " error gettin proxy cached apiMeshData object")
            *(newCachedData->fGeometry) = *geomPtr;
        MDataHandle cachedHandle = datablock.outputValue( cachedSurface,&stat );
 
        MCHECKERROR( stat, "computeInputSurface error getting cachedSurface")
            cachedHandle.set( newCachedData );
    }
    return stat;
}
{
    
    
    
    if ( ! computeInputSurface( plug, datablock ) ) {
    }
    
    
    MDataHandle cachedHandle = datablock.outputValue( cachedSurface, &stat );
 
    MCHECKERROR( stat, "computeInputSurface error getting cachedSurface")
    apiMeshData* cached = (apiMeshData*) cachedHandle.asPluginData();
    if ( NULL == cached ) {
        cerr << "NULL cachedSurface data found\n";
    }
    
    
    if ( hasHistory() ) {
        applyTweaks( datablock, cached->fGeometry );
    }
    else {
                                                           &stat );
    }
    
    
    fnDataCreator.
create( tmpid, &stat );
    MCHECKERROR( stat, "compute : error creating apiMeshData")
    apiMeshData * newData = (apiMeshData*)fnDataCreator.data( &stat );
    MCHECKERROR( stat, "compute : error gettin at proxy apiMeshData object")
    
    
    if ( NULL != cached ) {
        *(newData->fGeometry) = *(cached->fGeometry);
    }
    else {
        cerr << "computeOutputSurface: NULL cachedSurface data\n";
    }
    
    
    MDataHandle outHandle = datablock.outputValue( outputSurface );
 
    outHandle.
set( newData );
    
    
    stat = computeBoundingBox( datablock );
    MCHECKERROR( stat, "computeBoundingBox" )
    return stat;
}
{
    computeOutputSurface( plug, datablock );
    MDataHandle inHandle = datablock.outputValue( outputSurface );
 
    apiMeshData* outSurf = (apiMeshData*)inHandle.
asPluginData();
    if ( NULL == outSurf ) {
        cerr << "computeWorldSurface: outSurf NULL\n";
    }
    
    
    fnDataCreator.
create( tmpid, &stat );
    MCHECKERROR( stat, "compute : error creating apiMeshData")
    apiMeshData * newData = (apiMeshData*)fnDataCreator.data( &stat );
    MCHECKERROR( stat, "compute : error gettin at proxy apiMeshData object")
    
    MMatrix worldMat = getWorldMatrix(datablock, 0);
 
    newData->setMatrix( worldMat );
    
    
    *(newData->fGeometry) = *(outSurf->fGeometry);
    
    
    int arrayIndex = plug.logicalIndex( &stat );
    MCHECKERROR( stat, "computWorldSurface : logicalIndex" );
                                                               &stat );
    MCHECKERROR( stat, "computWorldSurface : outputArrayValue" );
    MCHECKERROR( stat, "computWorldSurface : builder" );
    MDataHandle outHandle = builder.addElement( arrayIndex, &stat );
 
    MCHECKERROR( stat, "computWorldSurface : addElement" );
    outHandle.set( newData );
    return stat;
}
{
                                                           &stat );
    MCHECKERROR( stat, "applyTweaks get cpHandle" )
    
    
    int elemCount = cpHandle.elementCount();
    for ( int idx=0; idx<elemCount; idx++ )
    {
        MPoint offset( pnt[0], pnt[1], pnt[2] );
 
        
        
        if (elemIndex < (int)geomPtr->vertices.length())
        {
            MPoint& oldPnt = geomPtr->vertices[elemIndex];
 
            oldPnt = oldPnt + offset;
        }
    }
    return stat;
}
bool apiMesh::value( int pntInd, int vlInd, double & val ) const
{
    bool result = false;
    apiMesh* nonConstThis = (apiMesh*)this;
    apiMeshGeom* geomPtr = nonConstThis->cachedGeom();
    if ( NULL != geomPtr ) {
        MPoint point = geomPtr->vertices[ pntInd ];
 
        val = point[ vlInd ];
        result = true;
    }
    return result;
}
bool apiMesh::value( 
int pntInd, 
MPoint & val ) 
const 
{
    bool result = false;
    apiMesh* nonConstThis = (apiMesh*)this;
    apiMeshGeom* geomPtr = nonConstThis->cachedGeom();
    if ( NULL != geomPtr ) {
        MPoint point = geomPtr->vertices[ pntInd ];
 
        val = point;
        result = true;
    }
    return result;
}
bool apiMesh::setValue( int pntInd, int vlInd, double val )
{
    bool result = false;
    apiMesh* nonConstThis = (apiMesh*)this;
    apiMeshGeom* geomPtr = nonConstThis->cachedGeom();
    if ( NULL != geomPtr ) {
        MPoint& point = geomPtr->vertices[ pntInd ];
 
        point[ vlInd ] = val;
        result = true;
    }
    verticesUpdated();
    return result;
}
bool apiMesh::setValue( 
int pntInd, 
const MPoint & val )
 
{
    bool result = false;
    apiMesh* nonConstThis = (apiMesh*)this;
    apiMeshGeom* geomPtr = nonConstThis->cachedGeom();
    if ( NULL != geomPtr ) {
        geomPtr->vertices[ pntInd ] = val;
        result = true;
    }
    verticesUpdated();
    return result;
}
{
    
    
    
    
    
    
}
apiMeshGeom* apiMesh::meshGeom()
{
    apiMeshGeom * result = NULL;
    apiMeshData * data = (apiMeshData*)fnData.data( &stat );
    MCHECKERRORNORET( stat, "meshGeom : Failed to get apiMeshData");
    if ( NULL != data ) {
        result = data->fGeometry;
    }
    return result;
}
{
    
    
}
apiMeshGeom* apiMesh::cachedGeom()
{
    apiMeshGeom * result = NULL;
    apiMeshData * data = (apiMeshData*)fnData.data( &stat );
    MCHECKERRORNORET( stat, "cachedGeom : Failed to get apiMeshData");
    if ( NULL != data ) {
        result = data->fGeometry;
    }
    return result;
}
{
    MCHECKERROR( stat, "compute get cpH" )
    if ( count != (int)oldBuilder.elementCount() )
    {
        
        
        MCHECKERROR( stat, "compute - create builder" )
        for ( int vtx=0; vtx<count; vtx++ )
        {
           builder.addElement( vtx ).asDouble3();
        }
    }
    return stat;
}
void apiMesh::verticesUpdated()
{
}
void apiMesh::signalDirtyToViewport()
{
    fShapeDirty = true;
}
void* apiMesh::creator()
{
    return new apiMesh();
}
{
    
    inputSurface = typedAttr.
create( 
"inputSurface", 
"is",
                                      apiMeshData::id,
    MCHECKERROR( stat, "create inputSurface attribute" )
    typedAttr.setStorable( false );
    ADD_ATTRIBUTE( inputSurface );
    useWeightedTransformUsingFunction = numericAttr.create( "useWeightedTransformUsingFunction", "utru", 
MFnNumericData::kBoolean, true, &stat);
    MCHECKERROR( stat, "create useWeightedTransformUsingFunction attribute" )
    numericAttr.setKeyable(true);
    ADD_ATTRIBUTE( useWeightedTransformUsingFunction );
    useWeightedTweakUsingFunction = numericAttr.create( "useWeightedTweakUsingFunction", "utwu", 
MFnNumericData::kBoolean, true, &stat);
    MCHECKERROR( stat, "create useWeightedTweakUsingFunction attribute" )
    numericAttr.setKeyable(true);
    ADD_ATTRIBUTE( useWeightedTweakUsingFunction );
    
    
    
    MAKE_NUMERIC_ATTR(  bboxCorner1, "bboxCorner1", "bb1",
                        false, false, false );
    MAKE_NUMERIC_ATTR(  bboxCorner2, "bboxCorner2", "bb2",
                        false, false, false );
    
    
    outputSurface = typedAttr.create( "outputSurface", "os",
                                      apiMeshData::id,
    MCHECKERROR( stat, "create outputSurface attribute" )
    ADD_ATTRIBUTE( outputSurface );
    typedAttr.setWritable( false );
    worldSurface = typedAttr.create( "worldSurface", "ws",
                                      apiMeshData::id,
    MCHECKERROR( stat, "create worldSurface attribute" );
    typedAttr.setCached( false );
    typedAttr.setWritable( false );
    stat = typedAttr.setArray( true );
    MCHECKERROR( stat, "set array" );
    stat = typedAttr.setUsesArrayDataBuilder( true );
    MCHECKERROR( stat, "set uses array data builder" );
    stat = typedAttr.setDisconnectBehavior( 
MFnAttribute::kDelete );
    MCHECKERROR( stat, "set disconnect behavior data builder" );
    stat = typedAttr.setWorldSpace( true );
    MCHECKERROR( stat, "set world space" );
    ADD_ATTRIBUTE( worldSurface );
    
    
    cachedSurface = typedAttr.create( "cachedSurface", "cs",
                                      apiMeshData::id,
    MCHECKERROR( stat, "create cachedSurface attribute" )
    typedAttr.setReadable( true );
    typedAttr.setWritable( true );
    typedAttr.setStorable( true );
    ADD_ATTRIBUTE( cachedSurface );
    
    
    ATTRIBUTE_AFFECTS( inputSurface, outputSurface );
    ATTRIBUTE_AFFECTS( inputSurface, worldSurface );
    ATTRIBUTE_AFFECTS( outputSurface, worldSurface );
    ATTRIBUTE_AFFECTS( inputSurface, bboxCorner1 );
    ATTRIBUTE_AFFECTS( inputSurface, bboxCorner2 );
    ATTRIBUTE_AFFECTS( cachedSurface, outputSurface );
    ATTRIBUTE_AFFECTS( cachedSurface, worldSurface );
    ATTRIBUTE_AFFECTS( mControlPoints, outputSurface );
    ATTRIBUTE_AFFECTS( mControlValueX, outputSurface );
    ATTRIBUTE_AFFECTS( mControlValueY, outputSurface );
    ATTRIBUTE_AFFECTS( mControlValueZ, outputSurface );
    ATTRIBUTE_AFFECTS( mControlPoints, cachedSurface );
    ATTRIBUTE_AFFECTS( mControlValueX, cachedSurface );
    ATTRIBUTE_AFFECTS( mControlValueY, cachedSurface );
    ATTRIBUTE_AFFECTS( mControlValueZ, cachedSurface );
    ATTRIBUTE_AFFECTS( mControlPoints, worldSurface );
    ATTRIBUTE_AFFECTS( mControlValueX, worldSurface );
    ATTRIBUTE_AFFECTS( mControlValueY, worldSurface );
    ATTRIBUTE_AFFECTS( mControlValueZ, worldSurface );
}
static bool sUseSubSceneOverride = (getenv("MAYA_APIMESHSHAPE_USE_SUBSCENEOVERRIDE") != NULL);
static 
MString sDrawDbClassification(sUseSubSceneOverride
    ? "drawdb/subscene/apiMesh"
    : "drawdb/geometry/apiMesh");
static 
MString sDrawRegistrantId("apiMeshPlugin");
{
    MFnPlugin plugin( obj, PLUGIN_COMPANY, 
"3.0", 
"Any");
 
    MStatus stat1, stat2, stat3, stat4;
 
    stat1 = plugin.registerData( "apiMeshData", apiMeshData::id,
                                  &apiMeshData::creator,
    if ( ! stat1 ) {
        cerr << "Failed to register geometry data : apiMeshData \n";
        return stat1;
    }
    stat2 = plugin.registerShape( "apiMesh", apiMesh::id,
                                   &apiMesh::creator,
                                   &apiMesh::initialize,
                                   &apiMeshUI::creator,
                                   &sDrawDbClassification );
    if ( ! stat2 ) {
        cerr << "Failed to register shape\n";
        if ( stat1) plugin.deregisterData( apiMeshData::id );
        return stat2;
    }
    stat3 = plugin.registerNode( "apiMeshCreator", apiMeshCreator::id,
                                 &apiMeshCreator::creator,
                                 &apiMeshCreator::initialize  );
    if ( ! stat3 ) {
        cerr << "Failed to register creator\n";
        if ( stat2 ) {
            plugin.deregisterNode( apiMesh::id );
            plugin.deregisterData( apiMeshData::id );
        }
    }
    if (sUseSubSceneOverride)
    {
                    sDrawDbClassification,
                    sDrawRegistrantId,
                    apiMeshSubSceneOverride::Creator);
        if (!stat4)
        {
            cerr << "Failed to register Viewport 2.0 sub-scene override\n";
        }
        else {
            stat4 = apiMeshSubSceneOverride::registerComponentConverters();
            if (!stat4)
            {
                cerr << "Failed to register component converters\n";
            }
        }
    }
    else
    {
                    sDrawDbClassification,
                    sDrawRegistrantId,
                    apiMeshGeometryOverride::Creator);
        if (!stat4)
        {
            cerr << "Failed to register Viewport 2.0 geometry override\n";
        }
        else {
            stat4 = apiMeshGeometryOverride::registerComponentConverters();
            if (!stat4)
            {
                cerr << "Failed to register component converters\n";
            }
        }
    }
    return stat3;
}
{
    if (sUseSubSceneOverride)
    {
        stat = apiMeshSubSceneOverride::deregisterComponentConverters();
        if (!stat)
        {
            cerr << "Failed to deregister component converters \n";
        }
                    sDrawDbClassification,
                    sDrawRegistrantId);
        if (!stat)
        {
            cerr << "Failed to deregister sub-scene override : apiMeshSubSceneOverride \n";
        }
    }
    else
    {
        stat = apiMeshGeometryOverride::deregisterComponentConverters();
        if (!stat)
        {
            cerr << "Failed to deregister component converters \n";
        }
                    sDrawDbClassification,
                    sDrawRegistrantId);
        if (!stat)
        {
            cerr << "Failed to deregister geometry override : apiMeshGeometryOverride \n";
        }
    }
    stat = plugin.deregisterNode( apiMesh::id );
    if ( ! stat ) {
        cerr << "Failed to deregister shape : apiMeshShape \n";
    }
    stat = plugin.deregisterData( apiMeshData::id );
    if ( ! stat ) {
        cerr << "Failed to deregister geometry data : apiMeshData \n";
    }
    stat = plugin.deregisterNode( apiMeshCreator::id );
    if ( ! stat ) {
        cerr << "Failed to deregister node : apiMeshCreator \n";
    }
    return stat;
}