#include <math.h>
#include <maya/MPxNode.h>
#include <maya/MIOStream.h>
#include <maya/MString.h>
#include <maya/MTypeId.h>
#include <maya/MPlug.h>
#include <maya/MDataBlock.h>
#include <maya/MDataHandle.h> 
#include <maya/MFnNumericAttribute.h>
#include <maya/MFnMatrixAttribute.h>
#include <maya/MFloatVector.h>
#include <maya/MFloatPoint.h>
#include <maya/MFnPlugin.h>
#ifdef LINUX
#define fsqrt   sqrtf
#include <stdlib.h>
#endif
class R3 {
    public:
    R3(float a, float b, float c): x(a), y(b), z(c) {}
    R3() {}
    public:
    float x;
    float y;
    float z;
};
static void initCellFunc();
static void cellFunc(const R3 &, float &n0, float &f1, float &f2);
{
public:
                    Cell3D();
    virtual         ~Cell3D();
    static  void *  creator();
    
    private:
    
    
};
#define MAKE_INPUT(attr)    \
    CHECK_MSTATUS( attr.setKeyable(true) );     \
    CHECK_MSTATUS( attr.setStorable(true) );    \
    CHECK_MSTATUS( attr.setReadable(true) );    \
    CHECK_MSTATUS( attr.setWritable(true) );
#define MAKE_OUTPUT(attr)   \
    CHECK_MSTATUS( attr.setKeyable(false) );    \
    CHECK_MSTATUS( attr.setStorable(false) );   \
    CHECK_MSTATUS( attr.setReadable(true) );    \
    CHECK_MSTATUS( attr.setWritable(false) );
void Cell3D::postConstructor( )
{
    setMPSafe(true);
}
Cell3D::Cell3D()
{
}
Cell3D::~Cell3D()
{
}
void * Cell3D::creator()
{
    return new Cell3D();
}
{
    
    MAKE_INPUT(nAttr);
    MAKE_INPUT(nAttr);
    
    aPlaceMat = mAttr.
create(
"placementMatrix", 
"pm", 
    MAKE_INPUT(mAttr);
    
    MAKE_INPUT(nAttr);
    
    MAKE_OUTPUT(nAttr);
    MAKE_OUTPUT(nAttr);
    MAKE_OUTPUT(nAttr);
    aOutBorderDist = nAttr.
create(
"borderDistance", 
"bd", 
    MAKE_OUTPUT(nAttr);
    
    MAKE_OUTPUT(nAttr);
    MAKE_OUTPUT(nAttr);
    
    
    
}
{
    if ( (plug != aOutColor) && (plug.
parent() != aOutColor) &&
 
         (plug != aOutAlpha) &&
         (plug != aOutBorderDist) && 
         (plug != aOutF0) && (plug != aOutF1) && (plug != aOutN0)
       ) 
    
    q *= m;                                 
    
    float n0, f0, f1;
    cellFunc(R3(q.x, q.y, q.z), n0, f0, f1);
    outHandle.
asFloat() = 0.5f*(f1 - f0);
    outColor = cGain * f0 + cOff;
}
{
    const MString UserClassify( 
"texture/3d" );
 
    MFnPlugin plugin( obj, PLUGIN_COMPANY, 
"4.5", 
"Any" );
 
                        Cell3D::creator, Cell3D::initialize,
    initCellFunc();
    
}
{
}
#define N_CELLS 1000
static int permuteTable[N_CELLS*2];
static void initPermute()
{
    int i;
    for (i = 0; i < N_CELLS; ++i) {
        permuteTable[i] = i;
    }
    for (i = N_CELLS - 1; i >= 1; --i) {
        int n = lrand48() % (i + 1);
        int tmp = permuteTable[n];
        permuteTable[n] = permuteTable[i];
        permuteTable[i] = tmp;
    }
    for (i = 0; i < N_CELLS; ++i) {
        permuteTable[i + N_CELLS] = permuteTable[i];
    }
}
static int fold(int i, int j, int k)
{
    
    if (i < 0) i = (i + N_CELLS*(i/N_CELLS + 1)) % N_CELLS;
    else i %= N_CELLS;
    if (j < 0) j = (j + N_CELLS*(j/N_CELLS + 1)) % N_CELLS;
    else j %= N_CELLS;
    if (k < 0) k = (k + N_CELLS*(k/N_CELLS + 1)) % N_CELLS;
    else k %= N_CELLS;
    return permuteTable[permuteTable[permuteTable[i] + j] + k];
}
#define N_CELLS 1000
static R3 CellSampleTable[N_CELLS];
static void initCellFunc()
{
    int i;
    srand48(10);                            
                                            
                                            
    for (i = 0; i < N_CELLS; ++i) {
    CellSampleTable[i] = R3((float)drand48(),
                            (float)drand48(),
                            (float)drand48());
    }
    initPermute();
}
static inline float sqr(float t) { return t*t; }
static inline float distance2(const R3 &a, const R3 &b)
{ 
    float t = sqr(b.x - a.x) + sqr(b.y - a.y) + sqr(b.z - a.z);
    return t;
}
static void cellFunc(const R3 &p, float &n0, float &f0, float &f1)
{
    R3 q = p;
    int i = (int)floorf(q.x);
    int j = (int)floorf(q.y);
    int k = (int)floorf(q.z);
    q.x -= i;
    q.y -= j;
    q.z -= k;
    int index = fold(i,j,k);
    float minDist = distance2(CellSampleTable[index], q);
    float minDist2 = 2.0;
    int k0;
    k0 = index;
    
    
    
    R3 q1;
    for (int ii = -1; ii <= 1; ++ii) {
        q1.x = q.x - ii;
        int i1 = i + ii;
        for (int jj = -1; jj <= 1; ++jj) {
            q1.y = q.y - jj;
            int j1 = j + jj;
            for (int kk = -1; kk <= 1; ++kk) {
                if (!ii && !jj && !kk) continue;
                q1.z = q.z - kk;
                int k1 = k + kk;
                index = fold(i1, j1, k1);
                float t = distance2(CellSampleTable[index], q1);
                if (minDist > t) {
                    minDist2 = minDist;
                    minDist = t;
                    k0 = index;
                }
                else if (minDist2 > t) {
                    minDist2 = t;
                }
            }
        }
    }
    f0 = sqrtf(minDist);
    f1 = sqrtf(minDist2);
    n0 = k0/(float)(N_CELLS);
}