#ifndef CGFXSHADER_VERSION  
#define CGFXSHADER_VERSION  "4.4"
#endif
#include "cgfxShaderNode.h"
#include "cgfxFindImage.h"
#include <maya/MDagPath.h>
#include <maya/MDataBlock.h>
#include <maya/MDataHandle.h>
#include <maya/MEventMessage.h>
#include <maya/MFloatVector.h>
#include <maya/MFnMesh.h>
#include <maya/MFnStringArrayData.h>
#include <maya/MFnStringData.h>
#include <maya/MFnTypedAttribute.h>
#include <maya/MGlobal.h>
#include <maya/MPlug.h>
#include <maya/MPoint.h>
#include <maya/MVector.h>
#include <maya/MDGModifier.h>
#include <maya/MFileIO.h>
#include <maya/MNodeMessage.h>
#include <maya/MFileObject.h>
#if defined(_SWATCH_RENDERING_SUPPORTED_)
        
        #include <maya/MHardwareRenderer.h>
        #include <maya/MGeometryData.h>
        #include <maya/MHWShaderSwatchGenerator.h>
#endif
        #include <maya/MImage.h>
#include "nv_dds.h"
#ifdef _WIN32
#else
#       include <sys/timeb.h>
#       include <string.h>
#
#   define stricmp strcasecmp
#   define strnicmp strncasecmp
#endif
PFNGLCLIENTACTIVETEXTUREARBPROC glStateCache::glClientActiveTexture = 0;
PFNGLVERTEXATTRIBPOINTERARBPROC glStateCache::glVertexAttribPointer = 0;
PFNGLENABLEVERTEXATTRIBARRAYARBPROC glStateCache::glEnableVertexAttribArray = 0;
PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glStateCache::glDisableVertexAttribArray = 0;
PFNGLVERTEXATTRIB4FARBPROC glStateCache::glVertexAttrib4f = 0;
PFNGLSECONDARYCOLORPOINTEREXTPROC glStateCache::glSecondaryColorPointer = 0;
PFNGLSECONDARYCOLOR3FEXTPROC glStateCache::glSecondaryColor3f = 0;
PFNGLMULTITEXCOORD4FARBPROC glStateCache::glMultiTexCoord4fARB = 0;
int glStateCache::sMaxTextureUnits = 0;
glStateCache::glStateCache()
{ 
        reset(); 
}
glStateCache glStateCache::gInstance;
void glStateCache::activeTexture( int i) 
{ 
        if( i != fActiveTextureUnit) 
        { 
                fActiveTextureUnit = i; 
                if( glStateCache::glClientActiveTexture) 
                        glStateCache::glClientActiveTexture( GL_TEXTURE0_ARB + i );
                }
        }
void glStateCache::enableVertexAttrib( int i)
{
        if( !(fEnabledRegisters & (1 << (glRegister::kVertexAttrib + i)))) 
        { 
                if( glStateCache::glEnableVertexAttribArray) 
                        glStateCache::glEnableVertexAttribArray( i);
                fEnabledRegisters |= (1 << (glRegister::kVertexAttrib + i)); 
        } 
        fRequiredRegisters |= (1 << (glRegister::kVertexAttrib + i));
}
void glStateCache::flushState() 
{ 
        
        long redundantRegisters = fEnabledRegisters & ~fRequiredRegisters;
        
        
        if( redundantRegisters & (1 << glRegister::kPosition)) 
                glDisableClientState(GL_VERTEX_ARRAY); 
        if( redundantRegisters & (1 << glRegister::kNormal)) 
                glDisableClientState(GL_NORMAL_ARRAY); 
        if( redundantRegisters & (1 << glRegister::kColor)) 
                glDisableClientState(GL_COLOR_ARRAY); 
        if( redundantRegisters & (1 << glRegister::kSecondaryColor)) 
                glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT); 
        for( int i = glRegister::kTexCoord; i <= glRegister::kLastTexCoord; i++)
        {
                if( redundantRegisters & (1 << i)) 
                {
                        activeTexture( i - glRegister::kTexCoord); 
                        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
                }
        }
        for( int i = glRegister::kVertexAttrib; i <= glRegister::kLastVertexAttrib; i++)
        {
                if( redundantRegisters & (1 << i)) 
                {
                        if( glStateCache::glDisableVertexAttribArray) 
                                glStateCache::glDisableVertexAttribArray( i - glRegister::kVertexAttrib);
                }
        }
        fEnabledRegisters = fRequiredRegisters;
        fRequiredRegisters = 0;
}
#ifdef _WIN32
MTypeId     cgfxShaderNode::sId( 4084862000 );
#else
MTypeId     cgfxShaderNode::sId( 0xF37A0C30 );
#endif
CGcontext               cgfxShaderNode::sCgContext;
MObject     cgfxShaderNode::sShader;
MObject     cgfxShaderNode::sTechnique;
MObject                 cgfxShaderNode::sAttributeList;
MObject         cgfxShaderNode::sVertexAttributeList;
MObject     cgfxShaderNode::sVertexAttributeSource;
MObject     cgfxShaderNode::sTexCoordSource;
MObject     cgfxShaderNode::sColorSource;
MObject     cgfxShaderNode::sTexturesByName;
enum ETexCoord 
{       
        etcNull      = -1, 
        etcConstant  = -2, 
        etcNormal    = -3,
        etcTangent   = -4,
        etcBinormal  = -5,
        etcDataSet       = -6,
};
cgfxShaderNode::cgfxShaderNode()
:       fEffect(0)
,       fAttrDefList(0)
,       fVertexAttributes( NULL)
#ifdef TEXTURES_BY_NAME
,       fTexturesByName( true )
#else
,       fTexturesByName( false )
#endif
,   fNormalsPerVertex( 3 )
,   fConstructed(false)
,   fErrorCount( 0 )
,   fErrorLimit( 8 )
,       fTechniqueHasBlending( false )
,       fShaderFxFile()
,       fShaderFxFileChanged( false )
{
        
        MStringArray sa;
        sa.append( "map1" );      
        sa.append( "tangent" );
        sa.append( "binormal" );
        MStringArray sa2;
        sa2.append( "colorSet1" );
        setDataSources( &sa, &sa2 );
}
void
cgfxShaderNode::postConstructor()
{
        fConstructed = true;               
}                                      
cgfxShaderNode::~cgfxShaderNode()
{
#ifdef KH_DEBUG
        MString ss = "  .. ~node ";
        if ( fConstructed )
        {
                MFnDependencyNode fnNode( thisMObject() );
                ss += fnNode.name();
        }
        ss += "\n";
        ::OutputDebugString( ss.asChar() );
#endif
        
        MMessage::removeCallbacks( fCallbackIds );
        fCallbackIds.clear();
        if (fAttrDefList)
        {
                fAttrDefList->release();
                fAttrDefList = 0;
        }
        
        
        
        if (fEffect)
        {
                cgDestroyEffect(fEffect);
                fEffect = 0;
        }
}
MStatus cgfxShaderNode::compute( const MPlug& plug, MDataBlock& data )
{
        MStatus returnStatus;
        
        if ((plug == outColor) || (plug.parent() == outColor))
        {
                MFloatVector color(.07f, .8f, .07f);
                MDataHandle outputHandle = data.outputValue( outColor );
                outputHandle.asFloatVector() = color;
                outputHandle.setClean();
                return MS::kSuccess;
        }
        return MS::kUnknownParameter;
}
void* cgfxShaderNode::creator()
{
        return new cgfxShaderNode();
}
MStatus
cgfxShaderNode::initialize()
{
        MStatus ms;
        try
        {
                initializeNodeAttrs();
        }
        catch ( cgfxShaderCommon::InternalError* e )   
        {
                size_t ee = (size_t)e;
                MString es = "cgfxShaderNode internal error ";
                es += (int)ee;
                MGlobal::displayError( es );
                ms = MS::kFailure;
        }
        catch ( ... )
        {
                MString es = "cgfxShaderNode internal error: Unhandled exception in initialize";
                MGlobal::displayError( es );
                ms = MS::kFailure;
        }
        return ms;
}
void
cgfxShaderNode::initializeNodeAttrs()
{
        MFnTypedAttribute       typedAttr;
        MFnNumericAttribute     numericAttr;
        MFnStringData           stringData;
        MFnStringArrayData      stringArrayData;
        MStatus                         stat, stat2;
        
        
        
        sShader = typedAttr.create("shader", "s", MFnData::kString, stringData.create(&stat2), &stat);
        M_CHECK( stat2 );
        M_CHECK( stat );
        
        
        stat = typedAttr.setKeyable(true);
        M_CHECK( stat );
        
        
        
        stat = typedAttr.setInternal(true);
        M_CHECK( stat );
        
        
        stat = addAttribute(sShader);
        M_CHECK( stat );
        
        
        
        sTechnique = typedAttr.create("technique", "t", MFnData::kString,
                stringData.create(&stat2), &stat);
        M_CHECK( stat2 );
        M_CHECK( stat );
        typedAttr.setInternal(true);
        typedAttr.setKeyable(true);
        stat = addAttribute(sTechnique);
        M_CHECK( stat );
        
        
        
        sAttributeList = typedAttr.create("attributeList", "al", MFnData::kStringArray,
                stringArrayData.create(&stat2), &stat);
        M_CHECK( stat2 );
        M_CHECK( stat );
        
        
        stat = typedAttr.setKeyable(false);
        M_CHECK( stat );
        
        
        stat = typedAttr.setConnectable(false);
        M_CHECK( stat );
        
        
        
        stat = typedAttr.setArray(false);
        M_CHECK( stat );
        
        
        
        stat = typedAttr.setInternal(true);
        M_CHECK( stat );
        
        
        stat = typedAttr.setHidden(true);
        M_CHECK( stat );
        
        
        stat = addAttribute(sAttributeList);
        M_CHECK( stat );
        
        
        
        sVertexAttributeList = typedAttr.create("vertexAttributeList", "val", MFnData::kStringArray,
                stringArrayData.create(&stat2), &stat);
        M_CHECK( stat2 );
        M_CHECK( stat );
        
        
        stat = typedAttr.setKeyable(false);
        M_CHECK( stat );
        
        
        stat = typedAttr.setConnectable(false);
        M_CHECK( stat );
        
        
        
        stat = typedAttr.setArray(false);
        M_CHECK( stat );
        
        
        
        stat = typedAttr.setInternal(true);
        M_CHECK( stat );
        
        
        stat = typedAttr.setHidden(true);
        M_CHECK( stat );
        
        
        stat = addAttribute(sVertexAttributeList);
        M_CHECK( stat );
        
        
        
        sVertexAttributeSource = typedAttr.create( "vertexAttributeSource", "vas", MFnData::kStringArray, 
                MObject::kNullObj, &stat );
        M_CHECK( stat );
        stat = typedAttr.setInternal( true );
        M_CHECK( stat );
        stat = addAttribute( sVertexAttributeSource );
        M_CHECK( stat );
        
        
        
        sTexCoordSource = typedAttr.create( "texCoordSource", "tcs", MFnData::kStringArray, 
                MObject::kNullObj, &stat );
        M_CHECK( stat );
        stat = typedAttr.setInternal( true );
        M_CHECK( stat );
        stat = addAttribute( sTexCoordSource );
        M_CHECK( stat );
        
        
        
        sColorSource = typedAttr.create( "colorSource", "cs", MFnData::kStringArray, 
                MObject::kNullObj, &stat );
        M_CHECK( stat );
        stat = typedAttr.setInternal( true );
        M_CHECK( stat );
        stat = addAttribute( sColorSource );
        M_CHECK( stat );
        
        
        
        sTexturesByName = numericAttr.create( "texturesByName", "tbn", MFnNumericData::kBoolean,
                0, &stat );
        M_CHECK( stat );
        stat = numericAttr.setInternal(true);
        M_CHECK( stat );
        
        
        
        
        
        
        
        stat = numericAttr.setHidden(true);
        M_CHECK( stat );
        numericAttr.setKeyable(false);
        stat = addAttribute( sTexturesByName );
        M_CHECK( stat );
}                                      
void
cgfxShaderNode::copyInternalData( MPxNode* pSrc )
{
        const cgfxShaderNode& src = *(cgfxShaderNode*)pSrc;
        setTexturesByName( src.getTexturesByName() );
        setShaderFxFile( src.shaderFxFile() );
        setShaderFxFileChanged( true );
        setTechnique( src.getTechnique() );     
        setDataSources( &src.getTexCoordSource(), &src.getColorSource() );
        
        
        MString fileName = cgfxFindFile(shaderFxFile());
        bool hasFile = (fileName.asChar() != NULL) && strcmp(fileName.asChar(), "");
        if ( hasFile )
        {
                
                
                MStringArray fileOptions; 
                cgfxGetFxIncludePath( fileName, fileOptions );
                const char *opts[_CGFX_PLUGIN_MAX_COMPILER_ARGS_];
                unsigned int numOpts = fileOptions.length();            
                if (numOpts)
                {
                        numOpts = (numOpts > _CGFX_PLUGIN_MAX_COMPILER_ARGS_) ? _CGFX_PLUGIN_MAX_COMPILER_ARGS_ : numOpts;
                        for (unsigned int i=0; i<numOpts; i++)
                                opts[i] = fileOptions[i].asChar();
                        opts[numOpts] = NULL;
                }
                CGeffect cgEffect = cgCreateEffectFromFile(sCgContext, fileName.asChar(), opts);
                if (cgEffect) 
                {
                        cgfxAttrDefList* effectList = NULL;
                        MStringArray attributeList;
                        MDGModifier dagMod;
                        
                        
                        cgfxAttrDef::updateNode(cgEffect, this, &dagMod, effectList, attributeList);
                        MStatus status = dagMod.doIt();
                        assert(status == MS::kSuccess);
                        setAttrDefList(effectList);
                        setAttributeList(attributeList);
                        setEffect(cgEffect);
                        
                        if( effectList ) 
                                effectList->release();
                }
        }
}
bool cgfxShaderNode::setInternalValueInContext( const MPlug& plug,
                                                                                          const MDataHandle& handle,
                                                                                          MDGContext&)
{
        bool retVal = true;
        try
        {
#ifdef KH_DEBUG
                MString ss = "  .. seti ";
                ss += plug.partialName( true, true, true, false, false, true );
                if (plug == sShader ||
                        plug == sTechnique)
                {
                        ss += " \"";
                        ss += handle.asString();
                        ss += "\"";
                }
                ss += "\n";
                ::OutputDebugString( ss.asChar() );
#endif
                if (plug == sShader)
                {
                        setShaderFxFile(handle.asString());
                }
                else if (plug == sTechnique)
                {
                        setTechnique(handle.asString());
                }
                else if (plug == sAttributeList)
                {
                        MDataHandle nonConstHandle(handle);
                        MObject saData = nonConstHandle.data();
                        MFnStringArrayData fnSaData(saData);
                        setAttributeList(fnSaData.array());
                }
                else if (plug == sVertexAttributeList)
                {
                        MDataHandle nonConstHandle(handle);
                        MObject saData = nonConstHandle.data();
                        MFnStringArrayData fnSaData(saData);
                        const MStringArray& attributeList = fnSaData.array();
                        cgfxVertexAttribute* attributes = NULL;
                        cgfxVertexAttribute** nextAttribute = &attributes;
                        int numAttributes = attributeList.length() / 4;
                        for( int i = 0; i < numAttributes; i++)
                        {
                                cgfxVertexAttribute* attribute = new cgfxVertexAttribute();
                                attribute->fName = attributeList[ i * 4 + 0];
                                attribute->fType = attributeList[ i * 4 + 1];
                                attribute->fUIName = attributeList[ i * 4 + 2];
                                attribute->fSemantic = attributeList[ i * 4 + 3];
                                *nextAttribute = attribute;
                                nextAttribute = &attribute->fNext;
                        }
                        setVertexAttributes( attributes);
                }
                else if ( plug == sVertexAttributeSource )
                {
                        MDataHandle nonConstHandle( handle );
                        MObject     saData = nonConstHandle.data();
                        MFnStringArrayData fnSaData( saData );
                        MStringArray values = fnSaData.array();
                        setVertexAttributeSource( values);
                }
                else if ( plug == sTexCoordSource )
                {
                        MDataHandle nonConstHandle( handle );
                        MObject     saData = nonConstHandle.data();
                        MFnStringArrayData fnSaData( saData );
                        MStringArray values = fnSaData.array();
                        setDataSources( &values, NULL );
                }
                else if ( plug == sColorSource )
                {
                        MDataHandle nonConstHandle( handle );
                        MObject     saData = nonConstHandle.data();
                        MFnStringArrayData fnSaData( saData );
                        MStringArray values = fnSaData.array();
                        setDataSources( NULL, &values );
                }
                else if ( plug == sTexturesByName )
                {
                        setTexturesByName( handle.asBool(), !MFileIO::isReadingFile());
                }
                else
                {
                        retVal = MPxHwShaderNode::setInternalValue(plug, handle);
                }
        }
        catch ( cgfxShaderCommon::InternalError* e )   
        {
                reportInternalError( __FILE__, (size_t)e );
                retVal = false;
        }
        catch ( ... )
        {
                reportInternalError( __FILE__, __LINE__ );
                retVal = false;
        }
        return retVal;
}
bool cgfxShaderNode::getInternalValueInContext( const MPlug& plug,
                                                                                          MDataHandle& handle,
                                                                                          MDGContext&)
{
        bool retVal = true;
        try
        {
#ifdef KH_DEBUG
                MString ss = "  .. geti ";
                ss += plug.partialName( true, true, true, false, false, true );
                if ( plug == sShader )
                        ss += " \"" + fShaderFxFile + "\"";
                else if (plug == sTechnique)
                        ss += " \"" + fTechnique + "\"";
                ss += "\n";
                ::OutputDebugString( ss.asChar() );
#endif
                if (plug == sShader)
                {
                        handle.set(fShaderFxFile);
                }
                else if (plug == sTechnique)
                {
                        handle.set(fTechnique);
                }
                else if (plug == sAttributeList)
                {
                        MFnStringArrayData saData;
                        handle.set(saData.create(fAttributeListArray));
                }
                else if (plug == sVertexAttributeList)
                {
                        MStringArray attributeList;
                        cgfxVertexAttribute* attribute = fVertexAttributes;
                        while( attribute)
                        {
                                attributeList.append( attribute->fName);
                                attributeList.append( attribute->fType);
                                attributeList.append( attribute->fUIName);
                                attributeList.append( attribute->fSemantic);
                                attribute = attribute->fNext;
                        }
                        MFnStringArrayData saData;
                        handle.set(saData.create( attributeList));
                }
                else if ( plug == sVertexAttributeSource )
                {
                        MStringArray attributeSources;
                        cgfxVertexAttribute* attribute = fVertexAttributes;
                        while( attribute)
                        {
                                attributeSources.append( attribute->fSourceName);
                                attribute = attribute->fNext;
                        }
                        MFnStringArrayData saData;
                        handle.set( saData.create( attributeSources ) );
                }
                else if ( plug == sTexCoordSource )
                {
                        MFnStringArrayData saData;
                        handle.set( saData.create( fTexCoordSource ) );
                }
                else if ( plug == sColorSource )
                {
                        MFnStringArrayData saData;
                        handle.set( saData.create( fColorSource ) );
                }
                else if (plug == sTexturesByName)
                {
                        handle.set(fTexturesByName);
                }
                else
                {
                        retVal = MPxHwShaderNode::getInternalValue(plug, handle);
                }
        }
        catch ( cgfxShaderCommon::InternalError* e )   
        {
                reportInternalError( __FILE__, (size_t)e );
                retVal = false;
        }
        catch ( ... )
        {
                reportInternalError( __FILE__, __LINE__ );
                retVal = false;
        }
        return retVal;
}
static void checkGlErrors(const char* msg)
{
#if defined(CGFX_DEBUG)
#define MYERR(n)        case n: OutputDebugStrings("    ", #n); break
        GLenum err;
        bool errors = false;
        while ((err = glGetError()) != GL_NO_ERROR)
        {
                if (!errors)
                {
                        
                        
                        OutputDebugStrings("OpenGl errors: ", msg);
                }
                errors = true;
                switch (err)
                {
                        MYERR(GL_INVALID_ENUM);
                        MYERR(GL_INVALID_VALUE);
                        MYERR(GL_INVALID_OPERATION);
                        MYERR(GL_STACK_OVERFLOW);
                        MYERR(GL_STACK_UNDERFLOW);
                        MYERR(GL_OUT_OF_MEMORY);
                default:
                        {
                                char tmp[32];
                                sprintf(tmp, "%d", err);
                                OutputDebugStrings("    GL Error #", tmp);
                        }
                }
        }
#undef MYERR
#endif 
}
void textureChangedCallback( MNodeMessage::AttributeMessage msg, MPlug & plug, MPlug & otherPlug, void* aDef)
{
        
        
        
        
        
        
        
        ((cgfxAttrDef*)aDef)->releaseCallback();
}
#if defined(_SWATCH_RENDERING_SUPPORTED_)
MStatus cgfxShaderNode::renderSwatchImage( MImage & outImage )
{
        MStatus status = MStatus::kFailure;
        if( sCgContext == 0 )   return status;
        
        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 );
                }
                
                
                {
                        float light_pos[4];
                        pRenderer->getSwatchLightDirection( light_pos[0], light_pos[1], light_pos[2], light_pos[3] );
                }
                
                
                {
                        
                        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 );
                }
                
                
                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);
                
                
                
                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() );
                
                int uvCount = fTexCoordSource.length();
                float ** texCoordArrays = uvCount ? new float * [ uvCount] : NULL;
                for( int uv = 0; uv < uvCount; uv++)
                {
                        texCoordArrays[ uv] = uvData;
                }
                
                int normalCount = uvCount > 0 ? uvCount : 1;
                float ** normalArrays = new float * [ fNormalsPerVertex * normalCount];
                for( int n = 0; n < normalCount; n++)
                {
                        if( fNormalsPerVertex > 0)
                        {
                                normalArrays[ n * fNormalsPerVertex + 0] = normalData;
                                if( fNormalsPerVertex > 1)
                                {
                                        normalArrays[ n * fNormalsPerVertex + 1] = tangentData;
                                        if( fNormalsPerVertex > 2)
                                        {
                                                normalArrays[ n * fNormalsPerVertex + 2] = binormalData;
                                        }
                                }
                        }
                }
                glGeometry( dummyPath,
                                        GL_TRIANGLES,
                                        false,
                                        indexCount,
                                        pIndexing,
                                        pGeomData[0].elementCount(), 
                                        NULL, 
                                        vertexData,
                                        fNormalsPerVertex,
                                        (const float **) normalArrays,
                                        0, 
                                        NULL, 
                                        uvCount,
                                        (const float **) texCoordArrays);
                glUnbind( dummyPath );
                if( normalArrays) delete[] normalArrays;
                if( texCoordArrays) delete[] texCoordArrays;
                
                
                pRenderer->readSwatchContextPixels( backEndStr, outImage );
                
                
                outImage.getSize( width, height );
                if (width != origWidth || height != origHeight)
                {
                        status = MStatus::kFailure;
                }
                else
                {
                        status = MStatus::kSuccess;
                }
        }
        return status;
}
#endif
bool cgfxShaderNode::supportsBatching() const
{
        return true;
}
bool cgfxShaderNode::invertTexCoords() const
{
        return true;
}
bool cgfxShaderNode::createEffect()
{
        
        
        
        
        
        
        bool rc = false;
        if (shaderFxFileChanged())
        {
                MString fileName = cgfxFindFile(shaderFxFile());
                if(fileName.asChar() != NULL && strcmp(fileName.asChar(), ""))
                {
                        
                        MStringArray fileOptions; 
                        cgfxGetFxIncludePath( fileName, fileOptions );
                        const char *opts[_CGFX_PLUGIN_MAX_COMPILER_ARGS_];
                        unsigned int numOpts = fileOptions.length();            
                        if (numOpts)
                        {
                                numOpts = (numOpts > _CGFX_PLUGIN_MAX_COMPILER_ARGS_) ? _CGFX_PLUGIN_MAX_COMPILER_ARGS_ : numOpts;
                                for (unsigned int i=0; i<numOpts; i++)
                                        opts[i] = fileOptions[i].asChar();
                                opts[numOpts] = NULL;
                        }
                        CGeffect cgEffect = cgCreateEffectFromFile(sCgContext, fileName.asChar(), opts);
                        if (cgEffect) 
                        {
                                cgfxAttrDefList* effectList = NULL;
                                MStringArray attributeList;
                                MDGModifier dagMod;
                                
                                
                                
                                
                                
                                
                                
                                cgfxAttrDef::updateNode(cgEffect, this, &dagMod, effectList, attributeList);
                                MStatus status = dagMod.doIt();
                                assert(status == MS::kSuccess);
                                
                                setAttrDefList(effectList);
                                setAttributeList(attributeList);
                                setEffect(cgEffect);
                                setTechnique( fTechnique);
                                rc = true;
                                
                                if( effectList ) 
                                        effectList->release();
                        }
                }
                setShaderFxFileChanged( false );
        }
        return rc;
}
MStatus cgfxShaderNode::glBind(const MDagPath& shapePath)
{       
        
        
        
        
        glStateCache::instance().reset();
        
        
        
        
        
        
        
        MStatus stat;     
#ifdef KH_DEBUG
        MString ss = "  .. bind ";
        if ( this && fConstructed )
                ss += name();
        ss += " ";
        ss += request.multiPath().fullPathName();
        ss += "\n";
        ::OutputDebugString( ss.asChar() );
#endif
        try
        {
                
                if ( glStateCache::sMaxTextureUnits <= 0 )
                {
                        
                        
                        
#ifdef _WIN32
#define RESOLVE_GL_EXTENSION( fn, ext) wglGetProcAddress( #fn #ext)
#elif defined LINUX
#define RESOLVE_GL_EXTENSION( fn, ext) &fn ## ext
#else
#define RESOLVE_GL_EXTENSION( fn, ext) &fn
#endif
                        glStateCache::glClientActiveTexture = (PFNGLCLIENTACTIVETEXTUREARBPROC) RESOLVE_GL_EXTENSION( glClientActiveTexture, ARB);
                        glStateCache::glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERARBPROC) RESOLVE_GL_EXTENSION( glVertexAttribPointer, ARB);
                        glStateCache::glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC) RESOLVE_GL_EXTENSION( glEnableVertexAttribArray, ARB);
                        glStateCache::glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) RESOLVE_GL_EXTENSION( glDisableVertexAttribArray, ARB);
                        glStateCache::glVertexAttrib4f = (PFNGLVERTEXATTRIB4FARBPROC) RESOLVE_GL_EXTENSION( glVertexAttrib4f, ARB);
                        glStateCache::glSecondaryColorPointer = (PFNGLSECONDARYCOLORPOINTEREXTPROC) RESOLVE_GL_EXTENSION( glSecondaryColorPointer, EXT);
                        glStateCache::glSecondaryColor3f = (PFNGLSECONDARYCOLOR3FEXTPROC) RESOLVE_GL_EXTENSION( glSecondaryColor3f, EXT);
                        glStateCache::glMultiTexCoord4fARB = (PFNGLMULTITEXCOORD4FARBPROC) RESOLVE_GL_EXTENSION( glMultiTexCoord4f, ARB);
                        
                        
                        
                        
                        
                        
                        
                        
                        GLint tval;
                        glGetIntegerv( GL_MAX_TEXTURE_COORDS_ARB, &tval );
                        GLint mic = 0;
                        glGetIntegerv( GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &mic );
                        if (mic < tval)
                                tval = mic;
                        
                        
                        glStateCache::sMaxTextureUnits = tval;
                        if (!glStateCache::glClientActiveTexture || glStateCache::sMaxTextureUnits < 1)
                                glStateCache::sMaxTextureUnits = 1;
                        else if (glStateCache::sMaxTextureUnits > CGFXSHADERNODE_GL_TEXTURE_MAX)
                                glStateCache::sMaxTextureUnits = CGFXSHADERNODE_GL_TEXTURE_MAX;
                }
                
                if( fNewEffect.fTechnique && fNewEffect.fTechnique->fPasses)
                {
                        
                        bindAttrValues();
                        
                        if (fTechniqueHasBlending)
                                glPushAttrib( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
                        glGetBooleanv( GL_DEPTH_TEST, &fDepthEnableState);
                        glGetIntegerv( GL_DEPTH_FUNC, &fDepthFunc);
                        glGetIntegerv( GL_BLEND_SRC, &fBlendSourceFactor);
                        glGetIntegerv( GL_BLEND_DST, &fBlendDestFactor);
                        glDepthFunc(GL_LEQUAL);
                        if( !fNewEffect.fTechnique->fMultiPass && fNewEffect.fTechnique->fPasses)
                                cgSetPassState( fNewEffect.fTechnique->fPasses->fPass);
                        }
                else
                {
                        
                        
                        
                        
                        
                        glPushAttrib( GL_LIGHTING);
                        static float diffuse_color[4]  = {1.0, 0.5, 0.5, 1.0};
                        static float specular_color[4] = {1.0, 1.0, 1.0, 1.0};
                        glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
                        glEnable(GL_COLOR_MATERIAL);
                        glColor4fv(diffuse_color);
                        
                        
                        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular_color);
                        
                        
                        glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 100.0);
                }
                checkGlErrors("cgfxShaderNode::glBind");
        }
        catch ( cgfxShaderCommon::InternalError* e )   
        {
                reportInternalError( __FILE__, (size_t)e );
                stat = MS::kFailure;
        }
        catch ( ... )
        {
                reportInternalError( __FILE__, __LINE__ );
                stat = MS::kFailure;
        }
        return stat;
}                                      
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;
}
void cgfxShaderNode::bindAttrValues()
{
        if ( !fEffect || !fTechnique.length() )
                return;
        MStatus  status;
        MObject  oNode = thisMObject();
        
        
        
        
        for ( cgfxAttrDefList::iterator it( fAttrDefList ); it; ++it )
        {                                  
                cgfxAttrDef* aDef = *it;
                try
                {
                        switch (aDef->fType)
                        {
                        case cgfxAttrDef::kAttrTypeBool:
                                {
                                        bool tmp;
                                        aDef->getValue(oNode, tmp);
                                        cgSetParameter1i(aDef->fParameterHandle, tmp);
                                        break;
                                }
                        case cgfxAttrDef::kAttrTypeInt:
                                {
                                        int tmp;
                                        aDef->getValue(oNode, tmp);
                                        cgSetParameter1i(aDef->fParameterHandle, tmp);
                                        break;
                                }
                        case cgfxAttrDef::kAttrTypeFloat:
                                {
                                        float tmp;
                                        aDef->getValue(oNode, tmp);
                                        cgSetParameter1f(aDef->fParameterHandle, tmp);
                                        break;
                                }
                        case cgfxAttrDef::kAttrTypeString:
                                {
                                        MString tmp;
                                        aDef->getValue(oNode, tmp);
                                        cgSetStringParameterValue(aDef->fParameterHandle, tmp.asChar());
                                        break;
                                }
                        case cgfxAttrDef::kAttrTypeVector2:
                                {
                                        float tmp[2];
                                        aDef->getValue(oNode, tmp[0], tmp[1]);
                                        cgSetParameter2fv(aDef->fParameterHandle, tmp);
                                        break;
                                }
                        case cgfxAttrDef::kAttrTypeVector3:
                        case cgfxAttrDef::kAttrTypeColor3:
                                {
                                        float tmp[3];
                                        aDef->getValue(oNode, tmp[0], tmp[1], tmp[2]);
                                        cgSetParameter3fv(aDef->fParameterHandle, tmp);
                                        break;
                                }
                        case cgfxAttrDef::kAttrTypeVector4:
                        case cgfxAttrDef::kAttrTypeColor4:
                                {
                                        float tmp[4];
                                        aDef->getValue(oNode, tmp[0], tmp[1], tmp[2], tmp[3]);
                                        cgSetParameter4fv(aDef->fParameterHandle, tmp);
                                        break;
                                }
                        case cgfxAttrDef::kAttrTypeWorldDir:
                        case cgfxAttrDef::kAttrTypeWorldPos:
                                {
                                        
                                        float tmp[4];
                                        if (aDef->fSize == 3)
                                        {
                                                aDef->getValue(oNode, tmp[0], tmp[1], tmp[2]);
                                                tmp[3] = 1.0;
                                        }
                                        else
                                        {
                                                aDef->getValue(oNode, tmp[0], tmp[1], tmp[2], tmp[3]);
                                        }
                                        
                                        
                                        int base = cgfxAttrDef::kAttrTypeFirstPos;
                                        if (aDef->fType <= cgfxAttrDef::kAttrTypeLastDir) 
                                                base = cgfxAttrDef::kAttrTypeFirstDir;
                                        int space = aDef->fType - base;
                                        
                                        MMatrix mat;
                                        switch (space)
                                        {
                                                
                                                case 1:  break;
                                                
                                                
                                                
                                        }
                                        if (base == cgfxAttrDef::kAttrTypeFirstPos)
                                        {
                                                MPoint point(tmp[0], tmp[1], tmp[2], tmp[3]);
                                                point *= mat;
                                                tmp[0] = (float)point.x;
                                                tmp[1] = (float)point.y;
                                                tmp[2] = (float)point.z;
                                                tmp[3] = (float)point.w;
                                        }
                                        else
                                        {
                                                MVector vec(tmp[0], tmp[1], tmp[2]);
                                                vec *= mat;
                                                tmp[0] = (float)vec.x;
                                                tmp[1] = (float)vec.y;
                                                tmp[2] = (float)vec.z;
                                                tmp[3] = 1.F;
                                        }
                                        cgSetParameterValuefr(aDef->fParameterHandle, aDef->fSize, tmp);
                                        break;
                                }
                        case cgfxAttrDef::kAttrTypeMatrix:
                                {
                                        MMatrix tmp;
                                        float tmp2[4][4];
                                        aDef->getValue(oNode, tmp);
                                        if (aDef->fInvertMatrix)
                                        {
                                                tmp = tmp.inverse();
                                        }
                                        if (!aDef->fTransposeMatrix)
                                        {
                                                tmp = tmp.transpose();
                                        }
                                        tmp.get(tmp2);
                                        cgSetMatrixParameterfr(aDef->fParameterHandle, &tmp2[0][0]);
                                        break;
                                }
                        case cgfxAttrDef::kAttrTypeColor1DTexture:
                        case cgfxAttrDef::kAttrTypeColor2DTexture:
                        case cgfxAttrDef::kAttrTypeColor3DTexture:
                        case cgfxAttrDef::kAttrTypeColor2DRectTexture:
                        case cgfxAttrDef::kAttrTypeNormalTexture:
                        case cgfxAttrDef::kAttrTypeBumpTexture:
                        case cgfxAttrDef::kAttrTypeCubeTexture:
                        case cgfxAttrDef::kAttrTypeEnvTexture:
                        case cgfxAttrDef::kAttrTypeNormalizationTexture:
                                {
                                        MString tmp;
                                        MObject textureNode = MObject::kNullObj;
                                        if( fTexturesByName)
                                        {
                                                aDef->getValue(oNode, tmp);
                                        }
                                        else
                                        {
                                                
                                                
                                                MPlug srcPlug;
                                                aDef->getSource(oNode, srcPlug);
                                                MObject srcNode = srcPlug.node();
                                                if( srcNode != MObject::kNullObj)
                                                {
                                                        MStatus rc;
                                                        MFnDependencyNode dgFn( srcNode);
                                                        MPlug filenamePlug = dgFn.findPlug( "fileTextureName", &rc);
                                                        if( rc == MStatus::kSuccess)
                                                        {
                                                                filenamePlug.getValue( tmp);
                                                                textureNode = filenamePlug.node(&rc);
                                                        }
                                                        
                                                        
                                                        
                                                        
                                                        
                                                        if( aDef->fTextureMonitor == kNullCallback && textureNode != MObject::kNullObj)
                                                        {
                                                                
                                                                
                                                                
                                                                
                                                                aDef->releaseTexture();
                                                                aDef->fTextureMonitor = MNodeMessage::addAttributeChangedCallback( textureNode, textureChangedCallback, aDef);
                                                        }
                                                }
                                        }
                                        if (aDef->fTextureId == 0 || tmp != aDef->fStringDef)
                                        {
                                                
                                                
                                                
                                                if (aDef->fTextureId == 0)
                                                {
                                                        GLuint val;
                                                        glGenTextures(1, &val);
                                                        aDef->fTextureId = val;
                                                }
                                                aDef->fStringDef = tmp;
                                                nv_dds::CDDSImage image;
                                                MString path = cgfxFindFile(tmp);
                                                
                                                
                                                
                                                if (path.asChar() == NULL || !strcmp(path.asChar(), ""))
                                                {
                                                        MFileObject effectFile;
                                                        effectFile.setRawFullName( fShaderFxFile);
                                                        path = cgfxFindFile( effectFile.path() + tmp);
                                                }
                                                if (path.asChar() != NULL && strcmp(path.asChar(), ""))
                                                {
                                                        switch (aDef->fType)
                                                        {
                                                        case cgfxAttrDef::kAttrTypeEnvTexture:
                                                        case cgfxAttrDef::kAttrTypeCubeTexture:
                                                        case cgfxAttrDef::kAttrTypeNormalizationTexture:
                                                                
                                                                image.load(path.asChar(),false);
                                                                break;
                                                        default:
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                image.load(path.asChar(), !invertTexCoords() );
                                                                break;
                                                        }
                                                }
                                                
                                                
                                                
                                                
                                                
                                                
                                                
                                                
                                                
                                                
                                                
                                                static unsigned char whitePixel[ 4] = { 255, 255, 255, 255};
                                                switch (aDef->fType)
                                                {
                                                case cgfxAttrDef::kAttrTypeColor1DTexture:
                                                        glBindTexture(GL_TEXTURE_1D,aDef->fTextureId);
                                                        if( image.is_valid())
                                                        {
                                                                
                                                                glTexParameteri(GL_TEXTURE_1D, GL_GENERATE_MIPMAP_SGIS, image.get_num_mipmaps() == 0);
                                                                image.upload_texture1D();
                                                        }
                                                        else
                                                        {
                                                                
                                                                glTexImage1D( GL_TEXTURE_1D, 0, GL_RGBA, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, whitePixel);
                                                        }
                                                        break;
                                                case cgfxAttrDef::kAttrTypeColor2DTexture:
                                                case cgfxAttrDef::kAttrTypeNormalTexture:
                                                case cgfxAttrDef::kAttrTypeBumpTexture:
#if !defined(WIN32) && !defined(LINUX)
                                                case cgfxAttrDef::kAttrTypeColor2DRectTexture:
#endif
                                                        glBindTexture(GL_TEXTURE_2D,aDef->fTextureId);
                                                        if( image.is_valid())
                                                        {
                                                                
                                                                glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, image.get_num_mipmaps() == 0);
                                                                image.upload_texture2D();
                                                        }
                                                        else
                                                        {
                                                                
                                                                
                                                                
                                                                
                                                                if (textureNode != MObject::kNullObj) 
                                                                {
                                                                        MImage img;
                                                                        unsigned int width, height;
                                                                        if (MS::kSuccess == img.readFromTextureNode(textureNode))
                                                                        {
                                                                                
                                                                                
                                                                                if( invertTexCoords() )
                                                                                {
                                                                                        img.verticalFlip();
                                                                                }
                                                                                MStatus status = img.getSize( width, height);
                                                                                if (width > 0 && height > 0 && (status != MStatus::kFailure) )
                                                                                {
                                                                                        
                                                                                        
                                                                                        
                                                                                        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 );
                                                                                                }
                                                                                        }                                                                               
                                                                                        glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, true);
                                                                                        glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.pixels());
                                                                                }
                                                                                else
                                                                                {
                                                                                        
                                                                                        glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, 
                                                                                                GL_RGBA, GL_UNSIGNED_BYTE, whitePixel);
                                                                                }
                                                                        }
                                                                        else
                                                                        {
                                                                                
                                                                                glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, 
                                                                                        GL_RGBA, GL_UNSIGNED_BYTE, whitePixel);
                                                                        }
                                                                }
                                                                else
                                                                {
                                                                        
                                                                        glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, 
                                                                                GL_RGBA, GL_UNSIGNED_BYTE, whitePixel);
                                                                }
                                                        }
                                                        break;
                                                case cgfxAttrDef::kAttrTypeEnvTexture:
                                                case cgfxAttrDef::kAttrTypeCubeTexture:
                                                case cgfxAttrDef::kAttrTypeNormalizationTexture:
                                                        {
                                                                glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, aDef->fTextureId);
                                                                if( image.is_valid())
                                                                {
                                                                        GLenum target;
                                                                        glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_GENERATE_MIPMAP_SGIS, image.get_num_mipmaps() == 0);
                                                                        
                                                                        for (int n = 0; n < 6; ++n)
                                                                        {
                                                                                
                                                                                target = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB+n;
                                                                                image.upload_texture2D(image.is_cubemap() ? n : 0, target);
                                                                        }
                                                                }
                                                                
                                                                break;
                                                        }
                                                case cgfxAttrDef::kAttrTypeColor3DTexture:
                                                        glBindTexture(GL_TEXTURE_3D,aDef->fTextureId);
                                                        if( image.is_valid())
                                                        {
                                                        image.upload_texture3D();
                                                        }
                                                        break;
#if defined(WIN32) || defined(LINUX)
                                                        
                                                        
                                                case cgfxAttrDef::kAttrTypeColor2DRectTexture:
                                                        glBindTexture(GL_TEXTURE_RECTANGLE_NV, aDef->fTextureId);
                                                        if( image.is_valid())
                                                        {
                                                                
                                                                image.upload_textureRectangle();
                                                        }
                                                        else
                                                        {
                                                                
                                                                glTexImage2D( GL_TEXTURE_RECTANGLE_NV, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, whitePixel);
                                                        }
                                                        break;
#endif
                                                default:
                                                        assert(false);
                                                }
                                        }
                                        checkGlErrors("After loading texture");
                                        cgGLSetupSampler(aDef->fParameterHandle, aDef->fTextureId);
                                        break;
                                }
#ifdef _WIN32
                        case cgfxAttrDef::kAttrTypeTime:
                                {
                                        int ival = timeGetTime() & 0xffffff;
                                        float val = (float)ival * 0.001f; 
                                        cgSetParameter1f(aDef->fParameterHandle, val);
                                        break;
                                }
#endif
                        case cgfxAttrDef::kAttrTypeOther:
                        case cgfxAttrDef::kAttrTypeUnknown:
                                break;
                        case cgfxAttrDef::kAttrTypeObjectDir:
                        case cgfxAttrDef::kAttrTypeViewDir:
                        case cgfxAttrDef::kAttrTypeProjectionDir:
                        case cgfxAttrDef::kAttrTypeScreenDir:
                        case cgfxAttrDef::kAttrTypeObjectPos:
                        case cgfxAttrDef::kAttrTypeViewPos:
                        case cgfxAttrDef::kAttrTypeProjectionPos:
                        case cgfxAttrDef::kAttrTypeScreenPos:
                        case cgfxAttrDef::kAttrTypeWorldMatrix:
                        case cgfxAttrDef::kAttrTypeViewMatrix:
                        case cgfxAttrDef::kAttrTypeProjectionMatrix:
                        case cgfxAttrDef::kAttrTypeWorldViewMatrix:
                        case cgfxAttrDef::kAttrTypeWorldViewProjectionMatrix:
                                
                                break;
                        default:
                                M_CHECK( false );
                        }                          
                }
                catch ( cgfxShaderCommon::InternalError* e )   
                {
                        if ( ++fErrorCount <= fErrorLimit ) 
                        {
                                size_t ee = (size_t)e;
                                MFnDependencyNode fnNode( oNode );
                                MString sMsg = "cgfxShader warning ";
                                sMsg += (int)ee;
                                sMsg += ": ";
                                sMsg += fnNode.name();
                                sMsg += " internal error while setting parameter \"";
                                sMsg += aDef->fName;
                                sMsg += "\" of effect \""; 
                                sMsg += fShaderFxFile;
                                sMsg += "\" for shape ";
                                sMsg += currentPath().partialPathName();
                                MGlobal::displayWarning( sMsg );
                        }
                }
        }                                  
}                                      
void
cgfxShaderNode::bindViewAttrValues(const MDagPath& shapePath)
{
        if ( !fEffect ||
                !fTechnique.length() )
                return;
        MStatus  status;
        MObject  oNode = thisMObject();
        MMatrix wMatrix, vMatrix, pMatrix, sMatrix;
        MMatrix wvMatrix, wvpMatrix, wvpsMatrix;
        {
                float tmp[4][4];
                if (shapePath.isValid())
                        wMatrix = shapePath.inclusiveMatrix();
                else
                        wMatrix.setToIdentity();
                glGetFloatv(GL_MODELVIEW_MATRIX, &tmp[0][0]);
                wvMatrix = MMatrix(tmp);
                vMatrix = wMatrix.inverse() * wvMatrix;
                glGetFloatv(GL_PROJECTION_MATRIX, &tmp[0][0]);
                pMatrix = MMatrix(tmp);
                wvpMatrix = wvMatrix * pMatrix;
                float vpt[4];
                float depth[2];
                glGetFloatv(GL_VIEWPORT, vpt);
                glGetFloatv(GL_DEPTH_RANGE, depth);
                
                
                float x0, y0, z0, w, h, d;
                x0 = vpt[0];
                y0 = vpt[1];
                z0 = depth[0];
                w  = vpt[2];
                h  = vpt[3];
                d  = depth[1] - z0;
                
                
                double* s = &sMatrix.matrix[0][0];
                s[ 0] = w/2;    s[ 1] = 0.0;    s[ 2] = 0.0;    s[ 3] = 0.0;
                s[ 4] = 0.0;    s[ 5] = h/2;    s[ 6] = 0.0;    s[ 7] = 0.0;
                s[ 8] = 0.0;    s[ 9] = 0.0;    s[10] = d/2;    s[11] = 0.0;
                s[12] = x0+w/2; s[13] = y0+h/2; s[14] = z0+d/2; s[15] = 1.0;
                wvpsMatrix = wvpMatrix * sMatrix;
        }               
        for ( cgfxAttrDefList::iterator it( fAttrDefList ); it; ++it )
        {                                  
                cgfxAttrDef* aDef = *it;
                try
                {
                        switch (aDef->fType)
                        {
                        case cgfxAttrDef::kAttrTypeObjectDir:
                        case cgfxAttrDef::kAttrTypeViewDir:
                        case cgfxAttrDef::kAttrTypeProjectionDir:
                        case cgfxAttrDef::kAttrTypeScreenDir:
                        case cgfxAttrDef::kAttrTypeObjectPos:
                        case cgfxAttrDef::kAttrTypeViewPos:
                        case cgfxAttrDef::kAttrTypeProjectionPos:
                        case cgfxAttrDef::kAttrTypeScreenPos:
                                {
                                        float tmp[4];
                                        if (aDef->fSize == 3)
                                        {
                                                aDef->getValue(oNode, tmp[0], tmp[1], tmp[2]);
                                                tmp[3] = 1.0;
                                        }
                                        else
                                        {
                                                aDef->getValue(oNode, tmp[0], tmp[1], tmp[2], tmp[3]);
                                        }
                                        
                                        
                                        
                                        
                                        MVector vec(tmp[0], tmp[1], tmp[2]);
                                        int space = aDef->fType - cgfxAttrDef::kAttrTypeFirstPos;
                                        if (space < 0)
                                        {
                                                space = aDef->fType - cgfxAttrDef::kAttrTypeFirstDir;
                                        }
                                        MMatrix mat;  
                                        switch (space)
                                        {
                                        case 0:     break;
                                        case 1: mat = wMatrix;                  break;
                                        case 2: mat = wvMatrix;                 break;
                                        case 3: mat = wvpMatrix;                break;
                                        case 4: mat = wvpsMatrix;               break;
                                        }
                                        
                                        
                                        
                                        
                                        int base = cgfxAttrDef::kAttrTypeFirstPos;
                                        if (aDef->fType <= cgfxAttrDef::kAttrTypeLastDir) 
                                                base = cgfxAttrDef::kAttrTypeFirstDir;
                                        if (base == cgfxAttrDef::kAttrTypeFirstPos)
                                        {
                                                MPoint point(tmp[0], tmp[1], tmp[2], tmp[3]);
                                                point *= wMatrix.inverse() * mat;
                                                tmp[0] = (float)point.x;
                                                tmp[1] = (float)point.y;
                                                tmp[2] = (float)point.z;
                                                tmp[3] = (float)point.w;
                                        }
                                        else
                                        {
                                                MVector vec(tmp[0], tmp[1], tmp[2]);
                                                vec *= wMatrix.inverse() * mat;
                                                tmp[0] = (float)vec.x;
                                                tmp[1] = (float)vec.y;
                                                tmp[2] = (float)vec.z;
                                                tmp[3] = 1.F;
                                        }
                                        cgSetParameterValuefc(aDef->fParameterHandle, aDef->fSize, tmp);
                                        break;
                                }
                        case cgfxAttrDef::kAttrTypeWorldMatrix:
                        case cgfxAttrDef::kAttrTypeViewMatrix:
                        case cgfxAttrDef::kAttrTypeProjectionMatrix:
                        case cgfxAttrDef::kAttrTypeWorldViewMatrix:
                        case cgfxAttrDef::kAttrTypeWorldViewProjectionMatrix:
                                {
                                        MMatrix mat;
                                        switch (aDef->fType)
                                        {
                                        case cgfxAttrDef::kAttrTypeWorldMatrix:
                                                mat = wMatrix; break;
                                        case cgfxAttrDef::kAttrTypeViewMatrix:
                                                mat = vMatrix; break;
                                        case cgfxAttrDef::kAttrTypeProjectionMatrix:
                                                mat = pMatrix; break;
                                        case cgfxAttrDef::kAttrTypeWorldViewMatrix:
                                                mat = wvMatrix; break;
                                        case cgfxAttrDef::kAttrTypeWorldViewProjectionMatrix:
                                                mat = wvpMatrix; break;
                                        default:
                                                break;
                                        }
                                        if (aDef->fInvertMatrix)
                                        {
                                                mat = mat.inverse();
                                        }
                                        if (!aDef->fTransposeMatrix)
                                        {
                                                mat = mat.transpose();
                                        }
                                        float tmp[4][4];
                                        mat.get(tmp);
                                        cgSetMatrixParameterfr(aDef->fParameterHandle, &tmp[0][0]);
                                        break;
                                }
                                default:
                                        break;
                        }                          
                }
                catch ( cgfxShaderCommon::InternalError* e )   
                {
                        if ( ++fErrorCount <= fErrorLimit ) 
                        {
                                size_t ee = (size_t)e;
                                MFnDependencyNode fnNode( oNode );
                                MString sMsg = "cgfxShader warning ";
                                sMsg += (int)ee;
                                sMsg += ": ";
                                sMsg += fnNode.name();
                                sMsg += " internal error while setting parameter \"";
                                sMsg += aDef->fName;
                                sMsg += "\" of effect \""; 
                                sMsg += fShaderFxFile;
                                sMsg += "\" for shape ";
                                if (shapePath.isValid())
                                        sMsg += shapePath.partialPathName();
                                else
                                        sMsg += "SWATCH GEOMETRY";
                                MGlobal::displayWarning( sMsg );
                        }
                }
        }                                  
}
MStatus cgfxShaderNode::glUnbind(const MDagPath& shapePath)
{
        if( fNewEffect.fTechnique && fNewEffect.fTechnique->fPasses)
        {
                
                if( !fNewEffect.fTechnique->fMultiPass)
                        cgResetPassState( fNewEffect.fTechnique->fPasses->fPass);
                
                if( fDepthEnableState)
                        glEnable( GL_DEPTH_TEST);
                else
                        glDisable( GL_DEPTH_TEST);
                glDepthFunc( fDepthFunc);
                glBlendFunc( fBlendSourceFactor, fBlendDestFactor);
                if (fTechniqueHasBlending)
                        glPopAttrib();
        }
        else
        {
                
                glPopAttrib();
        }
        glStateCache::instance().disableAll();
        glStateCache::instance().activeTexture( 0);
#ifdef KH_DEBUG
        MString ss = "  .. unbd ";
        if ( this && fConstructed )
                ss += name();
        ss += "\n";
        ::OutputDebugString( ss.asChar() );
#endif
        return MS::kSuccess;
}
MStatus cgfxShaderNode::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)
{
        MStatus stat;
#ifdef KH_DEBUG
        MString ss = "  .. geom ";
        if ( this && fConstructed )
                ss += name();
        ss += " ";
        ss += indexCount;
        ss += "i ";
        ss += vertexCount;
        ss += "v ";
        ss += normalCount;
        ss += "n ";
        ss += colorCount;
        ss += "c ";
        ss += texCoordCount;
        ss += "t ";
        ss += "\n";
        ::OutputDebugString( ss.asChar() );
#endif
        try
        {
                if( fNewEffect.fTechnique && fNewEffect.fTechnique->fPasses)
                {
                        
                        bindViewAttrValues(shapePath);
                        
                        if( dirtyMask() != kDirtyNone)
                                fNewEffect.flushCache( shapePath);
                        
                        cgfxPass* pass = fNewEffect.fTechnique->fPasses;
                        while( pass)
                        {
                                pass->bind( shapePath, vertexCount, vertexArray, fNormalsPerVertex, normalCount, normalArrays, colorCount, colorArrays, texCoordCount, texCoordArrays);
                                glStateCache::instance().flushState();
                                if( fNewEffect.fTechnique->fMultiPass) cgSetPassState( pass->fPass);
                                glDrawElements(prim, indexCount, GL_UNSIGNED_INT, indexArray);
                                if( fNewEffect.fTechnique->fMultiPass) cgResetPassState( pass->fPass);
                                pass = pass->fNext;
                        }
                }
                else 
                {
                        
                        
                        
                        glStateCache::instance().enablePosition();
                        glVertexPointer(3, GL_FLOAT, 0, vertexArray);
                        if ( normalCount > 0 && normalArrays[ 0 ] )
                        {
                                glStateCache::instance().enableNormal();
                                glNormalPointer(GL_FLOAT, 0, normalArrays[0]);
                        }
                        else
                        {
                                glStateCache::instance().disableNormal();
                                glNormal3f(0.0, 0.0, 1.0);
                        }
                        glStateCache::instance().flushState();
                        glDrawElements(prim, indexCount, GL_UNSIGNED_INT, indexArray);
                }
                checkGlErrors("After effects End");
        }
        catch ( cgfxShaderCommon::InternalError* e )   
        {
                reportInternalError( __FILE__, (size_t)e );
                stat = MS::kFailure;
        }
        catch ( ... )
        {
                reportInternalError( __FILE__, __LINE__ );
                stat = MS::kFailure;
        }
        return stat;
}                                      
int
cgfxShaderNode::getTexCoordSetNames( MStringArray& names )
{
        names = fUVSets;
        return names.length();
}                                      
#if MAYA_API_VERSION >= 700
int
cgfxShaderNode::getColorSetNames( MStringArray& names )
{
        names = fColorSets;
        return names.length();
}
#else
int cgfxShaderNode::colorsPerVertex()
{
        fColorType.setLength(1);
        fColorIndex.setLength(1);
        fColorType[0] = 0;
        fColorIndex[0] = 0;
        return 1;
} 
#endif
int cgfxShaderNode::normalsPerVertex()
{
#ifdef KH_DEBUG
        MString ss = "  .. npv  ";
        if ( this && fConstructed )
                ss += name();
        ss += " ";
        ss += fNormalsPerVertex;
        ss += "\n";
        ::OutputDebugString( ss.asChar() );
#endif
        
        
        
        if (fEffect == NULL) {
#ifdef _WIN32
                ::OutputDebugString( "CGFX: fEffect was NULL\n");
#endif
                
                
                
                
                
                
                createEffect();
        }
        return fNormalsPerVertex;
        
        
        
        
}                                      
void
cgfxShaderNode::setAttrDefList( cgfxAttrDefList* list )
{
        if (fAttrDefList)
                cgfxAttrDef::purgeMObjectCache( fAttrDefList );
        if ( list )
        {
                list->addRef();
                cgfxAttrDef::validateMObjectCache( thisMObject(), list );
        }
        if (fAttrDefList)
                fAttrDefList->release();
        fAttrDefList = list;
}                                      
void cgfxShaderNode::getAttributeList(MStringArray& attrList) const
{
        MString tmp;
        int len = fAttributeListArray.length();
        attrList.clear();
        for (int i = 0; i < len; ++i)
        {
                tmp = fAttributeListArray[i];
                attrList.append(tmp);
        }
}
void cgfxShaderNode::setAttributeList(const MStringArray& attrList)
{
        MString tmp;
        int len = attrList.length();
        fAttributeListArray.clear();
        for (int i = 0; i < len; ++i)
        {
                tmp = attrList[i];
                fAttributeListArray.append(tmp);
        }
}
void 
cgfxShaderNode::setVertexAttributes( cgfxVertexAttribute* attributeList)
{
        
        
        
        if( fTexCoordSource.length())
        {
                int length = fTexCoordSource.length();
                for( int i = 0; i < length; i++)
                {
                        MString semantic( "TEXCOORD");
                        if( i)
                                semantic += i;
                        else
                                semantic += "0";
                        MString source( fTexCoordSource[ i]);
                        if( source.index( ':') < 0)
                                source = "uv:" + source;
                        cgfxVertexAttribute* newAttribute = attributeList;
                        while( newAttribute)
                        {
                                if( newAttribute->fSemantic == semantic || 
                                        (i == 6 && (newAttribute->fSemantic == "TANGENT" || newAttribute->fSemantic == "TANGENT0")) ||
                                        (i == 7 && (newAttribute->fSemantic == "BINORMAL" || newAttribute->fSemantic == "BINORMAL0")))
                                        newAttribute->fSourceName = source;
                                newAttribute = newAttribute->fNext;
                        }
                }
                fTexCoordSource.clear();
        }
        if( fColorSource.length())
        {
                int length = fColorSource.length();
                for( int i = 0; i < length; i++)
                {
                        MString semantic( "COLOR");
                        if( i)
                                semantic += i;
                        else
                                semantic += "0";
                        MString source( fColorSource[ i]);
                        if( source.index( ':') < 0)
                                source = "color:" + source;
                        cgfxVertexAttribute* newAttribute = attributeList;
                        while( newAttribute)
                        {
                                if( newAttribute->fSemantic == semantic)
                                        newAttribute->fSourceName = source;
                                newAttribute = newAttribute->fNext;
                        }
                }
                fColorSource.clear();
        }
        
        
        cgfxVertexAttribute* oldAttributes = fVertexAttributes;
        while( oldAttributes)
        {
                cgfxVertexAttribute* oldAttribute = oldAttributes;
                oldAttributes = oldAttributes->fNext;
                cgfxVertexAttribute* newAttribute = attributeList;
                while( newAttribute)
                {
                        if( newAttribute->fName == oldAttribute->fName)
                        {
                                newAttribute->fSourceName = oldAttribute->fSourceName;
                                newAttribute->fSourceType = oldAttribute->fSourceType;
                        }
                        newAttribute = newAttribute->fNext;
                }
                delete oldAttribute;
        }
        
        fVertexAttributes = attributeList;
        
        
        analyseVertexAttributes();
}
void
cgfxShaderNode::setVertexAttributeSource( const MStringArray& sources)
{
        
        fNewEffect.flushCache();
        
        int i = 0;
        int numSources = sources.length();
        cgfxVertexAttribute* attribute = fVertexAttributes;
        while( attribute)
        {
                attribute->fSourceName = ( i <  numSources) ? sources[ i++] : "";
                attribute = attribute->fNext;
        }
        
        
        analyseVertexAttributes();
}
inline int findOrInsert( const MString& value, MStringArray& list)
{
        int length = list.length();
        for( int i = 0; i < length; i++)
                if( list[ i] == value)
                        return i;
        list.append( value);
        return length;
}
void 
cgfxShaderNode::analyseVertexAttributes()
{
        fUVSets.clear();
        fColorSets.clear();
        fNormalsPerVertex = 0;
        cgfxVertexAttribute* attribute = fVertexAttributes;
        while( attribute)
        {
                
                MString source( attribute->fSourceName);
                source.toLowerCase();
                if( attribute->fSourceName.length() == 0)
                {
                        attribute->fSourceType = cgfxVertexAttribute::kNone;
                }
                else if( source == "position")
                {
                        attribute->fSourceType = cgfxVertexAttribute::kPosition;
                }
                else if( source == "normal")
                {
                        attribute->fSourceType = cgfxVertexAttribute::kNormal;
                        if( fNormalsPerVertex < 1)
                                fNormalsPerVertex = 1;
                }
                else
                {
                        
                        MString set = attribute->fSourceName;
                        int colon = set.index( ':');
                        MString type;
                        if( colon >= 0)
                        {
                                if( colon > 0) type = source.substring( 0, colon - 1);
                                set = set.substring( colon + 1, set.length() - 1);                              
                        }
                        
                        if( type == "uv")
                        {
                                attribute->fSourceType = cgfxVertexAttribute::kUV;
                                attribute->fSourceIndex = findOrInsert( set, fUVSets);
                        }
                        else if( type == "tangent")
                        {
                                attribute->fSourceType = cgfxVertexAttribute::kTangent;
                                if( fNormalsPerVertex < 2)
                                        fNormalsPerVertex = 2;
                                attribute->fSourceIndex = findOrInsert( set, fUVSets);
                        }
                        else if( type == "binormal")
                        {
                                attribute->fSourceType = cgfxVertexAttribute::kBinormal;
                                if( fNormalsPerVertex < 3)
                                        fNormalsPerVertex = 3;
                                attribute->fSourceIndex = findOrInsert( set, fUVSets);
                        }
                        else if( type == "color")
                        {
                                attribute->fSourceType = cgfxVertexAttribute::kColor;
                                attribute->fSourceIndex = findOrInsert( set, fColorSets);
                        }
                        else
                        {
                                attribute->fSourceType = cgfxVertexAttribute::kUnknown;
                        }
                }
                attribute = attribute->fNext;
        }
        
}
const MStringArray&
cgfxShaderNode::getTexCoordSource() const
{
#ifdef KH_DEBUG
        MString ss = "  .. gtcs ";
        if ( this && fConstructed )
                ss += name();
        ss += " ";
        for ( int ii = 0; ii < fTexCoordSource.length(); ++ii )
        {
                ss += "\"";
                ss += fTexCoordSource[ii];
                ss += "\" ";
        }
        ss += "\n";
        ::OutputDebugString( ss.asChar() );
#endif
        return fTexCoordSource;
}                                      
const MStringArray&
cgfxShaderNode::getColorSource() const
{
#ifdef KH_DEBUG
        MString ss = "  .. gtcs ";
        if ( this && fConstructed )
                ss += name();
        ss += " ";
        for ( int ii = 0; ii < fColorSource.length(); ++ii )
        {
                ss += "\"";
                ss += fColorSource[ii];
                ss += "\" ";
        }
        ss += "\n";
        ::OutputDebugString( ss.asChar() );
#endif
        return fColorSource;
}                                      
void 
cgfxShaderNode::setDataSources( const MStringArray* texCoordSources, 
                                                            const MStringArray* colorSources)
{
        if( texCoordSources )
        {
                int length_TC = texCoordSources->length();
                if ( length_TC > CGFXSHADERNODE_GL_TEXTURE_MAX )
                        length_TC = CGFXSHADERNODE_GL_TEXTURE_MAX;
                fTexCoordSource.clear();
                for ( int i = 0; i < length_TC; ++i )
                {
                        fTexCoordSource.append( (*texCoordSources)[ i ] );
                }
                
                
                
                
                
        }
        if( colorSources )
        {
                int length_CS = colorSources->length();
                if ( length_CS > CGFXSHADERNODE_GL_COLOR_MAX )
                        length_CS = CGFXSHADERNODE_GL_COLOR_MAX;
                fColorSource.setLength( length_CS );
                for ( int i = 0; i < length_CS; ++i )
                        fColorSource[ i ] = (*colorSources)[ i ];
        }
        fDataSetNames.clear();
        fNormalsPerVertex = 1;
        updateDataSource( fTexCoordSource, fTexCoordType, fTexCoordIndex);
        updateDataSource( fColorSource, fColorType, fColorIndex);
}
void
cgfxShaderNode::updateDataSource( MStringArray& v, MIntArray& typeList, MIntArray& indexList)
{
#ifdef KH_DEBUG
        MString ss = "  .. stcs ";
        if ( this && fConstructed )
                ss += name();
        ss += " ";
        for ( int ii = 0; ii < v.length(); ++ii )
        {
                ss += "\"";
                ss += v[ii];
                ss += "\" ";
        }
        ss += "\n";
        ::OutputDebugString( ss.asChar() );
#endif
        int nDataSets = v.length();
        typeList.setLength( nDataSets );
        indexList.setLength( nDataSets );
        for ( int iDataSet = 0; iDataSet < nDataSets; ++iDataSet )
        {                                  
                MString s;
                int iType = etcNull;
                int iBuf = 0;
                
                const char* bp = v[ iDataSet ].asChar();
                const char* ep = v[ iDataSet ].length() + bp;
#ifdef _WIN32
                while ( bp < ep && *bp <= ' ' && *bp >= '\0') ++bp;
#else
                while ( bp < ep && *bp <= ' ') ++bp;
#endif
#ifdef _WIN32
                while ( bp < ep && ep[-1] <= ' ' && ep[-1] >= '\0' ) --ep;
#else
                while ( bp < ep && ep[-1] <= ' ' ) --ep;
#endif
                
                if ( bp == ep )
                        iType = etcNull;
                
                else if ( (*bp >= '0' && *bp <= '9') ||
                        *bp == '-' ||
                        *bp == '+' ||
                        *bp == '.' )
                {
                        const char* cp = bp;
                        int nValues = 0;
                        while ( cp < ep &&
                                nValues < 4 )
                        {
                                float x;
                                int   nc = 0;
                                int   nv = sscanf( cp, " %f%n", &x, &nc );
                                if ( nv != 1 )
                                        break;
                                ++nValues;
                                cp += nc;
                        }
                        if ( nValues > 0 )
                        {
                                s.set( bp, (int)(cp - bp) );      
                                for ( ; nValues < 4; ++nValues )
                                        s += " 0";  
                                iType = etcConstant;
                        }
                }
                
                else
                {
                        s.set( bp, (int)(ep - bp) );
                        
                        
                        
                        MStringArray splitStrings;      
                        #define kDefaultUVSet "map1"
                        if ((MStatus::kSuccess == s.split( ':', splitStrings)) && splitStrings.length() > 1)
                        {
                                s = splitStrings[0];
                                iBuf = findOrAppend( fDataSetNames, splitStrings[1]);
                        }
                        
                        bp = s.asChar();
                        if ( 0 == stricmp( "normal", bp ) )
                        {
                                s = "normal";
                                iType = etcNormal;
                        }
                        else if ( 0 == stricmp( "tangent", bp ) )
                        {
                                s = "tangent";
                                if( splitStrings.length() < 2)
                                {
                                        splitStrings.setLength( 2);
                                        splitStrings[ 1] = kDefaultUVSet;
                                        iBuf = findOrAppend( fDataSetNames, kDefaultUVSet);
                                }
                                s += ":" + splitStrings[1];
                                iType = etcTangent;
                                if( fNormalsPerVertex < 2)
                                        fNormalsPerVertex = 2;
                        }
                        else if ( 0 == stricmp( "binormal", bp ) )
                        {
                                s = "binormal";
                                if( splitStrings.length() < 2)
                                {
                                        splitStrings.setLength( 2);
                                        splitStrings[ 1] = kDefaultUVSet;
                                        iBuf = findOrAppend( fDataSetNames, kDefaultUVSet);
                                }
                                s += ":" + splitStrings[1];
                                iType = etcBinormal;
                                fNormalsPerVertex = 3;
                        }
                        
                        else
                        {
                                iType = etcDataSet;
                                iBuf = findOrAppend( fDataSetNames, s );
                        }
                }
                
                typeList[ iDataSet ] = iType;
                indexList[ iDataSet ] = iBuf;
                
                v[ iDataSet ] = s;
        }                                  
}                                      
const MStringArray&
cgfxShaderNode::getEmptyUVSets() const
{
        static const MStringArray saNull;
        return saNull;
}                                      
const MObjectArray&
cgfxShaderNode::getEmptyUVSetShapes() const
{
        static const MObjectArray oaNull;
        return oaNull;
}                                      
void
cgfxShaderNode::setEffect(CGeffect pNewEffect)
{
#ifdef KH_DEBUG
        char ssbuf[64];
        MString ss = "  .. se   ";
        ss += name();
        ss += " ";
        sprintf( ssbuf, "new=%X old=%X", pNewEffect, fEffect );
        ss += ssbuf;
        ss += "\n";
        ::OutputDebugString( ss.asChar() );
#endif
        if (fEffect)
                cgDestroyEffect(fEffect);
        fEffect = pNewEffect;
        fNewEffect.setEffect( fEffect);
        
        
        
        
        
        
        
        
        
        fTechniqueList.clear();
        if (fEffect)
        {
                CGtechnique cgTechnique = cgGetFirstTechnique(fEffect);
                while (cgTechnique) 
                {
                        MString s;
                        const char*             techniqueName = cgGetTechniqueName(cgTechnique);
                        if (techniqueName)
                        {
                                s += techniqueName;
                        }
                        if (cgValidateTechnique(cgTechnique) == CG_TRUE)
                        {
                                int             numPasses = 0;
                                CGpass cgPass = cgGetFirstPass(cgTechnique);
                                while (cgPass) 
                                {
                                        ++numPasses;
                                        cgPass = cgGetNextPass(cgPass);
                                }
                                s += "\t";
                                s += numPasses;
                        }
                        else
                        {
                                
                                
                                s += "\t0";
                        }
                        fTechniqueList.append(s);
                        cgTechnique = cgGetNextTechnique(cgTechnique);
                }
        }
}                                      
 bool cgfxShaderNode::hasTransparency()
{
        
        
        return false;
}
unsigned int cgfxShaderNode::transparencyOptions()
{
        if (fTechniqueHasBlending)
        {
                
                
                return ( kIsTransparent | kNoTransparencyFrontBackCull | kNoTransparencyPolygonSort );
        }
        return 0;
}
void cgfxShaderNode::setTechniqueHasBlending( CGtechnique technique)
{
        
        fTechniqueHasBlending = false;
        
        
        
        
        CGpass cgPass = cgGetFirstPass(technique);
        bool foundBlendEnabled = false;
        bool foundBlendFunc = false;
        if (cgPass) 
        {
                CGstateassignment stateAssignment = cgGetFirstStateAssignment(cgPass);
                while ( stateAssignment )
                {
                        CGstate state = cgGetStateAssignmentState( stateAssignment);
                        const char *stateName = cgGetStateName(state);
                        
                        if (!foundBlendEnabled && stricmp( stateName, "BlendEnable") == 0)
                        {
                                int numValues = 0;
                                const CGbool *values = cgGetBoolStateAssignmentValues(stateAssignment, &numValues);
                                if (values && numValues)
                                {
                                        if (values[0])
                                        {
                                                foundBlendEnabled = true;
                                        }
                                }
                        }
                        
                        else if (!foundBlendFunc && stricmp( stateName, "BlendFunc") == 0)
                        {
                                int numValues = 0;
                                const int * values = cgGetIntStateAssignmentValues(stateAssignment, &numValues);
                                if (values && numValues==2)
                                {
#if defined(CGFX_DEBUG_BLEND_FUNCTIONS)
                                        
                                        MString blendStringTable[6] = 
                                        {
                                                "GL_SRC_COLOR", 
                                                "GL_ONE_MINUS_SRC_COLOR", 
                                                "GL_SRC_ALPHA", 
                                                "GL_ONE_MINUS_SRC_ALPHA", 
                                                "GL_DST_ALPHA", 
                                                "GL_ONE_MINUS_DST_ALPHA" 
                                        };
#endif
                                        if ((values[0] >= GL_SRC_COLOR) && (values[0] <= GL_ONE_MINUS_DST_ALPHA) &&
                                            (values[1] >= GL_SRC_COLOR) && (values[1] <= GL_ONE_MINUS_DST_ALPHA) )
                                        {
#if defined(CGFX_DEBUG_BLEND_FUNCTIONS)
                                                printf("Found blend function = %s, %s\n",
                                                        blendStringTable[ values[0]-GL_SRC_COLOR].asChar(),
                                                        blendStringTable[ values[1]-GL_SRC_COLOR].asChar());
#endif
                                                foundBlendFunc = true;
                                        }
                                }
                        }
                        fTechniqueHasBlending = foundBlendEnabled && foundBlendFunc;
                        if (fTechniqueHasBlending)
                                break;
                        stateAssignment = cgGetNextStateAssignment( stateAssignment);
                }
        }
}
void
cgfxShaderNode::setTechnique( const MString& techn )
{
        
        if (!fEffect)
        {
                fTechnique = techn;
                fTechniqueHasBlending = false;
                return;
        }
        
        CGtechnique technique = cgGetNamedTechnique(fEffect, techn.asChar());
        if (cgValidateTechnique(technique) == CG_TRUE)
        {
                fTechnique = techn;  
                setTechniqueHasBlending( technique );
                
                fNewEffect.setupAttributes( this);
                return;
        }
        
        
        technique = cgGetNamedTechnique(fEffect, fTechnique.asChar());
        if (cgValidateTechnique(technique) == CG_TRUE)
        { 
                setTechniqueHasBlending( technique );
                return;
        }
        
        technique = cgGetFirstTechnique(fEffect);
        while (technique) 
        {
                if (cgValidateTechnique(technique) == CG_TRUE)
                {
                        fTechnique = cgGetTechniqueName(technique);
                        setTechniqueHasBlending( technique );
                        
                        fNewEffect.setupAttributes( this);
                        return;
                }
                technique = cgGetNextTechnique(technique);
  }
        
        
        
        fTechnique = techn;
        fTechniqueHasBlending = false;
}                                      
MStatus cgfxShaderNode::shouldSave ( const MPlug & plug, bool & ret )
{
        if (plug == sAttributeList)
        {
                ret = true;
                return MS::kSuccess;
        }
        else if (plug == sVertexAttributeList)
        {
                ret = true;
                return MS::kSuccess;
        }
        return MPxNode::shouldSave(plug, ret);
}
void cgfxShaderNode::setTexturesByName(bool texturesByName, bool updateAttributes)
{
        if( updateAttributes && fTexturesByName != texturesByName)
        {
                
                
                
                
                MDGModifier dgMod;
                cgfxAttrDefList* nodeList = attrDefList(); 
                cgfxAttrDefList::iterator nmIt;
                bool foundTextures = false;
                for (nmIt = nodeList->begin(); nmIt; ++nmIt)
                {
                        cgfxAttrDef* adef = (*nmIt);
                        if(adef->fType >= cgfxAttrDef::kAttrTypeFirstTexture && adef->fType <= cgfxAttrDef::kAttrTypeLastTexture)
                        {
                                MObject theMObject = thisMObject();
                                adef->destroyAttribute( theMObject, &dgMod);
                                foundTextures = true;
                        }
                }
                
                
                
                fTexturesByName = texturesByName;
                
                
                if( foundTextures)
                {
                        dgMod.doIt();
                        for (nmIt = nodeList->begin(); nmIt; ++nmIt)
                        {
                                cgfxAttrDef* adef = (*nmIt);
                                if( adef->fType >= cgfxAttrDef::kAttrTypeFirstTexture && adef->fType <= cgfxAttrDef::kAttrTypeLastTexture)
                                {
                                        adef->createAttribute(thisMObject(), &dgMod, this);
                                }
                        }
                        dgMod.doIt();
                        
                        
                        
                        if( fTexturesByName)
                        {
                                for (nmIt = nodeList->begin(); nmIt; ++nmIt)
                                {
                                        cgfxAttrDef* adef = (*nmIt);
                                        if( adef->fType >= cgfxAttrDef::kAttrTypeFirstTexture &&
                                                adef->fType <= cgfxAttrDef::kAttrTypeLastTexture)
                                        {
                                MObject theMObject = thisMObject();
                                                adef->setTexture( theMObject, adef->fStringDef, &dgMod);
                                        }
                                }
                        }
                }
        }
        else
        {
                fTexturesByName = texturesByName;
        }
}
MString
cgfxShaderNode::getPluginVersion()
{
        MString sVer = "cgfxShader ";
        sVer += CGFXSHADER_VERSION;       
        sVer += " for Maya ";
        sVer += (int)(MAYA_API_VERSION / 100);
        sVer += ".";
        sVer += (int)(MAYA_API_VERSION % 100 / 10);
        sVer += " (";
        sVer += __DATE__;
        sVer += ")";
        return sVer;
}                                      
void
cgfxShaderNode::reportInternalError( const char* function, size_t errcode )
{
        MString es = "cgfxShader";
        try
        {
                if ( this &&
                        fConstructed )
                {
                        if ( ++fErrorCount > fErrorLimit ) 
                                return;
                        MString s;
                        s += "\"";
                        s += name();
                        s += "\": ";
                        s += typeName();
                        es = s;
                }
        }
        catch ( ... )
        {}
        es += " internal error ";
        es += (int)errcode;
        es += " in ";
        es += function;
#ifdef KH_DEBUG
        ::OutputDebugString( es.asChar() );
        ::OutputDebugString( "\n" );
#endif
        MGlobal::displayError( es );
}                                      
void
cgfxShaderNode::cgErrorCallBack()
{
        MGlobal::displayInfo(__FUNCTION__);
        CGerror cgLastError = cgGetError();
        if(cgLastError)
        {
                MGlobal::displayError(cgGetErrorString(cgLastError));
                MGlobal::displayError(cgGetLastListing(sCgContext));
        }
}                                                                                                                                                        
void
cgfxShaderNode::cgErrorHandler(CGcontext cgContext, CGerror cgError, void* userData)
{
        MGlobal::displayError(cgGetErrorString(cgError));
        MGlobal::displayError(cgGetLastListing(sCgContext));
}