#include <maya/MFnStringData.h>
#include <maya/MFnMatrixData.h>
#include <maya/MFnTypedAttribute.h>
#include <maya/MFnEnumAttribute.h>
#include <maya/MFnMatrixAttribute.h>
#include <maya/MFloatVector.h>
#include <maya/MGlobal.h>
#include <maya/MDGModifier.h>
#include <maya/MImage.h>
#include <maya/MPlugArray.h>
#include <maya/MFileIO.h>
#include <maya/MMatrix.h>
#include <maya/MFnMesh.h>
#include <maya/MString.h>
#include <maya/MStringResource.h>
#include <maya/MStringResourceId.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <algorithm>
#include "Platform.h"
#include "GLSLShaderNode.h"
#include "AshliShaderStrings.h"
#include "glExtensions.h"
#include "ResourceManager.h"
#include <maya/MHWShaderSwatchGenerator.h>
#include <maya/MHardwareRenderer.h>
#include <maya/MGeometryData.h>
#include <maya/MImage.h>
MTypeId glslShaderNode::sId( 0x81022);
MObject glslShaderNode::sShader;
MObject glslShaderNode::sTechnique;
MObject glslShaderNode::sTechniqueList; 
MObject glslShaderNode::sShaderPath; 
MObject glslShaderNode::sNakedTexCoords[8];
MObject glslShaderNode::sNakedColors[2];
shader *glslShaderNode::sDefShader = NULL;
std::vector<glslShaderNode*> glslShaderNode::sNodeList;
const char *glslShaderNode::nakedSetNames[8] = { "map1", "tangent", "binormal", "", "", "", "", ""};
glslShaderNode::glslShaderNode() : m_shader(NULL), m_shaderDirty(false), m_parsedUserAttribList( false) {
        
        
        
        
        InitializeExtensions();
  for (int ii=0; ii<8; ii++) {
    m_nakedTexSets[ii] = nakedSetNames[ii];
    m_setNums[ii] = -1; 
        m_mayaType[ii] = kNonMaya; 
  }
}
glslShaderNode::~glslShaderNode() {
        if (MGlobal::mayaState() != MGlobal::kBatch)
        {
                MHardwareRenderer *pRenderer = MHardwareRenderer::theRenderer();
                if (pRenderer)
                {
                        const MString & backEndStr = pRenderer->backEndString();
                        MStatus status = pRenderer->makeResourceContextCurrent( backEndStr );
                        if (status != MStatus::kSuccess) {
                                MStatus strStat;
                                MGlobal::displayError(MStringResource::getString(rGLSLShaderNodeFailedResourceContext, strStat));
                                MGlobal::displayError(status.errorString());
                        }
                }
        }
  
  for (std::vector<samplerAttrib>::iterator it=m_samplerAttribList.begin(); it<m_samplerAttribList.end(); it++) {
    ResourceManager::destroyTexture( it->texName);
  }
  
  { 
    std::vector<glslShaderNode*>::iterator it = std::find( sNodeList.begin(), sNodeList.end(), this);
    if (it != sNodeList.end()) {
      
      sNodeList.erase(it);
    }
    else {
      
    }
  }
  delete m_shader;
}
void glslShaderNode::postConstructor() {
}
MStatus glslShaderNode::compute( const MPlug& plug, MDataBlock& data) {
  
  
  if ((plug == outColor) || (plug.parent() == outColor))
  {
    MFloatVector color(.95f, .1f, .07f);
    MDataHandle outputHandle = data.outputValue( outColor );
    outputHandle.asFloatVector() = color;
    outputHandle.setClean();
    return MS::kSuccess;
  }
  return MS::kUnknownParameter;
}
void* glslShaderNode::creator() {
  glslShaderNode *ret = new glslShaderNode;
  
  sNodeList.push_back(ret);
  return ret;
}
MStatus glslShaderNode::initialize() {
  
  MFnTypedAttribute typedAttr;
  MFnStringData stringData;
  MStatus stat;
  MObject string;
  
  
  
  
  
  
  string = stringData.create(&stat);
  if (stat != MS::kSuccess)
    return MS::kFailure;
  sShader = typedAttr.create("shader", "s", MFnData::kString, string, &stat);
  if (stat != MS::kSuccess)
    return MS::kFailure;
  stat = typedAttr.setInternal(true);
  if (stat != MS::kSuccess)
    return MS::kFailure;
  
  if ( addAttribute(sShader) != MS::kSuccess)
    return MS::kFailure;
  
  
  
  
  
  string = stringData.create(&stat);
  if (stat != MS::kSuccess)
    return MS::kFailure;
  sTechnique = typedAttr.create("technique", "t", MFnData::kString, string, &stat);
  if (stat != MS::kSuccess)
    return MS::kFailure;
  stat = typedAttr.setInternal(true);
  if (stat != MS::kSuccess)
    return MS::kFailure;
  
  if ( addAttribute(sTechnique) != MS::kSuccess)
    return MS::kFailure;
  
  sTechniqueList = typedAttr.create("techniqueList", "tl", MFnData::kString, string, &stat);
  if (stat != MS::kSuccess)
    return MS::kFailure;
  stat = typedAttr.setInternal(true);
  if (stat != MS::kSuccess)
    return MS::kFailure;
  typedAttr.setWritable( false );
  typedAttr.setStorable( false );
  typedAttr.setHidden( true );
  typedAttr.setConnectable( false );
  
  if ( addAttribute(sTechniqueList) != MS::kSuccess)
    return MS::kFailure;
  
  sShaderPath = typedAttr.create("shaderPath", "sp", MFnData::kString, string, &stat);
  if (stat != MS::kSuccess)
    return MS::kFailure;
  stat = typedAttr.setInternal(true);
  if (stat != MS::kSuccess)
    return MS::kFailure;
  typedAttr.setWritable( false );
  typedAttr.setStorable( false );
  typedAttr.setHidden( true );
  typedAttr.setConnectable( false );  
  
  if ( addAttribute(sShaderPath) != MS::kSuccess)
    return MS::kFailure;
  int ii;
  
  
  
  for (ii=0; ii<8; ii++) {
    string = stringData.create( MString(nakedSetNames[ii]));
    sNakedTexCoords[ii] = typedAttr.create( MString("TexCoord") + ii, MString("t")+ ii, MFnData::kString, string);
    typedAttr.setInternal( true);
    typedAttr.setKeyable( true );
    addAttribute( sNakedTexCoords[ii]);
  }
  
  for (ii=0; ii<2; ii++) {
    sNakedColors[ii] = typedAttr.create( MString("Color") + ii, MString("c")+ ii, MFnData::kString);
    typedAttr.setInternal( true);
    typedAttr.setKeyable( true );
    addAttribute( sNakedColors[ii]);
  }
  return MS::kSuccess;
}
void glslShaderNode::rejigShaders( void *data) {
  
  for (std::vector<glslShaderNode*>::iterator it = sNodeList.begin(); it < sNodeList.end(); it++) {
    (*it)->rebuildShader();
  }
}
static bool textureInitPowerOfTwo(unsigned int val, unsigned int & retval)
{
        unsigned int res = 0;                           
        if (val)
        {
                
                
                val <<= 1;
                unsigned int low = 3;
                res = 1;
                while (val > low)
                {
                        low <<= 1;
                        res <<= 1;
                }
        }
        retval = res;
    return (res == (val>>1)) ? 1 : 0;
}
bool glslShaderNode::rebuildShader()
{
  
  
        bool rebuiltAnything = false;
        GL_CHECK;
        
        if (m_shaderDirty) {
                MGlobal::displayInfo(MString("Rebuild shader : ") + m_shaderPath.asChar() );
                
                delete m_shader;
        GL_CHECK;
                
        m_shader = shader::create(m_shaderPath.asChar());
        GL_CHECK;
                if (!m_shader) {
                        MStatus strStat;
                        MGlobal::displayError(MStringResource::getString(rGLSLShaderNodeFailedLoadShader, strStat));
            MGlobal::displayError(shader::sError.c_str());
                }
                else {
                        rebuiltAnything = true;
                        
                        
                        
                        
                        bool foundExistingTechnique = false;
                        if (m_techniqueName.length())
                        {
                                for (int ii=0; ii<m_shader->techniqueCount(); ii++) {
                                        if (m_techniqueName  == m_shader->techniqueName(ii)) {
                                                m_shader->setTechnique(ii);
                                                foundExistingTechnique = true;
                                                break;
                                        }
                                }
                        }
                        
                        
                        if (!foundExistingTechnique)
                        {
                                m_techniqueName = m_shader->techniqueName(0);
                        }
                        m_techniqueList = m_techniqueName ;
                        for (int ii=1; ii<m_shader->techniqueCount(); ii++)
                                m_techniqueList = m_techniqueList + " " + m_shader->techniqueName(ii);
                        
                        configureAttribs();
            GL_CHECK;
                }
                m_shaderDirty = false;
        }
    m_techniqueList = "";
        if (m_shader && m_shader->techniqueCount())
        {
                for (int ii=0; ii<m_shader->techniqueCount(); ii++)
                        m_techniqueList = m_techniqueList + " " + m_shader->techniqueName(ii);
        }
        return rebuiltAnything;
}
MObject glslShaderNode::findFileTextureNode( const MPlug &plug) {
  MPlugArray arr;
  MStatus stat;
  plug.connectedTo(arr, true, false, &stat);
  MObject srcNode;
  if (stat != MStatus::kSuccess)
    return MObject::kNullObj;
  if (arr.length() == 1)
    srcNode = arr[0].node();
  else if (arr.length() == 0 ) {
    
    return MObject::kNullObj;
  }
  else {
    
    MGlobal::displayWarning("Texture plug is connected to multiple nodes");
    return MObject::kNullObj;
  }
  
  if( srcNode != MObject::kNullObj) {
    MStatus rc;
    MFnDependencyNode dgFn( srcNode, &rc);
    MPlug fnPlug = dgFn.findPlug( "fileTextureName", &rc);
    if (rc == MStatus::kSuccess) {
      MStatus tStat;
      MObject fTex = fnPlug.node(&tStat);
      if ( tStat != MStatus::kSuccess)
        return MObject::kNullObj;
      else
        return fTex;
    }
  }
  return MObject::kNullObj;
}
MObject glslShaderNode::findEnvCubeNode( const MPlug &plug) {
  MPlugArray arr;
  plug.connectedTo(arr, true, false);
  MObject srcNode;
  if (arr.length() == 1)
    srcNode = arr[0].node();
  else if (arr.length() == 0 ) {
    
    return MObject::kNullObj;
  }
  else {
    
    MGlobal::displayWarning("Texture plug is connected to multiple nodes");
    return MObject::kNullObj;
  }
  
  
  if( srcNode != MObject::kNullObj) {
    MStatus rc;
    MFnDependencyNode dgFn( srcNode, &rc);
    
    MPlug fnPlug = dgFn.findPlug( "left", &rc);
    if (rc == MStatus::kSuccess) {
      MStatus tStat;
      MObject fCube = fnPlug.node(&tStat);
      if ( tStat != MStatus::kSuccess)
        return MObject::kNullObj;
      else
        return fCube;
    }
  }
  return MObject::kNullObj;
}
void glslShaderNode::loadCubeFace( glslShaderNode::CubeFace cf, MObject &cube, MFnDependencyNode &dn){
  const char* faceNames[] = { "left", "right", "top", "bottom", "front", "back"};
  const GLenum targets[] = {GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_X,
    GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
    GL_TEXTURE_CUBE_MAP_NEGATIVE_Z };
  float rgb[3];
  MObject face = dn.attribute( faceNames[cf]);
  MPlug plug( cube, face);
  MObject fTex = findFileTextureNode( plug);
  if (fTex != MObject::kNullObj) {
          MImage img;
          unsigned int width, height;
          img.readFromTextureNode(fTex);
          MStatus status = img.getSize( width, height);
          
          
          
          
          bool resizeToBeSquare = false;
          if (width != height)
          {
                  width = height;
                  resizeToBeSquare = true;
          }
          if (width > 0 && height > 0 && (status != MStatus::kFailure) )
          {
                  
                  
                  
                  if (!glTextureNonPowerOfTwo || resizeToBeSquare )
                  {
                          if (width > 2 && height > 2)
                          {
                                  unsigned int p2Width, p2Height;
                                  bool widthPowerOfTwo  = textureInitPowerOfTwo(width,  p2Width);
                                  bool heightPowerOfTwo = textureInitPowerOfTwo(height, p2Height);
                                  if(!widthPowerOfTwo || !heightPowerOfTwo || resizeToBeSquare)
                                  {
                                          width = p2Width;
                                          height = p2Height;
                                          img.resize( p2Width, p2Height, false );
                                  }
                          }
                  }
                  
                  glTexImage2D( targets[cf], 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.pixels());
                  GL_CHECK;
          }
  }
  else {
    MObject data;
    plug.getValue( data);
    MFnNumericData val(data);
    val.getData( rgb[0], rgb[1], rgb[2]);
    glTexImage2D( targets[cf], 0, GL_RGB8, 1, 1, 0, GL_RGB, GL_FLOAT, rgb);
  }
}
void glslShaderNode::BindSamplerData() {
  
  for ( std::vector<samplerAttrib>::iterator it = m_samplerAttribList.begin(); it < m_samplerAttribList.end(); it++) {
    
    if (it->dirty) {
      it->dirty = false;
      
      MPlug plug(thisMObject(), it->attrib);
      MObject data;
      plug.getValue(data);
      MFnNumericData val(data);
      float rgb[3];
      if (it->texName == 0) {
        
        glGenTextures( 1, &(it->texName));
        m_shader->updateSampler( it->pNum, it->texName);
        GL_CHECK;
      }
      switch (m_shader->samplerType(it->pNum) ) {
        case shader::st1D:
          
          val.getData( rgb[0], rgb[1], rgb[2]);
          glBindTexture( GL_TEXTURE_1D, it->texName);
          glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, it->minFilter);
          glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, it->magFilter);
          glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, it->wrapMode);
          glTexParameterf( GL_TEXTURE_1D, GL_TEXTURE_MAX_ANISOTROPY_EXT, it->maxAniso);
          if ( (it->minFilter == GL_LINEAR_MIPMAP_NEAREST) || (it->minFilter == GL_LINEAR_MIPMAP_LINEAR)) {
            glTexParameteri( GL_TEXTURE_1D, GL_GENERATE_MIPMAP, GL_TRUE);
          }
          else {
            glTexParameteri( GL_TEXTURE_1D, GL_GENERATE_MIPMAP, GL_FALSE);
          }
          glTexImage1D( GL_TEXTURE_1D, 0, GL_RGB8, 1, 0, GL_RGB, GL_FLOAT, rgb);
          GL_CHECK;
          break;
        case shader::st1DShadow:
          
          break;
        case shader::st2D:
          {
            bool done = false;
            
            glBindTexture( GL_TEXTURE_2D, it->texName);
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, it->minFilter);
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, it->magFilter);
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, it->wrapMode);
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, it->wrapMode);
            glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, it->maxAniso);
            if ( (it->minFilter == GL_LINEAR_MIPMAP_NEAREST) || (it->minFilter == GL_LINEAR_MIPMAP_LINEAR)) {
              glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
            }
            else {
              glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
            }
            MObject fTex = findFileTextureNode( plug);
                        if (fTex != MObject::kNullObj) {
                                MImage img;
                                unsigned int width, height;
                                img.readFromTextureNode(fTex);
                                MStatus status = img.getSize( width, height);
                            if (width > 0 && height > 0 && (status != MStatus::kFailure) )
                                {
                                        
                                        
                                        
                                        if (!glTextureNonPowerOfTwo)
                                        {
                                                if (width > 2 && height > 2)
                                                {
                                                        unsigned int p2Width, p2Height;
                                                        bool widthPowerOfTwo  = textureInitPowerOfTwo(width,  p2Width);
                                                        bool heightPowerOfTwo = textureInitPowerOfTwo(height, p2Height);
                                                        if(!widthPowerOfTwo || !heightPowerOfTwo)
                                                        {
                                                                width = p2Width;
                                                                height = p2Height;
                                                                img.resize( p2Width, p2Height, false );
                                                        }
                                                }
                                        }
                                        glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.pixels());
                                        GL_CHECK;
                                        done = true;
                                }
                        }
            
            if (!done) {
              
              val.getData( rgb[0], rgb[1], rgb[2]);
              glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, 1, 1, 0, GL_RGB, GL_FLOAT, rgb);
            }
            GL_CHECK;
          }
          break;
        case shader::stCube:
          {
            
            glBindTexture( GL_TEXTURE_CUBE_MAP, it->texName);
            glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, it->minFilter);
            glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, it->magFilter);
            glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, it->wrapMode);
            glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, it->wrapMode);
            glTexParameterf( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, it->maxAniso);
            if ( (it->minFilter == GL_LINEAR_MIPMAP_NEAREST) || (it->minFilter == GL_LINEAR_MIPMAP_LINEAR)) {
              glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_GENERATE_MIPMAP, GL_TRUE);
            }
            else {
              glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_GENERATE_MIPMAP, GL_FALSE);
            }
            MObject cube = findEnvCubeNode( plug);
            if ( cube != MObject::kNullObj) {
              MFnDependencyNode dn(cube);
              loadCubeFace( cfLeft, cube, dn);
              loadCubeFace( cfRight, cube, dn);
              loadCubeFace( cfTop, cube, dn);
              loadCubeFace( cfBottom, cube, dn);
              loadCubeFace( cfFront, cube, dn);
              loadCubeFace( cfBack, cube, dn);
            }
          }
          break;
        case shader::st2DShadow:
        case shader::st3D:
          
          break;
                default:
                  break;
      };
    }
  }
}
void glslShaderNode::BindUniformData() {
  for ( std::vector<uniformAttrib>::iterator it = m_uniformAttribList.begin(); it < m_uniformAttribList.end(); it++) {
        
        
        
    
        
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
    if (it->dirty) {
#endif
      it->dirty = false;
      MPlug plug(thisMObject(), it->attrib);
      MObject data;
      plug.getValue(data);
      MFnNumericData val(data);
      float fTemp[4];
      int iTemp[4];
      bool bTemp[4];
      switch (m_shader->uniformType(it->pNum)) {
        case shader::dtBool:
          plug.getValue(bTemp[0]);
          m_shader->updateUniformBool( it->pNum, bTemp[0]);
          break;
        case shader::dtBVec2:
        case shader::dtBVec3:
        case shader::dtBVec4:
          
          break;
        case shader::dtInt:
          plug.getValue(iTemp[0]);
          m_shader->updateUniformInt( it->pNum, iTemp[0]);
          break;
        case shader::dtIVec2:
          val.getData( iTemp[0], iTemp[1]);
          m_shader->updateUniformIVec( it->pNum, iTemp);
          break;
        case shader::dtIVec3:
          val.getData( iTemp[0], iTemp[1], iTemp[2]);
          m_shader->updateUniformIVec( it->pNum, iTemp);
          break;
        case shader::dtIVec4:
          
          break;
        case shader::dtFloat:
          plug.getValue(fTemp[0]);
          m_shader->updateUniformFloat( it->pNum, fTemp[0]);
          break;
        case shader::dtVec2:
          val.getData( fTemp[0], fTemp[1]);
          m_shader->updateUniformVec( it->pNum, fTemp);
          break;
        case shader::dtVec3:
          val.getData( fTemp[0], fTemp[1], fTemp[2]);
          m_shader->updateUniformVec( it->pNum, fTemp);
          break;
        case shader::dtVec4:
          {
            MPlug plug2(thisMObject(), it->attrib2);
            val.getData( fTemp[0], fTemp[1], fTemp[2]);
            plug2.getValue( fTemp[3]);
            m_shader->updateUniformVec( it->pNum, fTemp);
          }
          break;
        case shader::dtMat4:
          {
            MFnMatrixData mValue(data);
            MMatrix matrix = mValue.matrix();
            m_shader->updateUniformMat( it->pNum, (double*)matrix.matrix);
          }
          break;
        case shader::dtMat2:
        case shader::dtMat3:
        
          
          break;
                default:
                  break;
      };
    }
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
  }
#endif
}
bool glslShaderNode::supportsBatching() const
{
        return true;
}
MStatus glslShaderNode::glBind(const MDagPath& shapePath) {
    
        
        
        
  
  
  if (!InitializeExtensions()) {
        MStatus strStat;
    MGlobal::displayError(MStringResource::getString(rGLSLShaderNodeAshliFailedFindExtensions, strStat));
    return MStatus::kFailure;
  }
    GL_CHECK;
    
    ResourceManager::recover();
        
        if (!sDefShader)
                sDefShader = new defaultShader;
    GL_CHECK;
  
  
  
  if (m_shader) {
    if (!m_shader->build())
      MGlobal::displayError(MString(m_shader->errorString()));
    BindUniformData();
    
    BindSamplerData();
  }
  
  
  glDisable(GL_POINT_SMOOTH);
  glDisable( GL_LINE_SMOOTH);
  
  if ((m_shader != NULL) && (m_shader->valid())) 
  {
    m_passCount = m_shader->passCount();
    
    if (!m_shader->build()) {
      m_passCount = 0;
    }
        if( m_passCount == 1)
        {
                m_shader->setPass( 0);
                m_shader->bind();
        }
  }
  else
  {
    m_passCount = -1;
        m_maxSetNum = 1; 
        sDefShader->bind();
  }
        
        glEnableClientState(GL_VERTEX_ARRAY);
        glEnable(GL_VERTEX_PROGRAM_TWO_SIDE);
  GL_CHECK;
  return MS::kSuccess;
}
MStatus glslShaderNode::glUnbind(const MDagPath& shapePath) {
        for (std::vector<attributeAttrib>::iterator it=m_attributeAttribList.begin(); it<m_attributeAttribList.end(); it++) 
                glDisableVertexAttribArray( it->handle);
        for( int ii = 0; ii < m_maxSetNum; ii++) 
                m_glState.disableTexCoord( ii);
        m_glState.activeTexture( 0);
    glDisableClientState(GL_COLOR_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);
        glDisableClientState(GL_VERTEX_ARRAY);
        glDisable(GL_VERTEX_PROGRAM_TWO_SIDE);
        
        if( m_passCount < 0)
                sDefShader->unbind();
        else if( m_passCount == 1)
                m_shader->unbind();
  
  
  m_parsedUserAttribList = false;
  return MS::kSuccess;
}
void glslShaderNode::updateBoundAttributes( const MDagPath& shapePath) {
  
  
  
  
  
  
  MMatrix world;
  MMatrix temp;
  MMatrix proj;
  MMatrix view;
  MMatrix worldview;
  
  if (shapePath.isValid())
          world = shapePath.inclusiveMatrix();
  else
          world.setToIdentity();
  glGetDoublev( GL_PROJECTION_MATRIX, (double*)proj.matrix);
  glGetDoublev( GL_MODELVIEW_MATRIX, (double*)worldview.matrix);
  view = world.inverse() * worldview;
  for (std::vector<boundUniform>::iterator it = m_boundUniformList.begin(); it < m_boundUniformList.end(); it++) {
    switch ( it->usage) {
      case shader::smWorld:
        m_shader->updateUniformMat( it->pNum, (double*)world.matrix);
        break;
      case shader::smView:
        m_shader->updateUniformMat( it->pNum, (double*)view.matrix);
        break;
      case shader::smProjection:
        m_shader->updateUniformMat( it->pNum, (double*)proj.matrix);
        break;
      case shader::smWorldView:
        m_shader->updateUniformMat( it->pNum, (double*)worldview.matrix);
        break;
      case shader::smViewProjection:
        temp = view * proj;
        m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
        break;
      case shader::smWorldViewProjection:
        temp = worldview * proj;
        m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
        break;
      case shader::smWorldI:
        temp = world.inverse();
        m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
        break;
      case shader::smViewI:
        temp = view.inverse();
        m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
        break;
      case shader::smProjectionI:
        temp = proj.inverse();
        m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
        break;
      case shader::smWorldViewI:
        temp = worldview.inverse();
        m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
        break;
      case shader::smViewProjectionI:
        temp = view * proj;
        temp = temp.inverse();
        m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
        break;
      case shader::smWorldViewProjectionI:
        temp = worldview * proj;
        temp = temp.inverse();
        m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
        break;
      case shader::smWorldT:
        temp = world.transpose();
        m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
        break;
      case shader::smViewT:
        temp = view.transpose();
        m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
        break;
      case shader::smProjectionT:
        temp = proj.transpose();
        m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
        break;
      case shader::smWorldViewT:
        temp = worldview.transpose();
        m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
        break;
      case shader::smViewProjectionT:
        temp = view * proj;
        temp = temp.transpose();
        m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
        break;
      case shader::smWorldViewProjectionT:
        temp = worldview * proj;
        temp = temp.transpose();
        m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
        break;
      case shader::smWorldIT:
        temp = world.inverse().transpose();
        m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
        break;
      case shader::smViewIT:
        temp = view.inverse().transpose();
        m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
        break;
      case shader::smProjectionIT:
        temp = proj.inverse().transpose();
        m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
        break;
      case shader::smWorldViewIT:
        temp = worldview.inverse().transpose();
        m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
        break;
      case shader::smViewProjectionIT:
        temp = view * proj;
        temp = temp.inverse().transpose();
        m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
        break;
      case shader::smWorldViewProjectionIT:
        temp = worldview * proj;
        temp = temp.inverse().transpose();
        m_shader->updateUniformMat( it->pNum, (double*)temp.matrix);
        break;
      case shader::smViewPosition:
        {
          float vec[4];
          temp = view.inverse();
          vec[0] = (float)temp[3][0];
          vec[1] = (float)temp[3][1];
          vec[2] = (float)temp[3][2];
          vec[3] = (float)temp[3][3];
          m_shader->updateUniformVec( it->pNum, vec);
        }
        break;
      
      case shader::smTime:
        
        
        
        
        
        
        m_shader->updateUniformFloat( it->pNum, 0.0f);
        break;
      
      case shader::smViewportSize:
        {
          float vp[4];
          glGetFloatv( GL_VIEWPORT, vp);
          m_shader->updateUniformVec( it->pNum, &vp[2]);
        }
        break;
          default:
                break;
    };
  }
}
void glslShaderNode::configureTexCoords( int normalCount, const float ** normalArrays, 
                                                                                int texCoordCount,
                                        const float ** texCoordArrays,
                                                                                int colorCount,
                                                                                const float ** colorArrays) 
{
  
                                                                                        
  int ii;
  
  for (ii=0; ii<m_maxSetNum; ii++) {
    
    if (m_setNums[ii] == -1) {
      
      glMultiTexCoord2f( GL_TEXTURE0 + ii, 0.0f, 0.0f);
      m_glState.disableTexCoord( ii);
      continue;
    }
    else if (m_mayaType[ii] == kNormal)  {
      
      if ( (normalCount > 0) && normalArrays[0]) {
        
        m_glState.enableAndActivateTexCoord( ii);
        glTexCoordPointer( 3, GL_FLOAT, 0, normalArrays[0]);
      }
      else {
        
        glMultiTexCoord3f( GL_TEXTURE0 + ii, 0.0f, 0.0f, 1.0f);
        m_glState.disableTexCoord( ii);
      }
      continue;
    }
    else if (m_mayaType[ii] == kTangent)  {
      
      if ( m_numNormals > 1  && normalCount > 1)
          {
                  int offset = 0;
                  if (m_numNormals > 2)
                        offset = ( m_setNums[ii] * 3 ) + 1;
                  else
                        offset = ( m_setNums[ii] * 2 ) + 1;
                  
                  if (offset > normalCount)
                  {
                          if (normalCount >= 2)
                                  offset = 1;
                          else
                                  offset = -1;
                  }
                  
                
                  if ((offset > 0) && normalArrays[offset]) {
                          
                          m_glState.enableAndActivateTexCoord( ii);
                          glTexCoordPointer( 3, GL_FLOAT, 0, normalArrays[offset]);
                  }
                  else {
                          
                          glMultiTexCoord3f( GL_TEXTURE0 + ii, 1.0f, 0.0f, 0.0f);
                          m_glState.disableTexCoord( ii);
                  }
          }
          else
          {
                  
                  glMultiTexCoord3f( GL_TEXTURE0 + ii, 1.0f, 0.0f, 0.0f);
                  m_glState.disableTexCoord( ii);
          }
      continue;
    }
    else if (m_mayaType[ii] == kBinormal)  {
      
      if ( m_numNormals > 2 && normalCount > 1)
          {
                  int offset = ( m_setNums[ii] * 3 ) + 2;
                  
                  if (offset > normalCount)
                  {
                          if (normalCount >= 3)
                                  offset = 2;
                          else
                                  offset = -1;
                  }
                  
                        
                  if ((offset > 0) && normalArrays[offset] )
                  {
                          
                          m_glState.enableAndActivateTexCoord( ii);
                          glTexCoordPointer( 3, GL_FLOAT, 0, normalArrays[offset]);
                  }
                  else
                  {
                          
                          glMultiTexCoord3f( GL_TEXTURE0 + ii, 0.0f, 1.0f, 0.0f);
                          m_glState.disableTexCoord( ii);
                  }
      }
      else 
          {
        
        glMultiTexCoord3f( GL_TEXTURE0 + ii, 0.0f, 1.0f, 0.0f);
        m_glState.disableTexCoord( ii);
      }
      continue;
    }
    else if (m_mayaType[ii] == kColorSet) {
      
      if ( (m_setNums[ii] < colorCount) && colorArrays[m_setNums[ii]]) {
        
        m_glState.enableAndActivateTexCoord( ii);
        glTexCoordPointer( 4, GL_FLOAT, 0, colorArrays[m_setNums[ii]]);
      }
      else {
        
        glMultiTexCoord4f( GL_TEXTURE0 + ii, 0.0f, 0.0f, 0.0f, 1.0f);
        m_glState.disableTexCoord( ii);
      }
      continue;
    }
    
    if ( (m_setNums[ii] < texCoordCount) && texCoordArrays[m_setNums[ii]]) {
      
      m_glState.enableAndActivateTexCoord( ii);
          glTexCoordPointer( 2, GL_FLOAT, 0, texCoordArrays[m_setNums[ii]]);
    }
    else {
      
      glMultiTexCoord2f( GL_TEXTURE0 + ii, 0.0f, 0.0f);
      m_glState.disableTexCoord( ii);
    }
  }
  
  
    glColor4f( 1.0f, 1.0f, 1.0f, 1.0f);
    glDisableClientState( GL_COLOR_ARRAY);
  
  if (m_colorSetNums[0] == -1) {
    
    glColor4f( 1.0f, 1.0f, 1.0f, 1.0f);
    glDisableClientState( GL_COLOR_ARRAY);
  }
  else if (m_colorMayaType[0] == kNormal)  {
          
          
    if ( (normalCount > 0) && normalArrays[0]) {
      
      glColorPointer( 3, GL_FLOAT, 0, normalArrays[0]);
      glEnableClientState( GL_COLOR_ARRAY);
    }
    else {
      
      glColor4f( 0.0f, 0.0f, 1.0f, 1.0f);
      glDisableClientState( GL_COLOR_ARRAY);
    }
  }
  else if (m_colorMayaType[0] == kTangent)  {
          
          if ( m_numNormals > 1 && normalCount > 1)
          {
                  int offset = 0;
                  if (m_numNormals > 2)
                          offset = ( m_colorSetNums[0] * 3 ) + 1;
                  else
                          offset = ( m_colorSetNums[0] * 2 ) + 1;
                  
                  if (offset > normalCount)
                  {
                          if (normalCount >= 2)
                                  offset = 1;
                          else
                                  offset = -1;
                  }
                  
                        
                  if ((offset > 0) && normalArrays[offset]) {
                          
                          glColorPointer( 3, GL_FLOAT, 0, normalArrays[offset]);
                          glEnableClientState( GL_COLOR_ARRAY);
                  }
                  else {
                          
                          glColor4f( 1.0f, 0.0f, 0.0f, 1.0f);
                          glDisableClientState( GL_COLOR_ARRAY);
                  }
          }
          else {
                  
                  glColor4f( 1.0f, 0.0f, 0.0f, 1.0f);
                  glDisableClientState( GL_COLOR_ARRAY);
          }               
  }
  else if (m_colorMayaType[0] == kBinormal)  {
      
          if ( m_numNormals > 2 && normalCount > 1)
          {
                  int offset = ( m_colorSetNums[0] * 3 ) + 2;
                  
                  if (offset > normalCount)
                  {
                          if (normalCount >= 3)
                                  offset = 2;
                          else
                                  offset = -1;
                  }
                  
                        
                  if ((offset > 0) && normalArrays[offset] )
                  {
                          
                          glColorPointer( 3, GL_FLOAT, 0, normalArrays[offset]);
                          glEnableClientState( GL_COLOR_ARRAY);
                  }
                  else
                  {
                          
                          glMultiTexCoord3f( GL_TEXTURE0 + ii, 0.0f, 1.0f, 0.0f);
                          m_glState.disableTexCoord( ii);
                  }
          }
          else 
          {
                  
                  glColor4f( 0.0f, 1.0f, 0.0f, 1.0f);
                  glDisableClientState( GL_COLOR_ARRAY);
          }
  }
  
  else if (m_colorMayaType[0] == kColorSet) {
    
    if ( (m_colorSetNums[0] < colorCount) && colorArrays[m_colorSetNums[0]]) {
      
      glColorPointer( 4, GL_FLOAT, 0, colorArrays[m_colorSetNums[0]]);
      glEnableClientState( GL_COLOR_ARRAY);
    }
    else {
      
      glColor4f( 0.0f, 0.0f, 0.0f, 1.0f);
      glDisableClientState( GL_COLOR_ARRAY);
    }
  }
  
  else if (m_colorMayaType[0] == kUvSet) {
    
    if ( (m_colorSetNums[0] < texCoordCount) && texCoordArrays[m_colorSetNums[0]]) {
      
      glColorPointer( 2, GL_FLOAT, 0, texCoordArrays[m_colorSetNums[0]]);
      glEnableClientState( GL_COLOR_ARRAY);
    }
    else {
      
      glColor4f( 1.0f, 0.0f, 0.0f, 1.0f);
      glDisableClientState( GL_COLOR_ARRAY);
    }
  }
  
  if (glSecondaryColorSupport) {
        glSecondaryColor3f( 1.0f, 1.0f, 1.0f);
        glDisableClientState( GL_SECONDARY_COLOR_ARRAY);
          
        
    if (m_colorSetNums[1] == -1) {
                
                glSecondaryColor3f( 1.0f, 1.0f, 1.0f);
                glDisableClientState( GL_SECONDARY_COLOR_ARRAY);
    }
    else if (m_colorMayaType[1] == kNormal)  {
      
      if ( (normalCount > 0) && normalArrays[0]) {
        
        glSecondaryColorPointer( 3, GL_FLOAT, 0, normalArrays[0]);
        glEnableClientState( GL_SECONDARY_COLOR_ARRAY);
      }
      else {
        
        glSecondaryColor3f( 0.0f, 0.0f, 1.0f);
        glDisableClientState( GL_SECONDARY_COLOR_ARRAY);
      }
    }
    else if (m_colorMayaType[1] == kTangent)  {
          
          if ( m_numNormals > 1 && normalCount > 1)
          {
                  int offset = 0;
                  if (m_numNormals > 2)
                          offset = ( m_colorSetNums[1] * 3 ) + 1;
                  else
                          offset = ( m_colorSetNums[1] * 2 ) + 1;
                  
                  if (offset > normalCount)
                  {
                          if (normalCount >= 2)
                                  offset = 1;
                          else
                                  offset = -1;
                  }
                  
                        
                  if ((offset > 0) && normalArrays[offset]) {
                          
                          glSecondaryColorPointer( 3, GL_FLOAT, 0, normalArrays[offset]);
                          glEnableClientState( GL_SECONDARY_COLOR_ARRAY);
                  }
                  else {
                          
                          glSecondaryColor3f( 1.0f, 0.0f, 0.0f);
                          glDisableClientState( GL_SECONDARY_COLOR_ARRAY);
                  }
          }
          else {
                  
                  glSecondaryColor3f( 1.0f, 0.0f, 0.0f);
                  glDisableClientState( GL_SECONDARY_COLOR_ARRAY);
          }             
    }
    else if (m_colorMayaType[1] == kBinormal)  {
      
          if ( m_numNormals > 2 && normalCount > 1 )
          {
                  int offset = ( m_colorSetNums[1] * 3 ) + 2;
                  
                  if (offset > normalCount)
                  {
                          if (normalCount >= 3)
                                  offset = 2;
                          else
                                  offset = -1;
                  }
                  
                        
                  if ((offset > 0) && normalArrays[offset] )
                  {
                          
                          glSecondaryColorPointer( 3, GL_FLOAT, 0, normalArrays[offset]);
                          glEnableClientState( GL_SECONDARY_COLOR_ARRAY);
                  }
                  else
                  {
                          
                          glSecondaryColor3f( 0.0f, 1.0f, 0.0f);
                          glDisableClientState( GL_SECONDARY_COLOR_ARRAY);
                  }
          }
          else 
          {
                  
                  glSecondaryColor3f( 0.0f, 1.0f, 0.0f);
                  glDisableClientState( GL_SECONDARY_COLOR_ARRAY);
          }             
    }
        
    else if (m_colorMayaType[1] == kColorSet) {
      
      if ( (m_colorSetNums[1] < colorCount) && colorArrays[m_colorSetNums[1]]) {
        
        glSecondaryColorPointer( 4, GL_FLOAT, 0, colorArrays[m_colorSetNums[1]]);
        glEnableClientState( GL_SECONDARY_COLOR_ARRAY);
      }
      else {
        
        glSecondaryColor3f( 1.0f, 1.0f, 1.0f);
        glDisableClientState( GL_SECONDARY_COLOR_ARRAY);
      }
    }
#if 0
        
        else if (m_colorMayaType[1] == kUvSet) {
                
                if ( (m_colorSetNums[1] < texCoordCount) && texCoordArrays[m_colorSetNums[1]]) {
                        
                        glSecondaryColorPointer( 2, GL_FLOAT, 0, texCoordArrays[m_colorSetNums[1]]);
                        glEnableClientState( GL_COLOR_ARRAY);
                }
                else {
                        
                        glColor4f( 0.0f, 0.0f, 0.0f, 1.0f);
                        glDisableClientState( GL_COLOR_ARRAY);
                }
        }
#endif
  }
  
  for (std::vector<attributeAttrib>::iterator it=m_attributeAttribList.begin(); it<m_attributeAttribList.end(); it++) {
    
    it->handle = m_shader->attributeHandle(it->pNum);
    if (it->set == -1) {
      glDisableVertexAttribArray( it->handle);
      glVertexAttrib2f( it->handle, 0.0f, 0.0f);
      continue;
    }
    else if (it->mtype == kNormal) {
      
      if (( normalCount > 0) && normalArrays[0]) {
        
        glVertexAttribPointer( it->handle, 3, GL_FLOAT, GL_FALSE, 0, normalArrays[0]);
        glEnableVertexAttribArray( it->handle);
      }
      else {
        
        glVertexAttrib2f( it->handle, 0.0f, 0.0f);
        glDisableVertexAttribArray( it->handle);
      }
      continue;
    }
    else if (it->mtype == kTangent) {
          
          if ( m_numNormals > 1 && normalCount > 1)
          {
                  int offset = 0;
                  if (m_numNormals > 2)
                          offset = ( it->set * 3 ) + 1;
                  else
                          offset = ( it->set * 2 ) + 1;
                  
                  if (offset > normalCount)
                  {
                          if (normalCount >= 2)
                                  offset = 1;
                          else
                                  offset = -1;
                  }
                  
                        
                  if ((offset > 0) && normalArrays[offset]) {
                          
                          glVertexAttribPointer( it->handle, 3, GL_FLOAT, GL_FALSE, 0, normalArrays[offset]);
                          glEnableVertexAttribArray( it->handle);
                  }
                  else {
                          
                          glVertexAttrib2f( it->handle, 0.0f, 0.0f);
                          glDisableVertexAttribArray( it->handle);
                  }
          }
          else {
                  
                  glVertexAttrib2f( it->handle, 0.0f, 0.0f);
                  glDisableVertexAttribArray( it->handle);
          }                             
      continue;
    }
    else if (it->mtype == kBinormal) {
      
          if ( m_numNormals > 2 && normalCount > 1)
          {
                  int offset = ( it->set * 3 ) + 2;
                  
                  if (offset > normalCount)
                  {
                          if (normalCount >= 3)
                                  offset = 2;
                          else
                                  offset = -1;
                  }
                  
                        
                  if ((offset > 0) && normalArrays[offset] )
                  {
                          
                          glVertexAttribPointer( it->handle, 3, GL_FLOAT, GL_FALSE, 0, normalArrays[offset]);
                          glEnableVertexAttribArray( it->handle);
                  }
                  else
                  {
                          
                          glVertexAttrib2f( it->handle, 0.0f, 0.0f);
                          glDisableVertexAttribArray( it->handle);
                  }
          }
          else
          {
        
        glVertexAttrib2f( it->handle, 0.0f, 0.0f);
        glDisableVertexAttribArray( it->handle);
          }
      continue;
    }
    else if (it->mtype == kColorSet) {
      
      if (( it->set < colorCount ) && colorArrays[it->set]) {
        
        glVertexAttribPointer( it->handle, 4, GL_FLOAT, GL_FALSE, 0, colorArrays[it->set]);
        glEnableClientState( it->handle );
      }
      else {
        
        glVertexAttrib4f( it->handle, 0.0f, 0.0f, 0.0f, 1.0f);
        glDisableVertexAttribArray( it->handle);
      }
      continue;
    }
    
    if (( it->set < texCoordCount ) && texCoordArrays[it->set]) {
      
      glVertexAttribPointer( it->handle, 2, GL_FLOAT, GL_FALSE, 0, texCoordArrays[it->set]);
      glEnableVertexAttribArray( it->handle);
    }
    else {
      
      glVertexAttrib2f( it->handle, 0.0f, 0.0f);
      glDisableVertexAttribArray( it->handle);
    }
  }
  m_glState.activeTexture( 0);
}
MStatus glslShaderNode::glGeometry( const MDagPath& shapePath, 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 (!(glShadingLanguageSupport && glMultiTextureSupport && glTexture3DSupport && glAsmProgramSupport))
    return MStatus::kFailure;
  
  
  if( m_passCount > 0)
    updateBoundAttributes(shapePath);
  
  int passCount = m_passCount >= 0 ? m_passCount : 1;
  for( int jj=0; jj < passCount; jj++) 
  {
        
        
        
    if( passCount > 1) 
        {
                m_shader->setPass( jj);
                m_shader->bind();
        }
        
        if( m_passCount > 0)
        {
                m_shader->setShapeDependentState();
    }
        else
        {
                sDefShader->setShapeDependentState();
        }
    
    
    glVertexPointer( 3, GL_FLOAT, 0, vertexArray);
    
    if (normalCount && normalArrays[0] ) {
      glNormalPointer( GL_FLOAT, 0, &normalArrays[0][0]);
      glEnableClientState(GL_NORMAL_ARRAY);
    }
        else
        {
      glDisableClientState(GL_NORMAL_ARRAY);
        }
  
    configureTexCoords( normalCount, normalArrays, texCoordCount, texCoordArrays,
                                            colorCount, colorArrays );
    
    GL_CHECK;
    
    glDrawElements( prim, indexCount, GL_UNSIGNED_INT, indexArray);
        
        
        
    if( m_passCount > 1) 
        {
      m_shader->unbind();
        }
    GL_CHECK;
  }
        
  if( m_passCount > 1) 
        m_shader->setPass(0);
  return MS::kSuccess;
}
MStatus                 
glslShaderNode::connectionMade( const MPlug& plug,
                                                           const MPlug& otherPlug,
                                                           bool asSrc )
{
        
        const MPlug &root = plug.isChild() ? plug.parent() : plug; 
        
        
        
        
        {
                for ( std::vector<uniformAttrib>::iterator it = m_uniformAttribList.begin(); it < m_uniformAttribList.end(); it++) {
                        if ( root == it->attrib) {
                                it->dirty = true;
                                
                                break;
                        }
                }
        }
        {
                for ( std::vector<samplerAttrib>::iterator it = m_samplerAttribList.begin(); it < m_samplerAttribList.end(); it++) {
                        if ( root == it->attrib) {
                                it->dirty = true;
                                
                                break;
                        }
                }
        }
        
        
        return MS::kUnknownParameter;
}
MStatus         
glslShaderNode::connectionBroken( const MPlug& plug,
                                                                 const MPlug& otherPlug,
                                                                 bool asSrc )
{
        
        const MPlug &root = plug.isChild() ? plug.parent() : plug; 
        
        
        
        
        {
                for ( std::vector<uniformAttrib>::iterator it = m_uniformAttribList.begin(); it < m_uniformAttribList.end(); it++) {
                        if ( root == it->attrib) {
                                it->dirty = true;
                                
                                break;
                        }
                }
        }
        {
                for ( std::vector<samplerAttrib>::iterator it = m_samplerAttribList.begin(); it < m_samplerAttribList.end(); it++) {
                        if ( root == it->attrib) {
                                it->dirty = true;
                                
                                break;
                        }
                }
        }
        
        
        return MS::kUnknownParameter;
}
bool glslShaderNode::getInternalValueInContext( const MPlug &plug, 
                                                                                           MDataHandle &handle,
                                                                                           MDGContext& )
{
  bool retVal = false;
  if ( plug == sShader) {
    handle.set(m_shaderName);
    retVal = true;
  }
  else if ( plug == sTechnique) {
    handle.set(m_techniqueName);
    retVal = true;
  }
  else if ( plug == sTechniqueList )
  {
        handle.set(m_techniqueList);
        retVal = true;
  }
  else if ( plug == sShaderPath )
  {
        handle.set(m_shaderPath);
        retVal = true;
  }  
  else {
    int ii;
    for (ii=0; ii<8; ii++) {
      if ( plug == sNakedTexCoords[ii]) {
        handle.set(m_nakedTexSets[ii]);
        retVal = true;
        break;
      }
    }
    for (ii=0; ii<2; ii++) {
      if (plug == sNakedColors[ii]) {
        handle.set(m_nakedColorSets[ii]);
        retVal = true;
        break;
      }
    }
    
    for (std::vector<attributeAttrib>::iterator it=m_attributeAttribList.begin(); it<m_attributeAttribList.end(); it++) {
      if (plug == it->attrib) {
        handle.set(it->setName);
        retVal = true;
        break;
      }
    }
  }
  return retVal;
}
bool glslShaderNode::setInternalValueInContext( const MPlug &plug, 
                                                                                           const MDataHandle &handle,
                                                                                           MDGContext & )
{
  bool retVal = false;
  
  
  bool reading = MFileIO::isReadingFile();
  if (reading)
          m_shader = NULL;
  
  if ( plug == sShader) {
    m_shaderName = handle.asString();
        m_shaderPath = m_shaderName;
    if (locateFile( m_shaderName, m_shaderPath)) {
          
          
          
          
      m_shaderDirty = true;
      if (!reading) {
                  if (MGlobal::mayaState() == MGlobal::kBatch)
                        rebuildShader();
                else
                {
                        MHardwareRenderer *pRenderer = MHardwareRenderer::theRenderer();
                        if (pRenderer)
                        {
                                const MString & backEndStr = pRenderer->backEndString();
                                MStatus status = pRenderer->makeResourceContextCurrent( backEndStr );
                                if (status != MStatus::kSuccess) {
                                        MStatus strStat;
                                        MGlobal::displayError(MStringResource::getString(rGLSLShaderNodeFailedResourceContext, strStat));
                                        MGlobal::displayError(status.errorString());
                                }
                                else
                                        rebuildShader();
                        }
                }
      }
    }
    else {
      MGlobal::displayError(MString("Couldn't find shader file: '") + m_shaderPath + "'");
    }
    retVal = true;
  }
  else if ( plug == sTechnique) {
    MString temp = handle.asString();
        
        
        
        if (reading)
        {
                m_techniqueName = temp;
                retVal = true;
        }
        else
        {
    if (m_shader) {
      for (int ii=0; ii<m_shader->techniqueCount(); ii++) {
        if (temp == m_shader->techniqueName(ii)) {
          m_shader->setTechnique(ii);
          retVal = true;
          break;
        }
      }
    }
    if (retVal)
      m_techniqueName = temp;
    else
                {
                        MGlobal::displayWarning(MString("Unknown technique: ") + temp +
                        MString(" for shader: ") + m_shaderPath.asChar());
                }
        }
    retVal = true;
  }
  else if ( plug == sTechniqueList )
  {
          
  }
  else {
    int ii;
    
    for (ii=0; ii<8; ii++) {
      if (plug == sNakedTexCoords[ii]) {
        m_nakedTexSets[ii] = handle.asString();
        
        return true;
      }
    }
    for (ii=0; ii<2; ii++) {
      if (plug == sNakedColors[ii]) {
        m_nakedColorSets[ii] = handle.asString();
        
        return true;
      }
    }
    
    for (std::vector<attributeAttrib>::iterator it=m_attributeAttribList.begin(); it<m_attributeAttribList.end(); it++) {
      if (plug == it->attrib) {
        it->setName = handle.asString();
        return true;
      }
    }
    
    if (!reading) {
      
      
      const MPlug &root = plug.isChild() ? plug.parent() : plug; 
      
      
  
      
      
      
      for ( std::vector<uniformAttrib>::iterator it2 = m_uniformAttribList.begin(); it2 < m_uniformAttribList.end(); it2++) {
        if ( ( root == it2->attrib) || ( root == it2->attrib2) ){
                        it2->dirty = true;
          
          break;
        }
      }
      for ( std::vector<samplerAttrib>::iterator it = m_samplerAttribList.begin(); it < m_samplerAttribList.end(); it++) {
        if (root == it->attrib) {
          it->dirty = true;
          
          break;
        }
        if (root == it->anisoAttrib) {
          it->dirty = true;
          it->maxAniso = handle.asFloat();
          
          break;
        }
        if (root == it->magFilterAttrib) {
          it->dirty = true;
          switch (handle.asShort()) {
            case 0:
              it->magFilter = GL_NEAREST;
              break;
            case 1:
              it->magFilter = GL_LINEAR;
              break;
            default:
              
              it->magFilter = GL_LINEAR;
              break;
          };
          
          break;
        }
        if (root == it->minFilterAttrib) {
          it->dirty = true;
          switch (handle.asShort()) {
            case 0:
              it->minFilter = GL_NEAREST;
              break;
            case 1:
              it->minFilter = GL_LINEAR;
              break;
            case 2:
              it->minFilter = GL_LINEAR_MIPMAP_NEAREST;
              break;
            case 3:
              it->minFilter = GL_LINEAR_MIPMAP_LINEAR;
              break;
            default:
              
              it->minFilter = GL_LINEAR;
              break;
          };
          
          break;
        }
        if (root == it->wrapAttrib) {
          it->dirty = true;
          switch (handle.asShort()) {
            case 0:
              it->wrapMode = GL_REPEAT;
              break;
            case 1:
              it->wrapMode = GL_CLAMP_TO_EDGE;
              break;
            case 2:
              it->wrapMode = GL_MIRRORED_REPEAT;
              break;
            default:
              
              it->wrapMode = GL_REPEAT;
              break;
          };
          
          break;
        }
      }
    }
  }
  GL_CHECK;
  return retVal;
}
void glslShaderNode::copyInternalData( MPxNode* pMPx )
{
        glslShaderNode* pNode = dynamic_cast<glslShaderNode*>( pMPx );
        m_shader = NULL;
        m_shaderDirty = false;
        
        m_uniformAttribList.clear();
        m_samplerAttribList.clear();
        m_attributeAttribList.clear();
        m_boundUniformList.clear();
        
        m_parsedUserAttribList = false;
        m_numUVsets = 0;
        m_uvSetNames.clear();
        m_numColorSets = 0;
        m_colorSetNames.clear();        
        m_numNormals = 3;
        m_maxSetNum = pNode->m_maxSetNum;
        if( pNode )
        {
                for(int ii=0; ii<8; ii++)
                {
                        m_nakedTexSets[ii] = pNode->m_nakedTexSets[ii];
                        m_setNums[ii] = pNode->m_setNums[ii];
                        m_mayaType[ii] = pNode->m_mayaType[ii];
                }
                m_nakedColorSets[0] = pNode->m_nakedColorSets[0];
                m_nakedColorSets[1] = pNode->m_nakedColorSets[1];
                m_colorSetNums[0] = pNode->m_colorSetNums[0]; 
                m_colorSetNums[1] = pNode->m_colorSetNums[1]; 
                m_colorMayaType[0] = pNode->m_colorMayaType[0];
                m_colorMayaType[1] = pNode->m_colorMayaType[1];
                m_shaderName = pNode->m_shaderName;
                m_shaderPath = m_shaderName;            
                m_techniqueList = "";
                m_techniqueName = "";
                if (locateFile( m_shaderName, m_shaderPath))
                {
                        
                        m_techniqueName = pNode->m_techniqueName;
                        m_shaderDirty = true;
                        MHardwareRenderer *pRenderer = MHardwareRenderer::theRenderer();
                        if (pRenderer)
                        {
                                const MString & backEndStr = pRenderer->backEndString();
                                MStatus status = pRenderer->makeResourceContextCurrent( backEndStr );
                                if (status != MStatus::kSuccess) {
                                        MStatus strStat;
                                        MGlobal::displayError(MStringResource::getString(rGLSLShaderNodeFailedResourceContext, strStat));
                                        MGlobal::displayError(status.errorString());
                                }
                                else
                                        rebuildShader();
                        }
                        else
                                rebuildShader();
                }
        }
}
int glslShaderNode::colorsPerVertex() {
  return 1;
}
int glslShaderNode::texCoordsPerVertex() {
    return 0;
}
#if MAYA_API_VERSION >= 700
  
  
  
  
void glslShaderNode::parseUserAttributeList()
{
  if (m_parsedUserAttribList)
    return;
  
  
  
  m_numUVsets = 0;
  m_numColorSets = 0;
  m_uvSetNames.clear();
  m_colorSetNames.clear();
  m_numNormals = 3;
  MStringArray uvSetNames;
  MStringArray colorSetNames;
  bool haveNurbs = false;
  
  MString nurbsDefaultUV("Nurbs Tri UVs"); 
  const MDagPath & path = currentPath();        
  if (path.hasFn( MFn::kMesh ) )
  {
    
    MFnMesh fnMesh( path.node() );
    if (fnMesh.numUVSets())
      fnMesh.getUVSetNames(uvSetNames);
    
    if (fnMesh.numColorSets())
      fnMesh.getColorSetNames(colorSetNames);
  }
  else 
  {
    haveNurbs = true;
    uvSetNames.append(nurbsDefaultUV);
    
    
  }
  
  
  
  
  
  
  
  int ii = 0;
  for (; ii<8; ii++) 
  {
    m_setNums[ii] = -1;
    m_mayaType[ii] = kNonMaya;
  }
  
  
  
  
  const char _splitChar = ':';
  ii = 0;
  for (; ii<8; ii++) 
  {
          MStringArray splitStrings;    
          MString comparisonString = m_nakedTexSets[ii];
          if ((MStatus::kSuccess == comparisonString.split(_splitChar, splitStrings)) &&
                   splitStrings.length() > 1)
          {
                  comparisonString = splitStrings[0];
          }
          
          
          if (haveNurbs && comparisonString == "map1") 
          {
                  m_setNums[ii] = m_uvSetNames.length();
                  m_uvSetNames.append(nurbsDefaultUV);
                  m_mayaType[ii] = kUvSet;
                  continue;
          }
          else if (comparisonString == "normal") {
                  m_setNums[ii] = 0; 
                  m_mayaType[ii] = kNormal;
                  continue;
          }
          else if (comparisonString == "tangent") {
                  m_setNums[ii] = 0; 
                  m_mayaType[ii] = kTangent;
                  continue;
          }
          
          
          
          else if (comparisonString == "binormal") {
                  m_setNums[ii] = 0; 
                  m_mayaType[ii] = kBinormal;
                  continue;
          }
          else if (comparisonString == "") {
                  m_setNums[ii] = -1;
                  m_mayaType[ii] = kNonMaya;
                  continue;
          }
          else {
                  
                  bool matchUVSet = false;
                  unsigned int numNames = uvSetNames.length();
                  if (numNames)
                  {
                          unsigned int jj = 0;
                          for (jj=0; jj<numNames; jj++) {
                                  if (comparisonString == uvSetNames[jj])
                                  {
                                          
                                          m_setNums[ii] = m_uvSetNames.length();
                                          m_uvSetNames.append( uvSetNames[jj] );
                                          m_mayaType[ii] = kUvSet;
                                          matchUVSet = true;
                                          break;
                                  }
                          }
                  }
                  
                  if (!matchUVSet)
                  {
                          numNames = colorSetNames.length();
                          if (numNames)
                          {
                                  unsigned int jj = 0;
                                  for (jj=0; jj<numNames ; jj++) {
                                          if (comparisonString == colorSetNames[jj])
                                          {
                                                  
                                                  m_setNums[ii] = m_colorSetNames.length();
                                                  m_colorSetNames.append( colorSetNames[jj] );
                                                  m_mayaType[ii] = kColorSet;
                                                  break;
                                          }
                                  }
                          }
                  }
          }
  }
  
  
  
  
  ii = 0;
  for (; ii<2; ii++) 
  {
          m_colorSetNums[ii] = -1;
          m_colorMayaType[ii] = kNonMaya;
  }
  ii = 0;
  for (; ii<2; ii++) 
  {
          MStringArray splitStrings;    
          MString comparisonString = m_nakedColorSets[ii];
          if ((MStatus::kSuccess == comparisonString.split(_splitChar, splitStrings)) &&
                  splitStrings.length() > 1)
          {
                  comparisonString = splitStrings[0];
          }
          if (comparisonString == "normal") {
                  m_colorSetNums[ii] = 0; 
                  m_colorMayaType[ii] = kNormal;
                  continue;
          }
          else if (comparisonString == "tangent") {
                  m_colorSetNums[ii] = 0; 
                  m_colorMayaType[ii] = kTangent;
                  continue;
          }
          
          
          
          else if (comparisonString == "binormal") {
                  m_colorSetNums[ii] = 0; 
                  m_colorMayaType[ii] = kBinormal;
                  continue;
          }
          else if (comparisonString == "") {
                  m_colorSetNums[ii] = -1;
                  m_colorMayaType[ii] = kNonMaya;
                  continue;
          }
          else {
                  
                  
                  
                  bool matchUVSet = false;
                  
                  unsigned int numNames = colorSetNames.length();
                  if (numNames)
                  {
                          unsigned int jj = 0;
                          for (jj=0; jj<numNames ; jj++) {
                                  if (comparisonString == colorSetNames[jj])
                                  {
                                          
                                          m_colorSetNums[ii] = m_colorSetNames.length();
                                          m_colorSetNames.append( colorSetNames[jj] );
                                          m_colorMayaType[ii] = kColorSet;
                                          matchUVSet = true;
                                          break;
                                  }
                          }
                  }
#ifdef _INTERACTIVE_SHADING_WORKS_FOR_ROUTING_TEXCOORDS_TO_COLOUR
                  
                  
                  numNames = uvSetNames.length();
                  if (numNames)
                  {
                          unsigned int jj = 0;
                          for (jj=0; jj<numNames; jj++) {
                                  if (comparisonString == uvSetNames[jj])
                                  {
                                          
                                          m_colorSetNums[ii] = m_uvSetNames.length();
                                          m_uvSetNames.append( uvSetNames[jj] );
                                          m_colorMayaType[ii] = kUvSet;
                                          break;
                                  }
                          }
                  }
#endif
          }
  }
  
  
  for (std::vector<attributeAttrib>::iterator it = m_attributeAttribList.begin(); 
          it<m_attributeAttribList.end(); it++) 
  {
          MStringArray splitStrings;    
          MString comparisonString( it->setName );
          if ((MStatus::kSuccess == comparisonString.split(_splitChar, splitStrings)) &&
                   splitStrings.length() > 1)
          {
                  comparisonString = splitStrings[0];
          }
          if (comparisonString == "normal") {
                  it->mtype = kNormal;
                  it->set = 0;
                  continue;
          }
          else if (comparisonString == "tangent") {
                  it->mtype = kTangent;
                  it->set = 0;
                  continue;
          }
          else if (comparisonString == "binormal") {
                  it->mtype = kBinormal;
                  it->set = 0;
                  continue;
          }
          else if (comparisonString == "") {
                  it->set = -1;
                  continue;
          }
          else {
                  
                  bool matchUVSet = false;
                  unsigned int numNames = uvSetNames.length();
                  if (numNames)
                  {
                          unsigned int jj = 0;
                          for (jj=0; jj<numNames; jj++) 
                          {
                                  
                                  if (comparisonString == uvSetNames[jj]) 
                                  {
                                          it->set = m_uvSetNames.length();
                                          m_uvSetNames.append( uvSetNames[jj] );
                                          it->mtype = kUvSet;
                                          matchUVSet = true;
                                          break;
                                  }
                          }
                  }
                  
                  if (!matchUVSet)
                  {
                          numNames = colorSetNames.length();
                          if (numNames)
                          {
                                  unsigned int jj = 0;
                                  for (jj=0; jj<numNames ; jj++) {
                                          if (m_nakedTexSets[ii] == colorSetNames[jj])
                                          {
                                                  
                                                  m_colorSetNames.append( colorSetNames[jj] );
                                                  it->set = m_colorSetNames.length();
                                                  it->mtype = kColorSet;
                                                  break;
                                          }
                                  }
                          }
                  }
          }
  }
  
  
  
  
  unsigned int numUVSets = uvSetNames.length();
  if (numUVSets)
  {
          for (ii=0; ii<8; ii++) 
          {
                  if (m_mayaType[ii] == kTangent || m_mayaType[ii] == kBinormal)
                  {
                          MStringArray splitStrings;
                          MString origString( m_nakedTexSets[ii] );
                          
                                
                          if ((MStatus::kSuccess == origString.split(_splitChar, splitStrings)) &&
                                  splitStrings.length() > 1)
                          {
                                  
                                  
                                        
                                  unsigned int jj = 0;
                                  for (jj=0; jj<numUVSets; jj++)
                                  {
                                          if (uvSetNames[jj] == splitStrings[1])
                                          {
                                                  int foundSet = -1;
                                                  for (unsigned int kk=0; kk<m_uvSetNames.length(); kk++)
                                                  {
                                                          if (splitStrings[1] == m_uvSetNames[kk])
                                                          {
                                                                  foundSet = kk;
                                                                  break;
                                                          }
                                                  }
                                                  if (foundSet > 0)
                                                  {
                                                          
                                                          m_setNums[ii] = foundSet;
                                                  }
                                                  else
                                                  {
                                                          
                                                          
                                                          m_setNums[ii] = m_uvSetNames.length();
                                                          m_uvSetNames.append( splitStrings[1] );
                                                  }
                                                  
                                                        
                                                  break;
                                          }
                                  }
                          }
                  }
          }
  }
  
  
  
  if (numUVSets)
  {
          for (ii=0; ii<2; ii++) 
          {
                  if (m_colorMayaType[ii] == kTangent || m_colorMayaType[ii] == kBinormal)
                  {
                          MStringArray splitStrings;
                          MString origString( m_nakedColorSets[ii] );
                          
                                
                          if ((MStatus::kSuccess == origString.split(_splitChar, splitStrings)) &&
                                  splitStrings.length() > 1)
                          {
                                  
                                  unsigned int jj = 0;
                                  for (jj=0; jj<numUVSets; jj++)
                                  {
                                          if (uvSetNames[jj] == splitStrings[1])
                                          {
                                                  int foundSet = -1;
                                                  for (unsigned int kk=0; kk<m_uvSetNames.length(); kk++)
                                                  {
                                                          if (splitStrings[1] == m_uvSetNames[kk])
                                                          {
                                                                  foundSet = kk;
                                                                  break;
                                                          }
                                                  }
                                                  if (foundSet > 0)
                                                  {
                                                          
                                                          m_colorSetNums[ii] = foundSet;
                                                  }
                                                  else
                                                  {
                                                          
                                                          
                                                          m_colorSetNums[ii] = m_uvSetNames.length();
                                                          m_uvSetNames.append( splitStrings[1] );
                                                  }
                                                  
                                                        
                                                  break;
                                          }
                                  }
                          }
                  }
          }
  }
  
  
  
  if (numUVSets)
  {
          for (std::vector<attributeAttrib>::iterator it2 = m_attributeAttribList.begin(); 
                  it2<m_attributeAttribList.end(); it2++)
          {
                  if (it2->mtype == kTangent || it2->mtype == kBinormal)
                  {
                          MStringArray splitStrings;
                          MString origString( it2->setName );
                          if ((MStatus::kSuccess == origString.split(_splitChar, splitStrings)) &&
                                  splitStrings.length() > 1)
                          {
                                  
                                  unsigned int jj = 0;
                                  for (jj=0; jj<numUVSets; jj++)
                                  {
                                          if (uvSetNames[jj] == splitStrings[1])
                                          {
                                                  int foundSet = -1;
                                                  for (unsigned int kk=0; kk<m_uvSetNames.length(); kk++)
                                                  {
                                                          if (splitStrings[1] == m_uvSetNames[kk])
                                                          {
                                                                  foundSet = kk;
                                                                  break;
                                                          }
                                                  }
                                                  if (foundSet > 0)
                                                  {
                                                          
                                                          it2->set = foundSet;
                                                  }
                                                  else
                                                  {
                                                          
                                                          
                                                          it2->set = m_uvSetNames.length();
                                                          m_uvSetNames.append( splitStrings[1] );
                                                  }
                                                  
                                                        
                                                  break;
                                          }             
                                  }
                          }
                  }
          }
  }
  m_numUVsets = m_uvSetNames.length();
  m_numColorSets = m_colorSetNames.length();
        m_maxSetNum = 0;
        for ( ii = 0; ii<8; ii++) 
                if( m_mayaType[ii] != kNonMaya)
                        m_maxSetNum = ii + 1;
  m_parsedUserAttribList = true;
}
#else // if MAYA_7
void glslShaderNode::parseUserAttributeList()
{
  if (m_parsedUserAttribList)
    return;
  
  
  
  m_numUVsets = 0;
  m_numColorSets = 0;
  m_uvSetNames.clear();
  m_colorSetNames.clear();
  
  
  
  
  m_uvSetNames.append("map1");
  int ii = 0;
  for (; ii<8; ii++) 
  {
    m_setNums[ii] = -1;
    m_mayaType[ii] = kNonMaya;
  }
  ii = 0;
  for (; ii<8; ii++) 
  {
    
    if ( m_nakedTexSets[ii] == "map1") 
    {
      m_setNums[ii] = 0;
      m_mayaType[ii] = kUvSet;
      continue;
    }
    else if (m_nakedTexSets[ii] == "normal") {
      m_setNums[ii] = 0; 
      m_mayaType[ii] = kNormal;
      continue;
    }
    else if (m_nakedTexSets[ii] == "tangent") {
      m_setNums[ii] = 0; 
      m_mayaType[ii] = kTangent;
      continue;
    }
    
    
    
    else if (m_nakedTexSets[ii] == "binormal") {
      m_setNums[ii] = 0; 
      m_mayaType[ii] = kBinormal;
      continue;
    }
    else if (m_nakedTexSets[ii] == "") {
      m_setNums[ii] = -1;
      m_mayaType[ii] = kNonMaya;
      continue;
    }
    else {
      
      m_setNums[ii] = m_uvSetNames.length();
      m_uvSetNames.append( m_nakedTexSets[ii] );
      m_mayaType[ii] = kUvSet;
    }
  }
  
  unsigned int setNum = 0;
  for (std::vector<attributeAttrib>::iterator it = m_attributeAttribList.begin(); it<m_attributeAttribList.end(); it++) {
    if (it->setName == "normal") {
      it->mtype = kNormal;
      it->set = 0;
      continue;
    }
    else if (it->setName == "tangent") {
      it->mtype = kTangent;
      it->set = 0;
      continue;
    }
    else if (it->setName == "binormal") {
      it->mtype = kBinormal;
      it->set = 0;
      continue;
    }
    else if (it->setName == "") {
      it->set = -1;
      continue;
    }
    else {
      
      it->set = m_uvSetNames.length();
      m_uvSetNames.append( it->setName );
      it->mtype = kUvSet;
     
    }
  }
  m_numUVsets = m_uvSetNames.length();
  m_numColorSets = m_colorSetNames.length();
        m_maxSetNum = 0;
        for ( ii = 0; ii<8; ii++) 
                if( m_mayaType[ii] != kNonMaya)
                        m_maxSetNum = ii + 1;
  m_parsedUserAttribList = true;
}
#endif // if MAYA_7
int     glslShaderNode::getColorSetNames(MStringArray& names)
{
        if (!m_parsedUserAttribList)
                parseUserAttributeList();
        names = m_colorSetNames;
        return m_numColorSets;
}
int glslShaderNode::getTexCoordSetNames( MStringArray &names) 
{       
        if (!m_parsedUserAttribList)
                parseUserAttributeList();
        names = m_uvSetNames;
        return m_numUVsets;
}
int glslShaderNode::normalsPerVertex() {
  
  m_numNormals = 3;
  return m_numNormals;
}
void glslShaderNode::configureUniformAttrib( MString &name, int pNum, shader::DataType type, shader::Semantic sm, float *defVal,
                                            MFnDependencyNode &dn, MDGModifier &mod) {
  uniformAttrib ua;
  MFnNumericAttribute nAttrib;
  MFnTypedAttribute tAttrib;
  MStatus stat;
  
  ua.name = name;
  ua.pNum = pNum;
  ua.dirty = true;
  ua.type = type;
  ua.attrib = MObject::kNullObj;
  ua.attrib2 = MObject::kNullObj;
  
  
  
  
  
  float min=0.0f, max=0.0f;
  bool color = shader::isColor(sm);
  bool clamped = shader::isClamped(sm);
  shader::getLimits( sm, min, max);
  switch (ua.type) {
    case shader::dtFloat:
      if ( !dn.hasAttribute( name )) {
        ua.attrib = nAttrib.create( name, name, MFnNumericData::kFloat);
        if (clamped) {
          nAttrib.setMin(min);
          nAttrib.setMax(max);
        }
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
        nAttrib.setInternal(true);
#endif
        nAttrib.setKeyable( true );
        if (defVal)
          nAttrib.setDefault( defVal[0]);
        else
          nAttrib.setDefault( -1.0 );
                stat = mod.addAttribute( thisMObject(), ua.attrib );
      }
      else {
        
        ua.attrib = dn.attribute(name, &stat);
      }
      break;
    case shader::dtVec2:
      if ( !dn.hasAttribute( name )) {
                ua.attrib = nAttrib.create( name, name, MFnNumericData::k2Float);
        if (clamped) {
          nAttrib.setMin( min, min);
          nAttrib.setMax( max, max);
        }
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
        nAttrib.setInternal(true);
#endif
        nAttrib.setKeyable( true );
        if (defVal)
          nAttrib.setDefault( defVal[0], defVal[1] );
        else
          nAttrib.setDefault( -1.0, -1.0 );
        stat = mod.addAttribute( thisMObject(), ua.attrib );
      }
      else {
        
        ua.attrib = dn.attribute(name, &stat);
      }
      break;
    case shader::dtVec3:
      if ( !dn.hasAttribute( name )) {
        if (color) {
          ua.attrib = nAttrib.createColor( name, name);
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
          nAttrib.setInternal(true);
#endif
                  nAttrib.setKeyable( true );
          if (defVal)
            nAttrib.setDefault( defVal[0], defVal[1], defVal[2] );
        }
        else {
                ua.attrib = nAttrib.create( name, name, MFnNumericData::k3Float);
          if (clamped) {
            nAttrib.setMin( min, min, min);
            nAttrib.setMax( max, max, max);
          }
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
        nAttrib.setInternal(true);
#endif
        nAttrib.setKeyable( true );
        if (defVal)
          nAttrib.setDefault( defVal[0], defVal[1], defVal[2] );
        else
          nAttrib.setDefault( -1.0, -1.0, -1.0 );
        }
        stat = mod.addAttribute( thisMObject(), ua.attrib );
      }
      else {
        
        ua.attrib = dn.attribute(name, &stat);
      }
      break;
    case shader::dtVec4:
      if ( !dn.hasAttribute( name )) {
        if (color) {
          ua.attrib = nAttrib.createColor( name, name);
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
          nAttrib.setInternal(true);
#endif
                  nAttrib.setKeyable( true );
          if (defVal)
            nAttrib.setDefault( defVal[0], defVal[1], defVal[2] );
          stat = mod.addAttribute( thisMObject(), ua.attrib );
          ua.attrib2 = nAttrib.create( name + "Alpha", name + "Alpha", MFnNumericData::kFloat);
          if (clamped) {
            nAttrib.setMin( 0.0f);
            nAttrib.setMax( 1.0f);
          }
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
          nAttrib.setInternal(true);
#endif
                  nAttrib.setKeyable( true );
          if (defVal)
            nAttrib.setDefault( defVal[3]);
          else
            nAttrib.setDefault( 1.0 );
          stat = mod.addAttribute( thisMObject(), ua.attrib2 );
        }
        else {
                ua.attrib = nAttrib.create( name, name, MFnNumericData::k3Float);
          if (clamped) {
            nAttrib.setMin( min, min, min);
            nAttrib.setMax( max, max, max);
          }
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
        nAttrib.setInternal(true);
#endif
        nAttrib.setKeyable( true );
        if (defVal)
          nAttrib.setDefault( defVal[0], defVal[1], defVal[2] );
        else
          nAttrib.setDefault( -1.0, -1.0, -1.0 );
        stat = mod.addAttribute( thisMObject(), ua.attrib );
        ua.attrib2 = nAttrib.create( name + "W", name + "W", MFnNumericData::kFloat);
          if (clamped) {
            nAttrib.setMin( min);
            nAttrib.setMax( max);
          }
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
        nAttrib.setInternal(true);
#endif
        nAttrib.setKeyable( true );
        if (defVal)
          nAttrib.setDefault( defVal[3]);
        else
          nAttrib.setDefault( -1.0 );
        stat = mod.addAttribute( thisMObject(), ua.attrib2 );
      }
      }
      else {
        
        ua.attrib = dn.attribute(name, &stat);
        ua.attrib2 = dn.attribute( name + "W", &stat);
      }
      break;
    case shader::dtBool:
      if ( !dn.hasAttribute( name )) {
                ua.attrib = nAttrib.create( name, name, MFnNumericData::kBoolean);
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
        nAttrib.setInternal(true);
#endif
        nAttrib.setKeyable( true );
        nAttrib.setDefault( true );  
        stat = mod.addAttribute( thisMObject(), ua.attrib );
      }
      else {
        
        ua.attrib = dn.attribute(name, &stat);
      }
      break;
    case shader::dtInt:
      if ( !dn.hasAttribute( name )) {
                ua.attrib = nAttrib.create( name, name, MFnNumericData::kInt);
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
        nAttrib.setInternal(true);
#endif
        nAttrib.setKeyable( true );
        if (defVal)
          nAttrib.setDefault( (int)defVal[0]);
        else
          nAttrib.setDefault( -1 );
        stat = mod.addAttribute( thisMObject(), ua.attrib );
      }
      else {
        
        ua.attrib = dn.attribute(name, &stat);
      }
      break;
    case shader::dtIVec2:
      if ( !dn.hasAttribute( name )) {
                ua.attrib = nAttrib.create( name, name, MFnNumericData::k2Int);
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
        nAttrib.setInternal(true);
#endif
        nAttrib.setKeyable( true );
        nAttrib.setDefault( -1, -1 );
        stat = mod.addAttribute( thisMObject(), ua.attrib );
      }
      else {
        
        ua.attrib = dn.attribute(name, &stat);
      }
      break;
    case shader::dtIVec3:
      if ( !dn.hasAttribute( name )) {
                ua.attrib = nAttrib.create( name, name, MFnNumericData::k3Int);
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
        nAttrib.setInternal(true);
#endif
        nAttrib.setKeyable( true );
        nAttrib.setDefault( -1, -1, -1 );
        stat = mod.addAttribute( thisMObject(), ua.attrib );
      }
      else {
        
        ua.attrib = dn.attribute(name, &stat);
      }
      break;
    case shader::dtMat4:
      if ( !dn.hasAttribute( name )) {
        MFnMatrixAttribute mAttrib;
        ua.attrib = mAttrib.create( name, name, MFnMatrixAttribute::kFloat);
#ifdef _CAN_ANIMATE_INTERNAL_DYNAMIC_ATTRIBS
        mAttrib.setInternal(true);
#endif
                mAttrib.setKeyable( true );
        
        stat = mod.addAttribute( thisMObject(), ua.attrib );
      }
      else {
        
        ua.attrib = dn.attribute(name, &stat);
      }
      break;
    case shader::dtBVec2:
    case shader::dtBVec3:
    case shader::dtIVec4:
    case shader::dtBVec4:
    case shader::dtMat2:
    case shader::dtMat3:
      
      return;
    default:
      MGlobal::displayWarning(MString("Unknown uniform parameter type for: ") + name);
  };
  if (stat != MStatus::kSuccess) {
        MStatus strStat;
        MString error = MStringResource::getString(rGLSLShaderNodeFailedAddAttribute, strStat);
        error.format(error, name);
        MGlobal::displayError(error);
    MGlobal::displayError(stat.errorString());
  }
  m_uniformAttribList.push_back(ua); 
}
void glslShaderNode::configureAttribs() {
  MDGModifier mod;
  {
          for (std::vector<uniformAttrib>::iterator it=m_uniformAttribList.begin(); it<m_uniformAttribList.end(); it++) {
                  it->pNum = -1; 
          }
  }
  {
          for (std::vector<samplerAttrib>::iterator it=m_samplerAttribList.begin(); it<m_samplerAttribList.end(); it++) {
                  it->pNum = -1; 
          }
  }
  {
          for (std::vector<attributeAttrib>::iterator it=m_attributeAttribList.begin(); it<m_attributeAttribList.end(); it++) {
                  it->pNum = -1; 
          }
  }
  
  m_boundUniformList.clear();
  MFnDependencyNode dn(thisMObject());
  int ii;
  if (m_shader && m_shader->valid()) {
    
    for (ii=0; ii<m_shader->uniformCount(); ii++) {
      MString name(m_shader->uniformName(ii));
      
      if ( shader::isBound(m_shader->uniformSemantic(ii))) {
        
        
        boundUniform bu;
        bu.name = name;
        bu.usage = m_shader->uniformSemantic(ii);
        bu.pNum = ii;
        m_boundUniformList.push_back(bu);
      }
      else {
        
        
        std::vector<uniformAttrib>::iterator it=m_uniformAttribList.begin();
        
        while (it < m_uniformAttribList.end()) {
          if (it->name == name)
            break; 
          it++; 
        }
        
        if (it !=m_uniformAttribList.end()) {
          
          if ( it->type == m_shader->uniformType(ii)) {
            
            it->pNum = ii;
            it->dirty = true;
            
            continue;
          }
          else {
            
            mod.removeAttribute( thisMObject(), it->attrib);
            it->attrib = MObject::kNullObj;
            
            if (it->attrib2 != MObject::kNullObj) {
              mod.removeAttribute( thisMObject(), it->attrib2);
              it->attrib2 = MObject::kNullObj;
            }
          }
        }
        
        
        configureUniformAttrib( name, ii, m_shader->uniformType(ii), m_shader->uniformSemantic(ii),
                                m_shader->uniformDefault(ii), dn, mod);
          
        GL_CHECK;
      }
    }
    
    for (ii=0; ii<m_shader->samplerCount(); ii++) {
      MString name(m_shader->samplerName(ii));
      
      std::vector<samplerAttrib>::iterator it=m_samplerAttribList.begin();
      
      while (it < m_samplerAttribList.end()) {
        if (it->name == name)
          break; 
        
        it++; 
      }
      if (it !=m_samplerAttribList.end()) {
        
        it->pNum = ii;
        it->dirty = false;
        m_shader->updateSampler( ii, it->texName);
      }
      else {
        
        samplerAttrib sa;
        MFnNumericAttribute nAttrib;
        MFnEnumAttribute eAttrib;
        MStatus stat;
        sa.name = name;
        sa.pNum = ii;
        sa.dirty = true;
        sa.texName = 0;
        sa.minFilter = GL_LINEAR;
        sa.magFilter = GL_LINEAR;
        sa.wrapMode = GL_REPEAT;
        sa.maxAniso = 1.0f;
        if ( !dn.hasAttribute( name )) {
          sa.attrib = nAttrib.createColor( name, name);
          nAttrib.setInternal(true);
          stat = mod.addAttribute( thisMObject(), sa.attrib);
        }
        else {
          sa.attrib = dn.attribute(name, &stat);
        }
        if (stat != MStatus::kSuccess) {
                        MStatus strStat;
                        MString error = MStringResource::getString(rGLSLShaderNodeFailedAddAttribute, strStat);
                        error.format(error, name);
                        MGlobal::displayError(error);
                MGlobal::displayError(stat.errorString());
        }
        if ( !dn.hasAttribute( name +"MinFilter")) {
          sa.minFilterAttrib = eAttrib.create( name+"MinFilter", name+"MinFilter");
          eAttrib.addField( "Nearest", 0);
          eAttrib.addField( "Linear", 1);
          eAttrib.addField( "Linear, Mipmaped", 2);
          eAttrib.addField( "Trilinear", 3);
          eAttrib.setDefault( 1);
          eAttrib.setInternal(true);
          
          stat = mod.addAttribute( thisMObject(), sa.minFilterAttrib);
        }
        else {
          sa.minFilterAttrib = dn.attribute(name+"MinFilter", &stat);
          
                  MPlug plug(thisMObject(), sa.minFilterAttrib);
          short val;
          plug.getValue(val);
          switch (val) {
            case 0:
              sa.minFilter = GL_NEAREST;
              break;
            case 1:
              sa.minFilter = GL_LINEAR;
              break;
            case 2:
              sa.minFilter = GL_LINEAR_MIPMAP_NEAREST;
              break;
            case 3:
              sa.minFilter = GL_LINEAR_MIPMAP_LINEAR;
              break;
            default:
              
              sa.minFilter = GL_LINEAR;
              break;
          };
        }
        if (stat != MStatus::kSuccess) {
                        MStatus strStat;
                        MString error = MStringResource::getString(rGLSLShaderNodeFailedAddAttribute, strStat);
                        error.format(error, name + "MinFilter");
                        MGlobal::displayError(error);
                        MGlobal::displayError(stat.errorString());
        }
        if ( !dn.hasAttribute( name +"MagFilter")) {
          sa.magFilterAttrib = eAttrib.create( name+"MagFilter", name+"MagFilter");
          eAttrib.addField( "Nearest", 0);
          eAttrib.addField( "Linear", 1);
          eAttrib.setDefault( 1);
          eAttrib.setInternal(true);
          
          stat = mod.addAttribute( thisMObject(), sa.magFilterAttrib);
        }
        else {
          sa.magFilterAttrib = dn.attribute(name+"MagFilter", &stat);
          
          MPlug plug(thisMObject(), sa.magFilterAttrib);
          short val;
          plug.getValue(val);
          switch (val) {
            case 0:
              sa.magFilter = GL_NEAREST;
              break;
            case 1:
              sa.magFilter = GL_LINEAR;
              break;
            default:
              
              sa.magFilter = GL_LINEAR;
              break;
          };
        }
        if (stat != MStatus::kSuccess) {
                        MStatus strStat;
                        MString error = MStringResource::getString(rGLSLShaderNodeFailedAddAttribute, strStat);
                        error.format(error, name + "MagFilter");
                        MGlobal::displayError(error);
                        MGlobal::displayError(stat.errorString());
        }
        if ( !dn.hasAttribute( name+"Wrap" )) {
          sa.wrapAttrib = eAttrib.create( name+"Wrap", name+"Wrap");
          eAttrib.addField( "Repeat", 0);
          eAttrib.addField( "Clamp", 1);
          eAttrib.addField( "Mirror", 2);
          eAttrib.setDefault( 0);
          eAttrib.setInternal(true);
          
          stat = mod.addAttribute( thisMObject(), sa.wrapAttrib);
        }
        else {
          sa.wrapAttrib = dn.attribute(name+"Wrap", &stat);
          
                  MPlug plug(thisMObject(), sa.wrapAttrib);
          short val;
          plug.getValue(val);
          switch (val) {
            case 0:
              sa.wrapMode = GL_REPEAT;
              break;
            case 1:
              sa.wrapMode = GL_CLAMP_TO_EDGE;
              break;
            case 2:
              sa.wrapMode = GL_MIRRORED_REPEAT;
              break;
            default:
              
              sa.wrapMode = GL_REPEAT;
              break;
          };
        }
        if (stat != MStatus::kSuccess) {
                        MStatus strStat;
                        MString error = MStringResource::getString(rGLSLShaderNodeFailedAddAttribute, strStat);
                        error.format(error, name + "Wrap");
                        MGlobal::displayError(error);
                        MGlobal::displayError(stat.errorString());
        }
        if ( !dn.hasAttribute( name+"MaxAniso" )) {
          sa.anisoAttrib = nAttrib.create( name+"MaxAniso", name+"MaxAniso", MFnNumericData::kFloat, 1.0);
          
          nAttrib.setInternal(true);
          nAttrib.setMin( 1.0);
          nAttrib.setMax( 16.0);
          stat = mod.addAttribute( thisMObject(), sa.anisoAttrib);
        }
        else {
          sa.anisoAttrib = dn.attribute(name+"MaxAniso", &stat);
          
                  MPlug plug(thisMObject(), sa.anisoAttrib);
          float val;
          plug.getValue(val);
          sa.maxAniso = val;
        }
        if (stat != MStatus::kSuccess) {
                        MStatus strStat;
                        MString error = MStringResource::getString(rGLSLShaderNodeFailedAddAttribute, strStat);
                        error.format(error, name + "MaxAniso");
                        MGlobal::displayError(error);
                        MGlobal::displayError(stat.errorString());
        }
        m_samplerAttribList.push_back(sa);
        GL_CHECK;
      }
    }
    
    for (ii=0; ii<m_shader->attributeCount(); ii++) {
      MString name(m_shader->attributeName(ii));
      
      std::vector<attributeAttrib>::iterator it=m_attributeAttribList.begin();
      
      while (it < m_attributeAttribList.end()) {
        if (it->name == name)
          break; 
        
        it++; 
      }
      if (it !=m_attributeAttribList.end()) {
        
        it->pNum = ii;
        it->handle = m_shader->attributeHandle( ii);
        it->set = -1;
      }
      else {
        MFnTypedAttribute tAttrib;
        attributeAttrib aa;
        MStatus stat;
        aa.name = name;
        aa.setName = name;
        aa.pNum = ii;
        aa.handle = m_shader->attributeHandle(ii);
        aa.set = -1; 
                aa.mtype = kNonMaya;
        if ( !dn.hasAttribute( name )) {
          aa.attrib = tAttrib.create( name, name, MFnData::kString);
          
          tAttrib.setInternal(true);
          tAttrib.setKeyable( true );
          stat = mod.addAttribute( thisMObject(), aa.attrib);
        }
        else {
          aa.attrib = dn.attribute(name, &stat);
        }
        m_attributeAttribList.push_back(aa);
      }
    }
  }
  for (ii=0; ii< (int)m_uniformAttribList.size(); ) {
    if (m_uniformAttribList[ii].pNum == -1) {
      
      if (m_uniformAttribList[ii].attrib != MObject::kNullObj ) {
        mod.removeAttribute( thisMObject(), m_uniformAttribList[ii].attrib);
        m_uniformAttribList[ii].attrib = MObject::kNullObj;
      }
      if ( m_uniformAttribList[ii].attrib2 != MObject::kNullObj ) {
        mod.removeAttribute( thisMObject(), m_uniformAttribList[ii].attrib2);
        m_uniformAttribList[ii].attrib2 = MObject::kNullObj;
      }
      
      m_uniformAttribList.erase(m_uniformAttribList.begin()+ii);
    }
    else {
      
      ii++;
    }
  }
  for (ii=0; ii<(int)m_samplerAttribList.size(); ) {
    MStatus stat, stat2, stat3, stat4, stat5;
    if (m_samplerAttribList[ii].pNum == -1) {
      
      
      if ( m_samplerAttribList[ii].attrib != MObject::kNullObj )
        stat = mod.removeAttribute( thisMObject(), m_samplerAttribList[ii].attrib);
      if ( m_samplerAttribList[ii].magFilterAttrib != MObject::kNullObj )
        stat2 = mod.removeAttribute( thisMObject(), m_samplerAttribList[ii].magFilterAttrib);
      if ( m_samplerAttribList[ii].minFilterAttrib != MObject::kNullObj )
        stat3 = mod.removeAttribute( thisMObject(), m_samplerAttribList[ii].minFilterAttrib);
      if ( m_samplerAttribList[ii].wrapAttrib != MObject::kNullObj )
        stat4 = mod.removeAttribute( thisMObject(), m_samplerAttribList[ii].wrapAttrib);
      if ( m_samplerAttribList[ii].anisoAttrib != MObject::kNullObj )
        stat5 = mod.removeAttribute( thisMObject(), m_samplerAttribList[ii].anisoAttrib);
      if (stat != MStatus::kSuccess) {
                        MStatus strStat;
                        MString error = MStringResource::getString(rGLSLShaderNodeFailedDestroyAttribute, strStat);
                        error.format(error, m_samplerAttribList[ii].name);
                        MGlobal::displayError(error);
                        MGlobal::displayError(MString("  ") + stat.errorString());
      }
      
      ResourceManager::destroyTexture( m_samplerAttribList[ii].texName);
      
      m_samplerAttribList[ii].attrib = MObject::kNullObj;
      m_samplerAttribList.erase(m_samplerAttribList.begin()+ii);
    }
    else {
      
      ii++;
    }
  }
  for (ii=0; ii<(int)m_attributeAttribList.size(); ) {
    MStatus stat;
    if (m_attributeAttribList[ii].pNum == -1) {
      
      
      stat = mod.removeAttribute( thisMObject(), m_attributeAttribList[ii].attrib);
      if (stat != MStatus::kSuccess) {
                        MStatus strStat;
                        MString error = MStringResource::getString(rGLSLShaderNodeFailedDestroyAttribute, strStat);
                        error.format(error, m_attributeAttribList[ii].name);
                        MGlobal::displayError(MString("  ") + stat.errorString());
      }
      m_attributeAttribList[ii].attrib = MObject::kNullObj;
      m_attributeAttribList.erase(m_attributeAttribList.begin()+ii);
    }
    else {
      
      ii++;
    }
  }
  GL_CHECK;
  mod.doIt();
}
bool glslShaderNode::locateFile( const MString &name, MString &path) {
  MString proj;
  struct stat fstats;
  MString temp;
  
  
  MGlobal::executeCommand( MString("workspace -q -rd;"), proj);
  
  
  
  
  
  if ( stat(name.asChar(), &fstats) == 0){
    
    path = name;
    return true;
  }
  
  
  char buffer[MAX_PATH_LENGTH];
  if ( getcwd( buffer, MAX_PATH_LENGTH ) != NULL)
  {
          temp = MString(buffer) + "\\" + name;
          if ( stat(temp.asChar(), &fstats) == 0){
                  
                  path = temp;
                  return true;
          }
  }
  temp = proj + "shaders/" + name;
  if ( stat(temp.asChar(), &fstats) == 0){
    
    path = temp;
    return true;
  }
 
  temp = proj + name;
  if ( stat(temp.asChar(), &fstats) == 0){
    
    path = temp;
    return true;
  }
  return false;
}
MStatus glslShaderNode::renderSwatchImage( MImage & outImage )
{
        MStatus status = MStatus::kFailure;
        
        MHardwareRenderer *pRenderer = MHardwareRenderer::theRenderer();
        if (pRenderer)
        {
                const MString& backEndStr = pRenderer->backEndString();
                
                
                unsigned int* pIndexing = 0;
                unsigned int  numberOfData = 0;
                unsigned int  indexCount = 0;
                MHardwareRenderer::GeometricShape gshape = MHardwareRenderer::kDefaultSphere;
                MGeometryData* pGeomData =
                        pRenderer->referenceDefaultGeometry( gshape, numberOfData, pIndexing, indexCount );
                if( !pGeomData )
                {
                        return MStatus::kFailure;
                }
                
                
                
                unsigned int width, height;
                outImage.getSize( width, height );
                unsigned int origWidth = width;
                unsigned int origHeight = height;
                MStatus status2 = pRenderer->makeSwatchContextCurrent( backEndStr, width, height );
                if( status2 != MS::kSuccess )
                {
                        pRenderer->dereferenceGeometry( pGeomData, numberOfData );
            return status2;
                }
                
                
                {
                        float light_pos[4];
                        pRenderer->getSwatchLightDirection( light_pos[0], light_pos[1], light_pos[2], light_pos[3] );
                        glMatrixMode(GL_MODELVIEW);
                        glPushMatrix();
                        glLoadIdentity();
                        glLightfv(GL_LIGHT0, GL_POSITION, light_pos );
                        glPopMatrix();
                        float light_ambt[4] = {1.0f, 1.0f, 1.0f, 1.0};
                        float light_diff[4] = {1.0f, 1.0f, 1.0f, 1.0};
                        float light_spec[4] = {1.0f, 1.0f, 1.0f, 1.0};
                        glLightfv( GL_LIGHT0, GL_AMBIENT,  light_ambt );
                        glLightfv( GL_LIGHT0, GL_DIFFUSE,  light_diff );
                        glLightfv( GL_LIGHT0, GL_SPECULAR, light_spec );
                        glEnable( GL_LIGHTING );
                        glEnable( GL_LIGHT0 );
            GL_CHECK;
                }
                
                
                {
                        
                        glMatrixMode(GL_PROJECTION);
                        glLoadIdentity();
                        double l, r, b, t, n, f;
                        pRenderer->getSwatchPerspectiveCameraSetting( l, r, b, t, n, f );
                        glFrustum( l, r, b, t, n, f );
                        glMatrixMode(GL_MODELVIEW);
                        glLoadIdentity();
                        float x, y, z, w;
                        pRenderer->getSwatchPerspectiveCameraTranslation( x, y, z, w );
                        glTranslatef( x, y, z );
            GL_CHECK;
                }
                
                
                float r, g, b, a;
                MHWShaderSwatchGenerator::getSwatchBackgroundColor( r, g, b, a );
                glClearColor( r, g, b, a );
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
                glShadeModel(GL_SMOOTH);
                glEnable(GL_DEPTH_TEST);
                glDepthFunc(GL_LEQUAL);
                glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
        GL_CHECK;
                
                
                
                MDagPath dummyPath;
                glBind( dummyPath );
                float *vertexData = (float *)( pGeomData[0].data() );
                float *normalData = (float *)( pGeomData[1].data() );
                float *uvData = (float *)( pGeomData[2].data() );
                float *tangentData = (float *)( pGeomData[3].data() );
                float *binormalData = (float *)( pGeomData[4].data() );
                unsigned int normalCount = 0;
                
                float ** normalArrays = new float * [3];
                if (normalData) 
                {
                        normalArrays[0] = normalData;
                        normalCount++;
                }
                else
                        normalArrays[0] = NULL;
                if (tangentData) 
                {
                        normalArrays[1] = tangentData;
                        normalCount++;
                }
                else
                        normalArrays[1] = NULL;
                if (binormalData)
                {
                        normalArrays[2] = binormalData;
                        normalCount++;
                }
                else
                        normalArrays[2] = NULL;
                
                unsigned int uvCount = 0;
                float ** texCoordArrays = new float * [1];
                if (uvData)
                {
                        texCoordArrays[0] = uvData;
                        uvCount = 1;
                }
                else
                        texCoordArrays[0] = NULL;
                m_setNums[0] = 0;
                m_setNums[1] = 0;
                m_setNums[2] = 0;
                m_setNums[3] = 0;
                m_setNums[4] = 0;
                m_setNums[5] = 0;
                m_setNums[6] = 0;
                m_setNums[7] = 0;
                m_mayaType[0] = kUvSet;
                m_mayaType[1] = kTangent;
                m_mayaType[2] = kBinormal;
                m_mayaType[3] = kUvSet;
                m_mayaType[4] = kUvSet;
                m_mayaType[5] = kUvSet;
                m_mayaType[6] = kUvSet;
                m_mayaType[7] = kUvSet;
                
                m_colorSetNums[0] = -1;
                m_colorSetNums[1] = -1;
                m_colorMayaType[0] = kColorSet;
                m_colorMayaType[1] = kColorSet;
                glGeometry( dummyPath,
                                        GL_TRIANGLES,
                                        false,
                                        indexCount,
                                        pIndexing,
                                        0, 
                                        NULL, 
                                        vertexData,
                                        normalCount,
                                        (const float **) normalArrays,
                                        0, 
                                        NULL, 
                                        uvCount,
                                        (const float **) texCoordArrays);
                glUnbind( dummyPath );
                glFinish();
                normalArrays[0] = NULL;
                normalArrays[1] = NULL;
                delete[] normalArrays;
                texCoordArrays[0] = NULL;
                delete[] texCoordArrays;
                
                
                pRenderer->readSwatchContextPixels( backEndStr, outImage );
                
                
                outImage.getSize( width, height );
                if (width != origWidth || height != origHeight)
                {
                        status = MStatus::kFailure;
                }
                else
                {
                        status = MStatus::kSuccess;
                }
        }
    GL_CHECK;
        return status;
}
bool glslShaderNode::printVertexShader( int pass) {
  if ( m_shader) {
    const char *shader = m_shader->getVertexShader( pass);
    if (shader) {
      MGlobal::displayInfo(shader);
      return true;
    }
  }
  return false;
}
bool glslShaderNode::printPixelShader( int pass) {
  if ( m_shader) {
    const char *shader = m_shader->getPixelShader( pass);
    if (shader) {
      MGlobal::displayInfo(shader);
      return true;
    }
  }
  return false;
}
glslShaderNode* glslShaderNode::findNodeByName(const MString &name) {
  for (std::vector<glslShaderNode*>::iterator it = sNodeList.begin(); it < sNodeList.end(); it++) {
    if ( (*it)->name() == name)
      return *it;
  }
  return NULL;
}