#include <maya/MPxNode.h> 
#include <maya/MString.h> 
#include <maya/MTypeId.h> 
#include <maya/MPlug.h>
#include <maya/MDataBlock.h>
#include <maya/MDataHandle.h>
#include <maya/MFnPlugin.h>
#include <maya/MAngle.h>
#include <maya/MFnUnitAttribute.h>
#include <maya/MFnNumericAttribute.h>
#include <maya/MFnTypedAttribute.h>
#include <maya/MFloatPoint.h>
#include <maya/MFloatPointArray.h>
#include <maya/MIntArray.h>
#include <maya/MDoubleArray.h>
#include <maya/MFnMesh.h>
#include <maya/MFnMeshData.h>
#include <maya/MItMeshVertex.h>
#include <math.h>
#include <maya/MIOStream.h>
#define Rad(x)  ((x)*FPI/180.0F)
#define Deg(x)  ((x)*180.0F/FPI)
#define FPI 3.14159265358979323846264338327950288419716939937510582F 
#define McheckErr(stat,msg)         \
    if ( MS::kSuccess != stat ) {   \
        cerr << msg;                \
        return MS::kFailure;        \
    }
{
public:
    shellNode();
    virtual ~shellNode(); 
    static  void *          creator();
public: 
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
private:
    struct ShellParams {
        float   alpha;      
        float   beta;       
        float   phi;        
        float   my;         
        float   omega;      
        float   omin;       
        float   omax;       
        float   od;         
        float   smin;       
        float   smax;       
        float   sd;         
        float   A;          
        float   a;          
        float   b;          
        float   scale;      
        
        
        float   P;          
        float   L;          
        float   N;          
        float   W1;         
        float   W2;         
        float   nstart;     
        
        
        float   P2;
        float   L2;
        float   N2;
        float   W12;
        float   W22;
        float   off2;
        float   nstart2;
        
        
        float   P3;
        float   L3;
        float   N3;
        float   W13;
        float   W23;
        float   off3;
        float   nstart3;
        
        
        float   uamp;       
        float   ufreq;      
        float   urib;       
        float   vamp;       
        float   vfreq;      
        float   vrib;       
    };
    ShellParams shellParams;
    bool        redoTopology;
    bool        rebuild;
    
    
    int ni;
    int nj;
    float   **pnts;
private:
                                    MString briefName, 
float attrDefault );
 
                                    MString briefName, 
float attrDefault );
 
    void  UpdateParameters(); 
    void  RedoTopology();
    void  Rebuild();
    float Nodules( float s, float o );
    float Ribs( float u, float v );
    void  Eval( float   *p, float o, float s );
};
shellNode::shellNode()
 :  rebuild( true ),
    redoTopology( true ),
    pnts( NULL ),
    ni( 0 ),
    nj( 0 )
{}
shellNode::~shellNode() {}
{    
    int i, j;
    
    
    
    UpdateParameters();
    bool createNewMesh = redoTopology;
    RedoTopology();
    Rebuild();
    
    if (plug == outMesh) {  
        
        McheckErr(returnStatus, "ERROR getting polygon data handle\n");
               
        if ( createNewMesh || mesh.
isNull() ) {
 
            McheckErr(returnStatus, "ERROR creating outputData");
            
            
            
            for( j=0; j<nj; ++j ) {
                for( i=0; i<ni; ++i ) {
                    const float *p= pnts[j] + 3*i;
                }
            }
            
            
            i= (nj-1)*(ni-1);
            while( i-- ) {
            }
            
            
            for( j=0; j<nj-1; ++j ) {
                for( i=0; i<ni-1; ++i ) {
                    int corner= i+j*ni;
                }
            }
            
            
            
            
                nj*ni,              
                (nj-1)*(ni-1),      
                vertices,           
                pcounts,            
                pconnect,           
                newOutputData,      
                &returnStatus
            );
            
            
            outputHandle.
set(newOutputData);
        } else {
            
            
            
            McheckErr(returnStatus, "ERROR creating iterator\n");
            
            for( j=0; j<nj; ++j ) {
                for( i=0; i<ni; ++i ) {
                    if ( vertIt.isDone() ) break;
                    const float *p= pnts[j] + 3*i;
                    vertIt.setPosition( 
MPoint(p[0],p[1],p[2]) );
                    vertIt.next();
                }
                if ( vertIt.isDone() ) break;
            }
        }
    }   
}
void* shellNode::creator()
{
    return new shellNode();
}
void shellNode::RedoTopology()
{
    if( !redoTopology ) return;
    redoTopology = false;
    int oldnj= pnts ? nj : 0;
    ni= 0;
    nj= 0;
    for( float s = shellParams.smin; 
         s < shellParams.smax; 
         s += shellParams.sd )  
    {
        ni++;   
    }
    for( float o = shellParams.omin; 
         o < shellParams.omax; 
         o += shellParams.od )  
    {
        nj++;   
    }
    if( nj<oldnj ) {
        for( int i = nj; i < oldnj; ++i ) {
            if( pnts[i] ) free( pnts[i] );
        }
    }
    if( nj!=oldnj) {
        pnts = (float**) realloc(pnts, nj*sizeof(float*));
    }
    if( nj>oldnj ) {
        memset( pnts+oldnj, 0, (nj-oldnj)*sizeof(float*) );
    }
    
    for(int j=0;j<nj;++j) {
        pnts[j] = (float*) realloc(pnts[j],3*ni*sizeof(float));
    }
}
void shellNode::Rebuild()
{
    if( !rebuild ) return;
    rebuild= 0;
    int     i;
    int     j;
    float   s;
    float   o;
    float   *p;
    o= shellParams.omin;
    for( j=0; j<nj; ++j )
    {
        s= shellParams.smin;
        p= pnts[j];
        for( i=0; i<ni; ++i )
        {
            Eval( p, o, s );
            s+=shellParams.sd;
            p+=3;
        }
        o+=shellParams.od;
    }
}
inline float SafeCot( float x )
{
    float s= sinf(x);
    return s ? cosf(x)/s : 0.0F;
}
inline float G( float a, float n )
{
    if( !n ) return n;
    float z= 2.0F*FPI;
    a*=n/z;
    return z/n*(a-floorf(0.5F+a));
}
float shellNode::Ribs( float u, float v )
{
    ShellParams & sp = shellParams;
    float zu=0.0F;
    if( sp.uamp )
    {
        zu= sp.uamp*cosf(2.0F*FPI*sp.ufreq*u);
        if( zu<0 ) zu*= (1.0F-2.0F*sp.urib);
    }
    float zv=0.0F;
    if( sp.vamp )
    {
        zv= sp.vamp*cosf(2.0F*FPI*sp.vfreq*v);
        if( zv<0 ) zv*= (1.0F-2.0F*sp.vrib);
    }
    return zu+zv;
}
float shellNode::Nodules( float s, float o )
{
    ShellParams & sp = shellParams;
    float p1;
    float p2;
    float k=0.0F;
    float g=0.0F;
    if( sp.L && sp.N && o>=sp.nstart )
    {
        g= G(o,sp.N);
        p1= g/sp.W2;
        p2= (s-sp.P)/sp.W1;
        k= sp.L*expf( -4.0F*(p1*p1+p2*p2) );
    }
    if( sp.L2 && sp.N2 && o>=sp.nstart2 )
    {
        g= G(o+sp.off2,sp.N2); 
        p1= g/sp.W22;
        p2= (s-sp.P2)/sp.W12;
        k+= sp.L2*expf( -4.0F*(p1*p1+p2*p2) );
    }
    if( sp.L3 && sp.N3 && o>= sp.nstart3 )
    {
        g= G(o+sp.off3, sp.N3);
        p1= g/sp.W23;
        p2= (s-sp.P3)/sp.W13;
        k+= sp.L3*expf( -4.0F*(p1*p1+p2*p2) );
    }
    return k;
}
void shellNode::Eval( float *p, float o, float s )
{
    ShellParams & sp = shellParams;
    float ss = sinf(s);
    float cs = cosf(s);
    float re = 1.0F/sqrtf(cs*cs/(sp.a*sp.a) 
               + ss*ss/(sp.b*sp.b));
    float sc = sp.scale*expf(o*SafeCot(sp.alpha));
    float csphi = cosf(s+sp.phi);
    float ssphi = sinf(s+sp.phi);
    float sbeta = sinf(sp.beta);
    float smy = sinf(sp.my);
    float r = re+Nodules(s,o)+Ribs(s,o);
    float x = sp.A*sbeta*cosf(o)        
              + r*csphi*cosf(o+sp.omega)    
              - r*smy*ssphi*sinf(o);
    float y = - sp.A*sbeta*sinf(o)  
              - r*csphi*sinf(o+sp.omega)    
              - r*smy*ssphi*cosf(o);
    float z = - sp.A*cosf(sp.beta)      
              + r*ssphi*cosf(sp.my);
    p[0] =  x*sc;
    p[1] = -z*sc;
    p[2] =  y*sc;
}
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
                                   MString briefName, 
float attrDefault )
 
{
                         0.0, &stat );
    stat = addAttribute( attr );
    
    stat = attributeAffects( attr, outMesh );
}
                                   MString briefName, 
float attrDefault )
 
{
    
    attr = uAttr.
create( longName, briefName, defaultAngle, &stat );
    stat = addAttribute( attr );
    
    stat = attributeAffects( attr, outMesh );
}
{
                              &stat ); 
        cerr << "ERROR creating animCube output attribute\n";
        return stat;
    }
    stat = addAttribute( outMesh );
    McheckErr(stat, "ERROR adding attribute");  
    
    try {
        addAngleParameter( alpha,   "profileParam1",           "pp1",   80.0F );
        addAngleParameter( beta,    "profileParam2",           "pp2",   90.0F );
        addAngleParameter( phi,     "sectionStartingPoint",    "ssp",    1.0F );
        addAngleParameter( my,      "sectionSlant",            "ss",     1.0F );
        addAngleParameter( omega,   "sectionAngleZ",           "saz",    1.0F );
        addAngleParameter( omin,    "spiralStartAngle",        "sps",    0.0F );
        addAngleParameter( omax,    "spiralEndAngle",          "spe", 1200.0F );
        addAngleParameter( od,      "spiralAngleStep",         "spa",    4.0F );
        addAngleParameter( smin,    "sectionStartAngle",       "ssa", -190.0F );
        addAngleParameter( smax,    "sectionEndAngle",         "sea",  190.0F );
        addAngleParameter( sd,      "sectionAngleStep",        "sas",   17.0F );
        addFloatParameter( A,       "distanceFromZ",           "dfz",    1.9F );
        addFloatParameter( a,       "sectionDiameter1",        "sd1",    1.0F );
        addFloatParameter( b,       "sectionDiameter2",        "sd2",    0.9F );
        addFloatParameter( scale,   "scale",                   "s",      0.03F );
        addAngleParameter( P,       "positionOnSection1",      "ps1",   10.0F );
        addFloatParameter( L,       "noduleAmplitude1",        "na1",    1.0F );
        addFloatParameter( N,       "noduleProfileFrequency1", "nf1",   15.0F );
        addAngleParameter( W1,      "noduleFatness11",         "f11",  100.0F );
        addAngleParameter( W2,      "noduleFatness21",         "f21",   20.0F );
        addAngleParameter( nstart,  "spiralStartingPoint1",    "sp1",    0.0F );
        addAngleParameter( P2,      "positionOnSection2",      "ps2",    0.0F );
        addFloatParameter( L2,      "noduleAmplitude2",        "na2",    0.0F );
        addFloatParameter( N2,      "noduleProfileFrequency2", "nf2",    0.0F );
        addAngleParameter( W12,     "noduleFatness12",         "f12",   30.0F );
        addAngleParameter( W22,     "noduleFatness22",         "f22",   30.0F );
        addAngleParameter( off2,    "noduleOffset2",           "no2",    0.0F );
        addAngleParameter( nstart2, "spiralStartingPoint2",    "sp2",    0.0F );
        addAngleParameter( P3,      "positionOnSection3",      "ps3",    0.0F );
        addFloatParameter( L3,      "noduleAmplitude3",        "na3",    0.0F );
        addFloatParameter( N3,      "noduleProfileFrequency3", "nf3",    0.0F );
        addAngleParameter( W13,     "noduleFatness13",         "f13",   30.0F );
        addAngleParameter( W23,     "noduleFatness23",         "f23",   30.0F );
        addAngleParameter( off3,    "noduleOffset3",           "no3",    0.0F );
        addAngleParameter( nstart3, "spiralStartingPoint3",    "sp3",    0.0F );
        addFloatParameter( uamp,    "sectionRibAmplitude",     "sra",    0.0F );
        addFloatParameter( ufreq,   "sectionRibFrequency",     "srf",    0.0F );
        addFloatParameter( urib,    "sectionRibWavePercent",   "srw",    0.0F );
        addFloatParameter( vamp,    "profileRibAmplitude",     "pra",    0.0F );
        addFloatParameter( vfreq,   "profileRibFrequency",     "prf",    0.0F );
        addFloatParameter( vrib,    "profileRibWavePercent",   "prw",    0.0F );
        fprintf(stderr,"Attribute Initialize Failed\n");
        return stat;
    }
}
inline float shellNode::GetFloatParameter( 
MObject node, 
MObject attr )
 
{
    MPlug plug( node, attr );
 
    float value;
    return value;
}
inline float shellNode::GetAngleParameter( 
MObject node, 
MObject attr )
 
{
    MPlug plug( node, attr );
 
}
#define UpdateFloatAttr(ATTR,TOPOLOGY)                          \
    oldValue = shellParams. ATTR;                           \
    shellParams. ATTR = GetFloatParameter( thisObj, ATTR ); \
    if ( shellParams. ATTR != oldValue ) {                  \
        rebuild = true;                                         \
        redoTopology = TOPOLOGY ? true : redoTopology;          \
    }
#define UpdateAngleAttr(ATTR,TOPOLOGY)                          \
    oldValue = shellParams. ATTR;                           \
    shellParams. ATTR = GetAngleParameter( thisObj, ATTR ); \
    if ( shellParams. ATTR != oldValue ) {                  \
        rebuild = true;                                         \
        redoTopology = TOPOLOGY ? true : redoTopology;          \
    }
void shellNode::UpdateParameters( ) 
{
    float oldValue;
    UpdateAngleAttr(alpha,false);
    UpdateAngleAttr(beta,false);
    UpdateAngleAttr(phi,false);
    UpdateAngleAttr(my,false);
    UpdateAngleAttr(omega,false);
    UpdateFloatAttr(A,false);
    UpdateFloatAttr(a,false);
    UpdateFloatAttr(b,false);
    UpdateFloatAttr(scale,false);
    UpdateAngleAttr(P,false);
    UpdateFloatAttr(L,false);
    UpdateFloatAttr(N,false);
    UpdateAngleAttr(W1,false);
    UpdateAngleAttr(W2,false);
    UpdateAngleAttr(nstart,false);
    UpdateAngleAttr(P2,false);
    UpdateFloatAttr(L2,false);
    UpdateFloatAttr(N2,false);
    UpdateAngleAttr(W12,false);
    UpdateAngleAttr(W22,false);
    UpdateAngleAttr(off2,false);
    UpdateAngleAttr(nstart2,false);
    UpdateAngleAttr(P3,false);
    UpdateFloatAttr(L3,false);
    UpdateFloatAttr(N3,false);
    UpdateAngleAttr(W13,false);
    UpdateAngleAttr(W23,false);
    UpdateAngleAttr(off3,false);
    UpdateAngleAttr(nstart3,false);
    UpdateFloatAttr(uamp,false);
    UpdateFloatAttr(ufreq,false);
    UpdateFloatAttr(urib,false);
    UpdateFloatAttr(vamp,false);
    UpdateFloatAttr(vfreq,false);
    UpdateFloatAttr(vrib,false);
    
    
    UpdateAngleAttr(omin,true);
    UpdateAngleAttr(omax,true);
    UpdateAngleAttr(od,true);
    UpdateAngleAttr(smin,true);
    UpdateAngleAttr(smax,true);
    UpdateAngleAttr(sd,true);
}
{ 
    MFnPlugin plugin( obj, PLUGIN_COMPANY, 
"3.0", 
"Any");
 
    status = plugin.registerNode( "shell", shellNode::id, 
                         &shellNode::creator, &shellNode::initialize,
    if (!status) {
        status.
perror(
"registerNode");
        return status;
    }
    return status;
}
{
    status = plugin.deregisterNode( shellNode::id );
    if (!status) {
        status.
perror(
"deregisterNode");
        return status;
    }
    return status;
}