#include <string.h>
#include <maya/MIOStream.h>
#include <maya/MStringArray.h>
#include <math.h>
#include <maya/MPxDeformerNode.h> 
#include <maya/MItGeometry.h>
#include <maya/MPxLocatorNode.h> 
#include <maya/MFnNumericAttribute.h>
#include <maya/MFnMatrixAttribute.h>
#include <maya/MFnMatrixData.h>
#include <maya/MFnPlugin.h>
#include <maya/MFnDependencyNode.h>
#include <maya/MTypeId.h> 
#include <maya/MPlug.h>
#include <maya/MDataBlock.h>
#include <maya/MDataHandle.h>
#include <maya/MArrayDataHandle.h>
#include <maya/MPoint.h>
#include <maya/MVector.h>
#include <maya/MMatrix.h>
#include <maya/MDagModifier.h>
#include <maya/MPxGPUDeformer.h>
#include <maya/MGPUDeformerRegistry.h>
#include <maya/MOpenCLInfo.h>
#include <maya/MViewport2Renderer.h>
#include <maya/MFnMesh.h>
#include <clew/clew_cl.h>
#include <vector>
{
public:
                        offset();
    virtual             ~offset();
    static  void*       creator();
    
    
                                       unsigned int     multiIndex);
    
    
    
    
public:
    
    
private:
};
offset::offset() {}
offset::~offset() {}
void* offset::creator()
{
    return new offset();
}
{
    
    offsetMatrix=mAttr.
create( 
"locateMatrix", 
"lm");
    
    addAttribute( offsetMatrix);
    attributeAffects( offset::offsetMatrix, offset::outputGeom );
}
                unsigned int multiIndex)
{
    
    
    
    
    
    
    
    
    
        pt *= omatinv;
        
        float weight = weightValue(block,multiIndex,iter.
index());
 
        
        
        
        pt.
y = pt.
y + env*weight;
        
        
        pt *= omat;
    }
    return returnStatus;
}
offset::accessoryAttribute() const
{
    return offset::offsetMatrix;
}
{
    
    
                                    &result);
        MObject attrMat = fnLoc.attribute(attrName);
 
        result = cmd.
connect(objLoc,attrMat,this->thisMObject(),offset::offsetMatrix);
    }
    return result;
}
{
public:
    
    offsetGPUDeformer();
    virtual ~offsetGPUDeformer();
    
private:
    
    
    unsigned int fNumElements;
    
};
{
public:
    offsetNodeGPUDeformerInfo(){}
    virtual ~offsetNodeGPUDeformerInfo(){}
    {
        return new offsetGPUDeformer();
    }
    
    {
        return offsetGPUDeformer::validateNodeInGraph(block, evaluationNode, plug, messages);
    }
    {
        return offsetGPUDeformer::validateNodeValues(block, evaluationNode, plug, messages);
    }
};
{
    static offsetNodeGPUDeformerInfo theOne;
    return &theOne;
}
offsetGPUDeformer::offsetGPUDeformer()
{
    
    
}
offsetGPUDeformer::~offsetGPUDeformer()
{
    terminate();
}
{
    
    
    
    return true;
}
{
    
    
    
    
    
    
    
    
    envelopePlug.getValue(envData);
    {
        MOpenCLInfo::appendMessage(messages, 
"Offset %s not supported by deformer evaluator because envelope is not exactly 1.0.", fnNode.name().asChar());
 
        return false;
    }
    return true;
}
MPxGPUDeformer::DeformerStatus offsetGPUDeformer::evaluate(
    unsigned int numElements,                   
{
    
    
    
    fNumElements = numElements;
    extractWeightArray(block, evaluationNode, plug);
    extractOffsetMatrix(block, evaluationNode, plug);
    
    if (!fKernel.get())
    {
        char *maya_location = getenv( "MAYA_LOCATION" );
        MString openCLKernelFile(maya_location);
 
        openCLKernelFile +="/../Extra/devkitBase/devkit/plug-ins/offsetNode/offset.cl";
        MString openCLKernelName(
"offset");
 
        if (!fKernel) return MPxGPUDeformer::kDeformerFailure;
    }
    cl_int err = CL_SUCCESS;
    
    
    
    unsigned int parameterId = 0;
    err = clSetKernelArg(fKernel.get(), parameterId++, sizeof(cl_mem), (void*)outputBuffer.getReadOnlyRef());
    err = clSetKernelArg(fKernel.get(), parameterId++, sizeof(cl_mem), (void*)inputBuffer.getReadOnlyRef());
    err = clSetKernelArg(fKernel.get(), parameterId++, sizeof(cl_mem), (void*)fCLWeights.getReadOnlyRef());
    err = clSetKernelArg(fKernel.get(), parameterId++, sizeof(cl_mem), (void*)fOffsetMatrix.getReadOnlyRef());
    err = clSetKernelArg(fKernel.get(), parameterId++, sizeof(cl_uint), (void*)&fNumElements);
    
    size_t workGroupSize;
    size_t retSize;
    err = clGetKernelWorkGroupInfo(
        fKernel.get(),
        CL_KERNEL_WORK_GROUP_SIZE,
        sizeof(size_t),
        &workGroupSize,
        &retSize);
    size_t localWorkSize = 256;
    if (retSize > 0) localWorkSize = workGroupSize;
    size_t globalWorkSize = (localWorkSize - fNumElements % localWorkSize) + fNumElements; 
    
    
    unsigned int numInputEvents = 0;
    if (inputEvent.get())
    {
        numInputEvents = 1;
    }
    
    err = clEnqueueNDRangeKernel(
        fKernel.get(),
        1,
        NULL,
        &globalWorkSize,
        &localWorkSize,
        numInputEvents,
    return MPxGPUDeformer::kDeformerSuccess;
}
void offsetGPUDeformer::terminate()
{
    fCLWeights.reset();
    fOffsetMatrix.reset();
    fKernel.reset();
}
{
    
    
    
    
    
    {
        return;
    }
    
    
    
    std::vector<float> temp;
    temp.reserve(fNumElements);
    
    
    
    if (!status) return; 
    
    if (!status)
    {   
        for(unsigned int i=0; i<fNumElements; i++)
            temp.push_back(1.0f);
    }
    else
    {
        if (!status) return;
        if (!status) return;
        
        if (!status) return;
        
        unsigned int weightIndex = 0;
        for(
unsigned int i=0; i<numWeights; i++, weights.
next())
 
        {
            unsigned int weightsElementIndex = weights.
elementIndex(&status);
 
            while (weightIndex < weightsElementIndex)
            {
                temp.push_back(0.0f); 
                weightIndex++;
            }
            weightIndex++;
        }
        
        
        while (weightIndex < fNumElements)
        {
            temp.push_back(0.0f); 
            weightIndex++;
        }
    }
    
    cl_int err = CL_SUCCESS;
    if (!fCLWeights.get())
    {
        fCLWeights.attach(clCreateBuffer(
MOpenCLInfo::getOpenCLContext(), CL_MEM_COPY_HOST_PTR | CL_MEM_READ_ONLY, fNumElements * 
sizeof(
float), (
void*)&temp[0], &err));
    }
    else
    {
        
        
    }
}
{
    
    if ((fOffsetMatrix.get() && !evaluationNode.
dirtyPlugExists(offset::offsetMatrix, &status)) || !status)
 
    {
        return;
    }
    
    
    unsigned int numFloat = 32;
    float* temp = new float[numFloat];
    unsigned int curr = 0;
    for(unsigned int row = 0; row<4; row++)
    {
        for(unsigned int column = 0; column<4; column++)
        {
            temp[curr++] = (float)omat(row, column);
        }
    }
    for(unsigned int row = 0; row<4; row++)
    {
        for(unsigned int column = 0; column<4; column++)
        {
            temp[curr++] = (float)omatinv(row, column);
        }
    }
    
    cl_int err = CL_SUCCESS;
    if (!fOffsetMatrix.get())
    {
        fOffsetMatrix.attach(clCreateBuffer(
MOpenCLInfo::getOpenCLContext(), CL_MEM_COPY_HOST_PTR | CL_MEM_READ_ONLY, numFloat * 
sizeof(
float), (
void*) temp, &err));
    }
    else
    {
        
    }
    delete [] temp;
}
{
    MFnPlugin plugin( obj, PLUGIN_COMPANY, 
"3.0", 
"Any");
 
    result = plugin.registerNode( "offset", offset::id, offset::creator, 
    MString registrantId(
"mayaPluginExample");
 
        nodeClassName,
        registrantId,
        offsetGPUDeformer::getGPUDeformerInfo());
            nodeClassName,
            registrantId,
    return result;
}
{
    result = plugin.deregisterNode( offset::id );
    MString registrantId(
"mayaPluginExample");
 
        nodeClassName,
        registrantId);
    return result;
}