#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();
~shellNode() override;
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( !pnts || ni<2 || nj<2 ) return MS::kSuccess;
if (plug == outMesh) {
if( !pnts || ni<2 || nj<2 ) return MS::kSuccess;
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;
}
}
}
return MS::kSuccess;
}
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) {
float **new_data = static_cast<float**>(realloc (pnts, nj*sizeof(float*)));
if (new_data == NULL) {
delete pnts;
pnts = NULL;
return;
} else {
pnts = new_data;
}
}
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 );
if ( stat != MS::kSuccess ) throw stat;
if ( stat != MS::kSuccess ) throw stat;
if ( stat != MS::kSuccess ) throw stat;
if ( stat != MS::kSuccess ) throw stat;
if ( stat != MS::kSuccess ) throw stat;
stat = addAttribute( attr );
if ( stat != MS::kSuccess ) throw stat;
stat = attributeAffects( attr, outMesh );
if ( stat != MS::kSuccess ) throw stat;
}
MString briefName,
float attrDefault )
{
attr = uAttr.
create( longName, briefName, defaultAngle, &stat );
if ( stat != MS::kSuccess ) throw stat;
if ( stat != MS::kSuccess ) throw stat;
if ( stat != MS::kSuccess ) throw stat;
if ( stat != MS::kSuccess ) throw stat;
stat = addAttribute( attr );
if ( stat != MS::kSuccess ) throw stat;
stat = attributeAffects( attr, outMesh );
if ( stat != MS::kSuccess ) throw stat;
}
{
if ( MS::kSuccess != 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;
}
return MS::kSuccess;
}
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;
}