#ifdef WIN32
#pragma warning( disable : 4786 )               // Disable stupid STL warnings.
#endif
#include <maya/MIOStream.h>
#include <math.h>
#include <maya/MString.h>
#include <maya/MPlug.h>
#include <maya/MDagPath.h>
#include <maya/MFnDependencyNode.h>
#include <maya/MFnNumericAttribute.h>
#include <maya/MFnTypedAttribute.h>
#include <maya/MFloatVector.h>
#include <maya/MFnStringData.h>
#include <maya/MFnPlugin.h>
#include <maya/MGlobal.h>
#include <maya/MSceneMessage.h>
#include <maya/MPoint.h>
#include <maya/MMatrix.h>
#include <maya/MVector.h>
#include <maya/MQuaternion.h>
#include <maya/MEulerRotation.h>
#include <GL/gl.h>
#include <gl/glext.h>
#define GLH_EXT_SINGLE_FILE
#include "glh_extensions.h"
#undef GL_NV_vertex_array_range
#include "glh_genext.h"
#include "glh_obs.h"
using namespace glh;
#include "hwRefractReflectShader_NV20.h"
#include "ShadingConnection.h"
MTypeId hwRefractReflectShader_NV20::id( 0x00105445 );
void hwRefractReflectShader_NV20::postConstructor( )
{
        setMPSafe(false);
}
MObject  hwRefractReflectShader_NV20::color;
MObject  hwRefractReflectShader_NV20::colorR;
MObject  hwRefractReflectShader_NV20::colorG;
MObject  hwRefractReflectShader_NV20::colorB;
MObject  hwRefractReflectShader_NV20::refractionIndex;
MObject  hwRefractReflectShader_NV20::reflectivity;
char vertexProgramString[] = 
                "!!VP1.0 # Refraction and Reflection\n"
                
                
                
                "DP4    o[HPOS].x, c[0], v[OPOS];"
                "DP4    o[HPOS].y, c[1], v[OPOS];"
                "DP4    o[HPOS].z, c[2], v[OPOS];"
                "DP4    o[HPOS].w, c[3], v[OPOS];"
                
                
                
        
                
                "DP4    R9.x, c[8],  v[OPOS];"
                "DP4    R9.y, c[9],  v[OPOS];"
                "DP4    R9.z, c[10], v[OPOS];"
                "DP4    R9.w, c[11], v[OPOS];"          
                
        
                
                "DP3    R0.x, c[4], v[NRML];"
                "DP3    R0.y, c[5], v[NRML];"
                "DP3    R0.z, c[6], v[NRML];"
        "DP3    R11.w, R0, R0;"
                "RSQ    R11.w, R11.w;"
                "MUL    R11, R0, R11.w;"                        
                
                
                "ADD    R0, -R9, c[59];"                        
        "DP3    R8.w, R0, R0;"
                "RSQ    R8.w, R8.w;"
                "MUL    R8, R0, R8.w;"                          
        
                
                
        
        
        
                
                "DP3    R0.x, R11, -R8;"                                
        
                "MAD    R1.x, -R0.x, R0.x, c[64].y;"    
                "MUL    R1.x, R1.x, c[58].y;"                   
        "ADD    R1.x, c[64].y, -R1.x;"                  
        
        "RSQ    R2.x, R1.x;"                                    
        "RCP    R2.x, R2.x;"                                    
        "MAD    R2.x, c[58].x, R0.x, R2.x;"             
        "MUL    R2, R11, R2.x;"                                 
        "MAD    R2, c[58].x, -R8, R2;"                  
                
        
                
        "DP3    o[TEX0].x, c[12], R2;"
        "DP3    o[TEX0].y, c[13], R2;"
        "DP3    o[TEX0].z, c[14], R2;"
        
        
        "MUL    R0, R11, c[64].z;"              
        "DP3    R3.w, R11, R8;"                 
        "MAD    R3, R3.w, R0, -R8;"             
                
        
                
        "DP3    o[TEX1].x, c[12], R3;"
        "DP3    o[TEX1].y, c[13], R3;"
        "DP3    o[TEX1].z, c[14], R3;"
        "END";
void initVertexProgram(const char vertexProgramCode[], GLuint* pVertexProgramId)
{
        
        glGenProgramsNV(1, pVertexProgramId);
        GLenum error = glGetError();
        assert(error == GL_NO_ERROR);
        
        unsigned int length = strlen(vertexProgramCode);
        glLoadProgramNV(GL_VERTEX_PROGRAM_NV, *pVertexProgramId, length, 
                (const GLubyte *) vertexProgramCode);
        error = glGetError();
        
        
        if (error != GL_NO_ERROR)
        {
                
                
                
                
                
                if (error == GL_INVALID_OPERATION)
                {
                        int error_position = -2;
                        glGetIntegerv(GL_PROGRAM_ERROR_POSITION_NV, &error_position);
                        
                        assert(0);
                }
        }
}
void hwRefractReflectShader_NV20::loadVertexProgramGL( M3dView& view )
{
        view.beginGL();
        {
                
                
                if (vertex_program_id == 0)     
                        initVertexProgram(vertexProgramString, &vertex_program_id);
                
                
                
                
                
                
                
                
                glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 0,  GL_MODELVIEW_PROJECTION_NV, GL_IDENTITY_NV);
                glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 4,  GL_MODELVIEW,               GL_INVERSE_TRANSPOSE_NV);
                glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 8,  GL_MODELVIEW,               GL_IDENTITY_NV);
                glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 12, GL_TEXTURE,                 GL_IDENTITY_NV);
                
                float rIdx = fRefractionIndex;
                glProgramParameter4fNV(GL_VERTEX_PROGRAM_NV, 58, rIdx, rIdx*rIdx, 0.0, 0.0);    
                glProgramParameter4fNV(GL_VERTEX_PROGRAM_NV, 59, 0.0, 0.0, 0.0, 1.0);                   
                glProgramParameter4fNV(GL_VERTEX_PROGRAM_NV, 64, 0.0, 1.0, 2.0, 3.0);                   
        }
        view.endGL();
}
MStatus hwRefractReflectShader_NV20::loadTextures(const MDrawRequest& request, M3dView& view)
{
        
        
        MStringArray    decalNames;
        MString                 decalName;
        
        
        ShadingConnection       colorConnection(thisMObject(), request.multiPath().partialPathName(), "color");
        
        
        
        bool gotAllEnvironmentMaps = TRUE;
        if (colorConnection.type() == ShadingConnection::TEXTURE &&
                colorConnection.texture().hasFn(MFn::kEnvCube))
        {
                
                MFnDependencyNode textureNode(colorConnection.texture());
                MString attributeName;
                MString envNames[6] = { "top", "bottom", "left", "right", "front", "back" };
                
                
                for (int i=0; i<6; i++)
                {
                        ShadingConnection conn(colorConnection.texture(), request.multiPath().partialPathName(), 
                                                        envNames[i]);
                        if (conn.type() == ShadingConnection::TEXTURE &&
                                conn.texture().hasFn(MFn::kFileTexture))
                        {
                                MFnDependencyNode envNode(conn.texture());
                                MPlug filenamePlug( conn.texture(), envNode.attribute(MString("fileTextureName")) );
                                filenamePlug.getValue(decalName);
                                if (decalName.length() == 0)    decalName = "internalDefaultTexture";
                                
                                decalNames.append( decalName );
                        }
                        
                        else
                        {
                                decalName = "internalDefaultTexture";
                                decalNames.append( decalName );
                        }
                }
        }
        else
        {
                
                decalName = "internalDefaultTexture";
                for (int i=0; i<6; i++)
                {
                        decalNames.append( decalName );
                }
        }
        
        
        
        bool reload = FALSE;
        for (int i=0; i<6; i++)
        {
                if (currentTextureNames[i] != decalNames[i])
                {
                        reload = TRUE;
                        break;
                }
        }
        view.beginGL();
        {
                if ( reload )
                {
                        MString ypTexName(decalNames[0]);       
                        MString ynTexName(decalNames[1]);       
                        MString xpTexName(decalNames[2]);       
                        MString xnTexName(decalNames[3]);       
                        MString zpTexName(decalNames[4]);       
                        MString znTexName(decalNames[5]);       
                        MStatus stat;
                        if (! (stat = theImage_XP.readFromFile(xpTexName)) )    return MS::kFailure;
                        if (! (stat = theImage_XN.readFromFile(xnTexName)) )    return MS::kFailure;
                        if (! (stat = theImage_YP.readFromFile(ypTexName)) )    return MS::kFailure;
                        if (! (stat = theImage_YN.readFromFile(ynTexName)) )    return MS::kFailure;
                        if (! (stat = theImage_ZP.readFromFile(zpTexName)) )    return MS::kFailure;
                        if (! (stat = theImage_ZN.readFromFile(znTexName)) )    return MS::kFailure;
                        
                        if (fTextureName == -1)         glGenTextures(1, &fTextureName);
                        glBindTexture( GL_TEXTURE_CUBE_MAP_ARB, fTextureName );
                        glEnable( GL_TEXTURE_CUBE_MAP_ARB );
                        
                        
                        unsigned int width, height;
                        stat = theImage_XP.getSize( width, height );
                        glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
                                0, GL_RGBA8, width,     height, 0, GL_RGBA,     GL_UNSIGNED_BYTE, theImage_XP.pixels() );
                        glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
                                0, GL_RGBA8, width,     height, 0, GL_RGBA,     GL_UNSIGNED_BYTE, theImage_XN.pixels() );
                        glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
                                0, GL_RGBA8, width,     height, 0, GL_RGBA,     GL_UNSIGNED_BYTE, theImage_YP.pixels() );
                        glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
                                0, GL_RGBA8, width,     height, 0, GL_RGBA,     GL_UNSIGNED_BYTE, theImage_YN.pixels() );
                        glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
                                0, GL_RGBA8, width,     height, 0, GL_RGBA,     GL_UNSIGNED_BYTE, theImage_ZP.pixels() );
                        glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB,
                                0, GL_RGBA8, width,     height, 0, GL_RGBA,     GL_UNSIGNED_BYTE, theImage_ZN.pixels() );
                        glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
                        glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
                        glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
                        glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
                        glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
                        for (i=0; i<6; i++)             currentTextureNames[i] = decalNames[i];
                }
                
                
                glActiveTextureARB( GL_TEXTURE0_ARB );
                glBindTexture( GL_TEXTURE_CUBE_MAP_ARB, fTextureName );
                glEnable( GL_TEXTURE_CUBE_MAP_ARB );
                
                
                glActiveTextureARB( GL_TEXTURE1_ARB );
                glBindTexture( GL_TEXTURE_CUBE_MAP_ARB, fTextureName );
                glEnable( GL_TEXTURE_CUBE_MAP_ARB );
        }
        view.endGL();
        return MS::kSuccess;
}
void    hwRefractReflectShader_NV20::initCombiners(const MDrawRequest& request, M3dView& view)
{
        view.beginGL();
        {
                
                
                glCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV, 1);
                {
                        float refractivity[4], reflectivity[4];
                        refractivity[0] = refractivity[1] = refractivity[2] = refractivity[3] = 1.0f - fReflectivity;
                        reflectivity[0] = reflectivity[1] = reflectivity[2] = reflectivity[3] = fReflectivity;
                        glCombinerParameterfvNV(GL_CONSTANT_COLOR0_NV, refractivity);
                        glCombinerParameterfvNV(GL_CONSTANT_COLOR1_NV, reflectivity);
                }
                
                
                
                
                
                glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV, GL_TEXTURE0_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
                glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, GL_CONSTANT_COLOR0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
                glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_C_NV, GL_TEXTURE1_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
                glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_D_NV, GL_CONSTANT_COLOR1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
                
                
                
                glCombinerOutputNV(GL_COMBINER0_NV, GL_RGB, GL_DISCARD_NV, GL_DISCARD_NV, GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE);
                
                
                
                
                
                
                glFinalCombinerInputNV(GL_VARIABLE_A_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
                glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
                glFinalCombinerInputNV(GL_VARIABLE_C_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
                glFinalCombinerInputNV(GL_VARIABLE_D_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
        }
        view.endGL();
}
MStatus hwRefractReflectShader_NV20::preDraw(const MDrawRequest& request, M3dView& view)
{
        MStatus stat = loadTextures( request, view);
        if( MS::kSuccess != stat )              return stat;
        
        
        MPlug   tPlug(thisMObject(), reflectivity);
        if( tPlug.getValue( fReflectivity ) )
        {
                if( fReflectivity < 0.01f )     fReflectivity = 0.01f;
                if( fReflectivity > 1.0f )      fReflectivity = 1.0f;
        }
        else    fReflectivity = 0.5f;
        
        
        
        MPlug   rPlug(thisMObject(), refractionIndex);
        if( rPlug.getValue( fRefractionIndex ) )
        {
                if ( fRefractionIndex < 1.0f )  fRefractionIndex = 1.0f;
                if ( fRefractionIndex > 2.0f )  fRefractionIndex = 2.0f;
        }
        else    fRefractionIndex = 1.0f;
        
        initCombiners( request, view );
        
        
        
        MDagPath        cameraPath;
        MStatus         status = view.getCamera( cameraPath );
        MMatrix         mmatrix = cameraPath.inclusiveMatrix( &status );
        MTransformationMatrix tmatrix( mmatrix );
        
        MQuaternion camRotation = tmatrix.rotation();
        MVector         camAxis;
        double          camTheta;
        camRotation.getAxisAngle(  camAxis, camTheta );
        
        
        camTheta *= 57.295779513082320876798154814105;  
        
        view.beginGL();
                glMatrixMode( GL_TEXTURE );
                glPushMatrix();
                glLoadIdentity();
                glScalef(1.0, -1.0, 1.0);
                glRotated( camTheta, camAxis[0], camAxis[1], camAxis[2]);
                glMatrixMode( GL_MODELVIEW );
        view.endGL();
        return stat;
}
MStatus hwRefractReflectShader_NV20::geometry( const MDrawRequest& request,
        M3dView&                view,
        int                             prim,
        unsigned int    writable,
        int                             indexCount,
        const unsigned int * indexArray,
        int                             vertexCount,
        const int *             vertexIDs,
        const float *   vertexArray,
        int                             normalCount,
        const float **  normalArrays,
        int                             colorCount,
        const float **  colorArrays,
        int                             texCoordCount,
        const float **  texCoordArrays)
{
        
        
        if( prim != GL_TRIANGLES )              return  MS::kSuccess;
        
        
        view.beginGL();
                glPushAttrib( GL_ALL_ATTRIB_BITS );
                glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
        view.endGL();
        MStatus preDrawStatus = preDraw( request, view );
        if( MS::kSuccess == preDrawStatus )
        {       
                loadVertexProgramGL( view );
                
                view.beginGL();
                {
                        glEnable(GL_REGISTER_COMBINERS_NV);
                        
                        
                        
                        glBindProgramNV(GL_VERTEX_PROGRAM_NV, vertex_program_id);
                        glEnable(GL_VERTEX_PROGRAM_NV);
                        {                               
                                
                                
                                
                                
                                glVertexAttribPointerNV( 0, 3, GL_FLOAT, 0, vertexArray );
                                glVertexAttribPointerNV( 2, 3, GL_FLOAT, 0, normalArrays[0] );
                                
                                glEnableClientState( GL_VERTEX_ATTRIB_ARRAY0_NV );
                                glEnableClientState( GL_VERTEX_ATTRIB_ARRAY2_NV );
                                
                                glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, indexArray);
                                
                                glDisableClientState( GL_VERTEX_ATTRIB_ARRAY0_NV );
                                glDisableClientState( GL_VERTEX_ATTRIB_ARRAY2_NV );
                        }
                        glDisable(GL_VERTEX_PROGRAM_NV);
                        
                        glDisable(GL_REGISTER_COMBINERS_NV);
                }
                view.endGL();
                postDraw( request, view );
        }
        
        
        view.beginGL();
                glPopClientAttrib();
                glPopAttrib();
        view.endGL();
        return preDrawStatus;
}
MStatus hwRefractReflectShader_NV20::postDraw(
        const MDrawRequest& request,
        M3dView& view )
{
        view.beginGL();
        {
                glMatrixMode( GL_TEXTURE );
                glPopMatrix();
                glMatrixMode( GL_MODELVIEW );
                
                glActiveTextureARB( GL_TEXTURE1_ARB );
                glBindTexture( GL_TEXTURE_CUBE_MAP_ARB, 0 );
                glDisable(GL_TEXTURE_CUBE_MAP_ARB);
                
                glActiveTextureARB( GL_TEXTURE0_ARB );
                glBindTexture( GL_TEXTURE_CUBE_MAP_ARB, 0 );
                glDisable(GL_TEXTURE_CUBE_MAP_ARB);
        }
        view.endGL();
        return MS::kSuccess;
}
int             hwRefractReflectShader_NV20::normalsPerVertex()
{
        return 1;
}
int             hwRefractReflectShader_NV20::texCoordsPerVertex()
{
        return 1;
}
void hwRefractReflectShader_NV20::init_ext(const char * ext)
{
        if(!glh_init_extension(ext))
        { cerr << "Failed to initialize " << ext << "!" << endl; exit(0); }
}
hwRefractReflectShader_NV20::hwRefractReflectShader_NV20()
{
        
        m_pTextureCache = MTextureCache::instance();
        init_ext("GL_ARB_multitexture");
        init_ext("GL_NV_register_combiners");
        init_ext("GL_NV_vertex_program");
        
        
        fTextureName = -1;
        currentTextureNames[0] = "";
        currentTextureNames[1] = "";
        currentTextureNames[2] = "";
        currentTextureNames[3] = "";
        currentTextureNames[4] = "";
        currentTextureNames[5] = "";
        
        fBeforeNewCB = 0;
        fBeforeOpenCB = 0;
        fBeforeRemoveReferenceCB = 0;
        fMayaExitingCB = 0;
        attachSceneCallbacks();
        vertex_program_id = 0;          
}
hwRefractReflectShader_NV20::~hwRefractReflectShader_NV20()
{
        detachSceneCallbacks();
}
void releaseVertexProgram(GLuint* pVertexProgramId)
{
        
        if (*pVertexProgramId > 0)
        {
                
                glBindProgramNV(GL_VERTEX_PROGRAM_NV, 0);
                glDeleteProgramsNV(1, pVertexProgramId);
                
                *pVertexProgramId = 0;
        }
}
void hwRefractReflectShader_NV20::releaseEverything()
{
        if (fTextureName != -1) glDeleteTextures(1, &fTextureName);
        releaseVertexProgram(&vertex_program_id);
        
        m_pTextureCache->release();
        if(!MTextureCache::getReferenceCount())
        {
                m_pTextureCache = 0;
        }
}
void hwRefractReflectShader_NV20::attachSceneCallbacks()
{
        fBeforeNewCB  = MSceneMessage::addCallback(MSceneMessage::kBeforeNew,  releaseCallback, this);
        fBeforeOpenCB = MSceneMessage::addCallback(MSceneMessage::kBeforeOpen, releaseCallback, this);
        fBeforeRemoveReferenceCB = MSceneMessage::addCallback(MSceneMessage::kBeforeRemoveReference, 
                                                                                                                  releaseCallback, this);
        fMayaExitingCB = MSceneMessage::addCallback(MSceneMessage::kMayaExiting, releaseCallback, this);
}
void hwRefractReflectShader_NV20::releaseCallback(void* clientData)
{
        hwRefractReflectShader_NV20 *pThis = (hwRefractReflectShader_NV20*) clientData;
        pThis->releaseEverything();
}
void hwRefractReflectShader_NV20::detachSceneCallbacks()
{
        if (fBeforeNewCB)                               MMessage::removeCallback(fBeforeNewCB);
        if (fBeforeOpenCB)                              MMessage::removeCallback(fBeforeOpenCB);
        if (fBeforeRemoveReferenceCB)   MMessage::removeCallback(fBeforeRemoveReferenceCB);
        if (fMayaExitingCB)                             MMessage::removeCallback(fMayaExitingCB);
        fBeforeNewCB = 0;
        fBeforeOpenCB = 0;
        fBeforeRemoveReferenceCB = 0;
        fMayaExitingCB = 0;
}
MStatus initializePlugin( MObject obj )
{ 
        MStatus   status;
        
        const MString UserClassify( "shader/surface/utility" );
        MFnPlugin plugin( obj, PLUGIN_COMPANY, "4.0", "Any");
        status = plugin.registerNode( "hwRefractReflectShader_NV20", hwRefractReflectShader_NV20::id, 
                                              hwRefractReflectShader_NV20::creator, hwRefractReflectShader_NV20::initialize,
                                                                  MPxNode::kHwShaderNode, &UserClassify );
        if (!status) {
                status.perror("registerNode");
                return status;
        }
        return MS::kSuccess;
}
MStatus uninitializePlugin( MObject obj )
{
        MStatus         status;
        MFnPlugin       plugin( obj );
        status = plugin.deregisterNode( hwRefractReflectShader_NV20::id );
        if (!status) {
                status.perror("deregisterNode");
                return status;
        }
        return MS::kSuccess;
}
void * hwRefractReflectShader_NV20::creator()
{
    return new hwRefractReflectShader_NV20();
}
MStatus hwRefractReflectShader_NV20::initialize()
{
    MFnNumericAttribute nAttr; 
        MStatus status;
        MFnTypedAttribute sAttr; 
    
    colorR = nAttr.create( "colorR", "cr",MFnNumericData::kFloat);
    nAttr.setStorable(true);
    nAttr.setKeyable(true);
    nAttr.setDefault(1.0f);
    colorG = nAttr.create( "colorG", "cg",MFnNumericData::kFloat);
    nAttr.setStorable(true);
    nAttr.setKeyable(true);
    nAttr.setDefault(0.5f);
    colorB = nAttr.create( "colorB", "cb",MFnNumericData::kFloat);
    nAttr.setStorable(true);
    nAttr.setKeyable(true);
    nAttr.setDefault(0.5f);
    color = nAttr.create( "color", "c", colorR, colorG, colorB);
    nAttr.setStorable(true);
    nAttr.setKeyable(true);
    nAttr.setDefault(1.0f, 0.5f, 0.5f);
    nAttr.setUsedAsColor(true);
    refractionIndex = nAttr.create( "refractionIndex", "ri", MFnNumericData::kFloat);
    nAttr.setStorable(true);
    nAttr.setKeyable(true);
    nAttr.setMin(1.0f);
    nAttr.setMax(2.0f);
    nAttr.setDefault(1.1f);
    reflectivity = nAttr.create( "reflectivity", "rfl", MFnNumericData::kFloat);
    nAttr.setStorable(true);
    nAttr.setKeyable(true);
    nAttr.setMin(0.0f);
    nAttr.setMax(1.0f);
    nAttr.setDefault(0.5f);
 
    addAttribute(color);
    addAttribute(refractionIndex);
    addAttribute(reflectivity);
    attributeAffects (colorR, outColor);
    attributeAffects (colorG, outColor);
    attributeAffects (colorB, outColor);
    attributeAffects (color,  outColor);
    attributeAffects (refractionIndex,   outColor);
    attributeAffects (reflectivity,   outColor);
    return MS::kSuccess;
}
MStatus hwRefractReflectShader_NV20::compute(
const MPlug&      plug,
      MDataBlock& block ) 
{ 
        
        
        
        bool k = false;
    k |= (plug==outColor);
    k |= (plug==outColorR);
    k |= (plug==outColorG);
    k |= (plug==outColorB);
    if( !k ) return MS::kUnknownParameter;
    MFloatVector resultColor(0.0,0.0,0.0);
    
    MDataHandle outColorHandle = block.outputValue( outColor );
    MFloatVector& outColor = outColorHandle.asFloatVector();
    outColor = resultColor;
    outColorHandle.setClean();
    return MS::kSuccess;
}