#ifndef HLSL_VERSION  
#define HLSL_VERSION  "1.0"
#endif
#define ERROR_LIMIT 20
#define MAX_SEGMENTED_BATCH_SIZE 40000
#include "hlslShader.h"
#include <maya/MGlobal.h>
#include <maya/MGeometry.h>
#include <maya/MGeometryData.h>
#include <maya/MGeometryPrimitive.h>
#include <maya/MGeometryList.h>
#include <maya/MGeometryManager.h>
#include <maya/MVaryingParameterList.h>
#include <maya/MUniformParameter.h>
#include <maya/MGlobal.h>
#include <maya/MFnTypedAttribute.h>
#include <maya/MFnStringData.h>
#include <maya/MFnStringArrayData.h>
#include <maya/MSceneMessage.h>
#include <maya/MFileIO.h>
#include <maya/MMatrix.h>
#include <maya/MFileObject.h>
#include <maya/MD3D9Renderer.h>
#include <maya/MHwrCallback.h>
#include <stdio.h>
#include <new.h> 
#include <maya/MHardwareRenderer.h>
#include <maya/MHWShaderSwatchGenerator.h>
#include <maya/MGeometryRequirements.h>
#include <maya/MHwTextureManager.h>
#include <maya/MImageFileInfo.h>
#define DEBUG_TEXTURE_CACHE(X) 
template <class T> class ObjArray
{
public:
        inline          ObjArray() : fLength( 0), fCapacity( 0), fData( NULL) {}
        inline          ~ObjArray() { if( fData) { destroy( 0, fLength); delete[] ((char*)fData); } } 
        inline int      length() const { return fLength; }
        inline void     length( int l) { if( l > fLength) { if( l > fCapacity) resize( l); create( fLength, l); } else if( l < fLength) destroy( l, fLength); fLength = l; }
        inline const T& operator[]( int i) const { return fData[ i]; }
        inline T&       operator[]( int i) { return fData[ i]; }
private:
        inline void create( int s, int e) { for( ; s < e; s++) new ((void*)(fData + s)) T; }
        inline void destroy( int s, int e) { for( ; s < e; s++) (fData + s)->T::~T(); }
        enum
        {
                MIN_ARRAY_SIZE = 4
        };
        inline void resize( int l) 
        { 
                if( l < MIN_ARRAY_SIZE) l = MIN_ARRAY_SIZE; 
                else if( l < fCapacity * 2) l = fCapacity * 2; 
                T* newData = (T*)new char[ l * sizeof( T)]; 
                if( fData) 
                { 
                        memcpy( newData, fData, fCapacity * sizeof( T)); 
                        delete[] ((char*)fData); 
                } 
                fData = newData; 
                fCapacity = l; 
        }
        int                     fLength;
        int                     fCapacity;
        T*                      fData;
};
void hlslDeviceManager::deviceNew()
{
        fState = kValid;
        
        fShader.setShader( fShader.fShader);
}
void hlslDeviceManager::deviceLost()
{
        fState = kInvalid;
        
        fShader.release();
}
void hlslDeviceManager::deviceDeleted()
{
        fState = kInvalid;
        
        fShader.release();
}
void hlslDeviceManager::deviceReset()
{
        fState = kReset;
        
}
void hlslDeviceManager::resetShader()
{
        fState = kValid;
        fShader.setShader( fShader.fShader);
        
}
struct SemanticInfo
{
        const char* Name;
        MVaryingParameter::MVaryingParameterSemantic Type;
        int                     MinElements;
        int                     MaxElements;
        BYTE            D3DType;
};
SemanticInfo gSemanticInfo[] = 
{ 
        "Position",                             MVaryingParameter::kPosition,           2, 4,           D3DDECLTYPE_FLOAT3,     
        "BlendWeight",                  MVaryingParameter::kNoSemantic,         1, 4,           D3DDECLTYPE_FLOAT4,
        "BlendIndices",                 MVaryingParameter::kNoSemantic,         1, 4,           D3DDECLTYPE_FLOAT4, 
        "Normal",                               MVaryingParameter::kNormal,                     3, 4,           D3DDECLTYPE_FLOAT3, 
        "PointSize",                    MVaryingParameter::kNoSemantic,         1, 4,           D3DDECLTYPE_FLOAT3, 
        "UV",                                   MVaryingParameter::kTexCoord,           2, 4,           D3DDECLTYPE_FLOAT2,
        "Tangent",                              MVaryingParameter::kTangent,            3, 4,           D3DDECLTYPE_FLOAT3, 
        "BiNormal",                             MVaryingParameter::kBinormal,           3, 4,           D3DDECLTYPE_FLOAT3, 
        "TesselateFactor",              MVaryingParameter::kNoSemantic,         1, 4,           D3DDECLTYPE_FLOAT4, 
        "PositionTransformed",  MVaryingParameter::kNoSemantic,         1, 4,           D3DDECLTYPE_FLOAT4, 
        "Color",                                MVaryingParameter::kColor,                      3, 4,           D3DDECLTYPE_FLOAT4, 
        "Fog",                                  MVaryingParameter::kNoSemantic,         1, 4,           D3DDECLTYPE_FLOAT4, 
        "Depth",                                MVaryingParameter::kNoSemantic,         1, 4,           D3DDECLTYPE_FLOAT4, 
        "Sample",                               MVaryingParameter::kNoSemantic,         1, 4,           D3DDECLTYPE_FLOAT4,
};
class HLSLStateManager : public ID3DXEffectStateManager
{
public:
        static HLSLStateManager sInstance;
        inline HLSLStateManager() : fShapeCullMode( MGeometryList::kCullCW), fShaderCullMode( D3DCULL_CCW) {}
        
        
        inline void shapeCullMode( MGeometryList::MCullMode cullMode, bool ignoreShaderCullMode = false) 
        { 
                fShapeCullMode = cullMode; 
                if( ignoreShaderCullMode) fShaderSetCullMode = false;
                setupCulling(); 
        }
        
        
        STDMETHOD(SetRenderState)(THIS_ D3DRENDERSTATETYPE d3dRenderState, DWORD dwValue ) 
        { 
                if( d3dRenderState == D3DRS_CULLMODE)
                {
                        fShaderCullMode = dwValue;
                        fShaderSetCullMode = true;
                        return D3D_OK;
                }
                return fD3DDevice->SetRenderState( d3dRenderState, dwValue ); 
        }
        
        inline void BeginPass( LPD3DXEFFECT effect, int pass) 
        { 
                fShaderSetCullMode = false;
                effect->BeginPass( pass); 
                setupCulling();
        }
        
        STDMETHOD(SetSamplerState)(THIS_ DWORD dwStage, D3DSAMPLERSTATETYPE d3dSamplerState, DWORD dwValue ) { return fD3DDevice->SetSamplerState( dwStage, d3dSamplerState, dwValue ); }
        STDMETHOD(SetTextureStageState)(THIS_ DWORD dwStage, D3DTEXTURESTAGESTATETYPE d3dTextureStageState, DWORD dwValue ) { return fD3DDevice->SetTextureStageState( dwStage, d3dTextureStageState, dwValue ); }
        STDMETHOD(SetTexture)(THIS_ DWORD dwStage, LPDIRECT3DBASETEXTURE9 pTexture ) { return fD3DDevice->SetTexture( dwStage, pTexture ); }
        STDMETHOD(SetVertexShader)(THIS_ LPDIRECT3DVERTEXSHADER9 pShader ) { return fD3DDevice->SetVertexShader( pShader ); }
        STDMETHOD(SetPixelShader)(THIS_ LPDIRECT3DPIXELSHADER9 pShader ) { return fD3DDevice->SetPixelShader( pShader ); }
        STDMETHOD(SetFVF)(THIS_ DWORD dwFVF ) { return fD3DDevice->SetFVF( dwFVF ); }
        STDMETHOD(SetTransform)(THIS_ D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX *pMatrix ) { return fD3DDevice->SetTransform( State, pMatrix ); }
        STDMETHOD(SetMaterial)(THIS_ CONST D3DMATERIAL9 *pMaterial ) { return fD3DDevice->SetMaterial( pMaterial ); }
        STDMETHOD(SetLight)(THIS_ DWORD Index, CONST D3DLIGHT9 *pLight ) { return fD3DDevice->SetLight( Index, pLight ); }
        STDMETHOD(LightEnable)(THIS_ DWORD Index, BOOL Enable ) { return fD3DDevice->LightEnable( Index, Enable ); }
        STDMETHOD(SetNPatchMode)(THIS_ FLOAT NumSegments ) { return fD3DDevice->SetNPatchMode( NumSegments ); }
        STDMETHOD(SetVertexShaderConstantF)(THIS_ UINT RegisterIndex, CONST FLOAT *pConstantData, UINT RegisterCount ) { return fD3DDevice->SetVertexShaderConstantF( RegisterIndex, pConstantData, RegisterCount ); }
        STDMETHOD(SetVertexShaderConstantI)(THIS_ UINT RegisterIndex, CONST INT *pConstantData, UINT RegisterCount ) { return fD3DDevice->SetVertexShaderConstantI( RegisterIndex, pConstantData, RegisterCount ); }
        STDMETHOD(SetVertexShaderConstantB)(THIS_ UINT RegisterIndex, CONST BOOL *pConstantData, UINT RegisterCount ) { return fD3DDevice->SetVertexShaderConstantB( RegisterIndex, pConstantData, RegisterCount ); }
        STDMETHOD(SetPixelShaderConstantF)(THIS_ UINT RegisterIndex, CONST FLOAT *pConstantData, UINT RegisterCount ) { return fD3DDevice->SetPixelShaderConstantF( RegisterIndex, pConstantData, RegisterCount ); }
        STDMETHOD(SetPixelShaderConstantI)(THIS_ UINT RegisterIndex, CONST INT *pConstantData, UINT RegisterCount ) { return fD3DDevice->SetPixelShaderConstantI( RegisterIndex, pConstantData, RegisterCount ); }
    STDMETHOD(SetPixelShaderConstantB)(THIS_ UINT RegisterIndex, CONST BOOL *pConstantData, UINT RegisterCount ) { return fD3DDevice->SetPixelShaderConstantB( RegisterIndex, pConstantData, RegisterCount ); }
        STDMETHOD(QueryInterface)(THIS_ REFIID iid, LPVOID *ppv) { if (iid == IID_IUnknown || iid == IID_ID3DXEffectStateManager) { *ppv = static_cast<ID3DXEffectStateManager*>(this); } else { *ppv = NULL; return E_NOINTERFACE; } reinterpret_cast<IUnknown*>(this)->AddRef(); return S_OK; }
        STDMETHOD_(ULONG, AddRef)(THIS) {  return 1L; }
        STDMETHOD_(ULONG, Release)(THIS) {  return 1L; }
        LPDIRECT3DDEVICE9 fD3DDevice;
protected:
        
        
        
        
        
        
        
        inline void setupCulling()
        {
                DWORD d3dCullMode = D3DCULL_NONE;
                if( !fShaderSetCullMode)
                {
                        if( fShapeCullMode == MGeometryList::kCullCW)
                                d3dCullMode = D3DCULL_CW; 
                        else if( fShapeCullMode == MGeometryList::kCullCCW)
                                d3dCullMode = D3DCULL_CCW; 
                }
                else if( fShaderCullMode == D3DCULL_CCW)
                {
                        d3dCullMode = (fShapeCullMode == MGeometryList::kCullCCW) ? D3DCULL_CCW : D3DCULL_CW; 
                }
                else if( fShaderCullMode == D3DCULL_CW)
                {
                        d3dCullMode = (fShapeCullMode == MGeometryList::kCullCCW) ? D3DCULL_CW : D3DCULL_CCW; 
                }
                fD3DDevice->SetRenderState( D3DRS_CULLMODE, d3dCullMode); 
        }
        MGeometryList::MCullMode fShapeCullMode;
        DWORD           fShaderCullMode;
        bool            fShaderSetCullMode;
};
HLSLStateManager HLSLStateManager::sInstance;
class HLSLTextureManager : public MHwrCallback
{
public:
        static HLSLTextureManager sInstance;
        HLSLTextureManager() 
        { 
                addCallback( this); 
                sceneCallbackIds[0] = MSceneMessage::addCallback( MSceneMessage::kBeforeNew, HLSLTextureManager::newSceneCallback, (void*)this); 
                sceneCallbackIds[1] = MSceneMessage::addCallback( MSceneMessage::kBeforeOpen, HLSLTextureManager::newSceneCallback, (void*)this); 
        }
        virtual ~HLSLTextureManager() { removeCallback( this); release(); for( int i = 0; i < 2; i++) MSceneMessage::removeCallback( sceneCallbackIds[ i]); }
        void bind( const MString& name, MUniformParameter& uniform, LPD3DXEFFECT d3dEffect, D3DXHANDLE d3dParameter)
        {
                
                User* user = NULL;
                for( int i = users.length(); i--; )
                {
                        if( users[ i].parameter == d3dParameter && users[ i].effect == d3dEffect)
                        {
                                user = &users[ i];
                                break;
                        }
                }
                
                if( !user && name.length() > 0)
                {
                        int idx = users.length();
                        users.length( idx + 1);
                        user = &users[ idx];
                        DEBUG_TEXTURE_CACHE( printf( "Registering user %s at %d\n", uniform.name().asChar(), (int)((long long)user)); )
                        user->parameter = d3dParameter;
                        user->effect = d3dEffect;
                        user->uniform = uniform;
                }
                
                if( user && user->texture)
                {
                        
                        Texture* texture = user->texture;
                        if( texture->name == name)
                        {
                                
                                DEBUG_TEXTURE_CACHE( printf( "Reloading %s\n", name.asChar()); )
                                if( texture->texture)
                                {
                                        texture->texture->Release();
                                        texture->texture = NULL;
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        for( int i = users.length(); i--; )
                                        {
                                                if( &users[ i] != user && users[ i].texture == texture)
                                                {
                                                        DEBUG_TEXTURE_CACHE( printf( "Breaking texture reference for shared entry %s to avoid duplicate reloads\n", users[ i].uniform.name().asChar()); )
                                                        users[ i].uniform.setDirty();
                                                        users[ i].texture = NULL;
                                                        texture->numUsers--;
                                                }
                                        }
                                }
                        }
                        else
                        {
                                decUsage( texture);
                                
                                user->texture = NULL;
                        }
                }
                
                if( user && !user->texture && name.length() > 0)
                {
                        for( int i = textures.length(); i--; )
                        {
                                if( textures[ i].name == name && textures[ i].type == uniform.type())
                                {
                                        DEBUG_TEXTURE_CACHE( printf( "Sharing %s\n", textures[ i].name.asChar()); )
                                        user->texture = &textures[ i];
                                        user->texture->numUsers++;
                                        break;
                                }
                        }
                }
                
                if( user && !user->texture && name.length() > 0)
                {
                        
                        Texture* oldMem = &textures[ 0];
                        
                        DEBUG_TEXTURE_CACHE( printf( "Creating %s\n", name.asChar()); )
                        int idx = textures.length();
                        textures.length( idx + 1);
                        
                        Texture* newMem = &textures[ 0];
                        if( oldMem != newMem)
                                for( int i = users.length(); i--; )
                                        if( users[ i].texture)
                                                users[ i].texture = (Texture*)((char*)users[ i].texture + ((char*)newMem - (char*)oldMem));
                        
                        Texture* texture = &textures[ idx];
                        texture->name = name;
                        texture->type = uniform.type();
                        texture->numUsers = 1;
                        user->texture = texture;
                }
                
                if( user && user->texture && !user->texture->texture)
                {
                        
                        MD3D9Renderer *pRenderer = MD3D9Renderer::theRenderer();
                        if (pRenderer != NULL) {
                                IDirect3DDevice9* d3dDevice = pRenderer->getD3D9Device();
                                if(d3dDevice != NULL)
                                {
                                        DEBUG_TEXTURE_CACHE( printf( "Loading %s\n", name.asChar()); )
                                                if( uniform.type() == MUniformParameter::kTypeCubeTexture)
                                                {
                                                        LPDIRECT3DCUBETEXTURE9 d3dTexture;
                                                        if( D3DXCreateCubeTextureFromFile(d3dDevice, name.asChar(), &d3dTexture) == D3D_OK)
                                                                user->texture->texture = d3dTexture;
                                                }
                                                
                                                
                                                
                                                
                                                
                                                
                                                else
                                                {
                                                        LPDIRECT3DTEXTURE9 d3dTexture;
                                                        if( D3DXCreateTextureFromFile(d3dDevice, name.asChar(), &d3dTexture) == D3D_OK)
                                                                user->texture->texture = d3dTexture;
                                                }
                                }
                        }
                }
                
                d3dEffect->SetTexture( d3dParameter, (user && user->texture) ? user->texture->texture : NULL);
        }
        
        void release( LPD3DXEFFECT effect)
        {
                for( int i = users.length(); i--; )
                {
                        if( users[ i].effect == effect)
                        {
                                DEBUG_TEXTURE_CACHE( printf( "Releasing effect usage %s\n", users[ i].uniform.name().asChar()); )
                                if( users[ i].texture) decUsage( users[ i].texture);
                                int newLength = users.length() - 1;
                                if( i != newLength)
                                        users[ i] = users[ newLength];
                                users.length( newLength);
                        }
                }
        }
        virtual void deviceNew() {}
        virtual void deviceLost() { release(); }
        virtual void deviceDeleted() { release(); }
        static void newSceneCallback( void* ptr) { ((HLSLTextureManager*)ptr)->release(); }
        struct Texture
        {
                inline                  Texture() : numUsers( 0), texture( NULL) {}
                MString                 name;
                MUniformParameter::DataType type;
                LPDIRECT3DBASETEXTURE9 texture;
                int                             numUsers;
        };
        struct User
        {
                inline                  User() : parameter( NULL), effect( NULL), texture( NULL) {}
                D3DXHANDLE              parameter;
                LPD3DXEFFECT    effect;
                MUniformParameter uniform;
                Texture*                texture;
        };
        ObjArray<Texture>       textures;
        ObjArray<User>          users;
        MCallbackId                     sceneCallbackIds[ 2];
        void            release()
        {
                DEBUG_TEXTURE_CACHE( printf( "Releasing cache with %d textures and %d users\n", textures.length(), users.length()); )
                for( int i = users.length(); i--; )
                        users[ i].uniform.setDirty();
                for( int i = textures.length(); i--; )
                        if( textures[ i].texture)
                                textures[ i].texture->Release();
                users.length( 0);
                textures.length( 0);
        }
        void            decUsage( Texture* texture)
        {
                
                if( --texture->numUsers == 0)
                {
                        
                        DEBUG_TEXTURE_CACHE( printf( "Unloading %s\n", texture->name.asChar()); )
                        if( texture->texture)
                                texture->texture->Release();
                        
                        
                        Texture* lastTexture = &textures[ textures.length() - 1];
                        if( texture != lastTexture)
                        {
                                *texture = *lastTexture;
                                for( int i = users.length(); i--; )
                                        if( users[ i].texture == lastTexture)
                                                users[ i].texture = texture;
                        }
                        
                        
                        textures.length( textures.length() - 1);
                }
                DEBUG_TEXTURE_CACHE( else printf( "Unsharing %s\n", texture->name.asChar()); )
        }
};
HLSLTextureManager HLSLTextureManager::sInstance;
bool hlslShader::GetAnnotation( D3DXHANDLE parameter, const char* name, LPCSTR& value)
{
        D3DXHANDLE d3dSemantic = fD3DEffect->GetAnnotationByName( parameter, name);
        return d3dSemantic && fD3DEffect->GetString( d3dSemantic, &value) == D3D_OK && value != NULL;
}
bool hlslShader::GetAnnotation( D3DXHANDLE parameter, const char* name, BOOL& value)
{
        D3DXHANDLE d3dSemantic = fD3DEffect->GetAnnotationByName( parameter, name);
        return d3dSemantic && fD3DEffect->GetBool( d3dSemantic, &value) == D3D_OK;
}
MUniformParameter::DataType hlslShader::ConvertType( D3DXHANDLE parameter, D3DXPARAMETER_DESC& description)
{
        MUniformParameter::DataType mtype = MUniformParameter::kTypeUnknown;
        switch( description.Type)
        {
                
                case D3DXPT_BOOL: mtype = MUniformParameter::kTypeBool; break; 
                case D3DXPT_INT: mtype = MUniformParameter::kTypeInt; break; 
                case D3DXPT_FLOAT: mtype = MUniformParameter::kTypeFloat; break; 
                case D3DXPT_STRING: mtype = MUniformParameter::kTypeString; break; 
                case D3DXPT_TEXTURE1D: mtype = MUniformParameter::kType1DTexture; break; 
                case D3DXPT_TEXTURE2D: mtype = MUniformParameter::kType2DTexture; break; 
                case D3DXPT_TEXTURE3D: mtype = MUniformParameter::kType3DTexture; break; 
                case D3DXPT_TEXTURECUBE: mtype = MUniformParameter::kTypeCubeTexture; break; 
                case D3DXPT_TEXTURE: 
                {
                        
                        
                        
                        LPCSTR textureType;
                        if( ( GetAnnotation( parameter, "TextureType", textureType) || GetAnnotation( parameter, "ResourceType", textureType)) && textureType)
                        {
                                
                                
                                         if( !stricmp( textureType, "1D")) mtype = MUniformParameter::kType1DTexture;
                                else if( !stricmp( textureType, "2D")) mtype = MUniformParameter::kType2DTexture;
                                else if( !stricmp( textureType, "3D")) mtype = MUniformParameter::kType3DTexture;
                                else if( !stricmp( textureType, "Cube")) mtype = MUniformParameter::kTypeCubeTexture;
                                else 
                                {
                                        fDiagnostics += "Unrecognised texture type semantic ";
                                        fDiagnostics += textureType;
                                        fDiagnostics += " on parameter ";
                                        fDiagnostics += description.Name;
                                        fDiagnostics += "\n";
                                }
                        }
                        if( mtype == MUniformParameter::kTypeUnknown)
                        {
                                
                                
                                
                                
                                
                                mtype = MUniformParameter::kType2DTexture;
                                fDiagnostics += "No texture type provided for ";
                                fDiagnostics += description.Name;
                                fDiagnostics += ", assuming 2D\n";
                        }
                        
                        break; 
                }
                
                
                
                
                
                
                
                
                
                default: break;
        }
        return mtype;
}
MUniformParameter::DataSemantic hlslShader::ConvertSpace( D3DXHANDLE parameter, D3DXPARAMETER_DESC& description, MUniformParameter::DataSemantic defaultSpace)
{
        MUniformParameter::DataSemantic space = defaultSpace;
        LPCSTR ann;
        if( GetAnnotation( parameter, "Space", ann) && ann)
        {
                         if( !stricmp( ann, "Object")) space = defaultSpace >= MUniformParameter::kSemanticObjectPos ? MUniformParameter::kSemanticObjectPos : MUniformParameter::kSemanticObjectDir;
                else if( !stricmp( ann, "World")) space = defaultSpace >= MUniformParameter::kSemanticObjectPos ? MUniformParameter::kSemanticWorldPos : MUniformParameter::kSemanticWorldDir;
                else if( !stricmp( ann, "View")) space = defaultSpace >= MUniformParameter::kSemanticObjectPos ? MUniformParameter::kSemanticViewPos : MUniformParameter::kSemanticViewDir;
                else if( !stricmp( ann, "Camera")) space = defaultSpace >= MUniformParameter::kSemanticObjectPos ? MUniformParameter::kSemanticViewPos : MUniformParameter::kSemanticViewDir;
                else
                {
                        fDiagnostics += "Unrecognised space ";
                        fDiagnostics += ann;
                        fDiagnostics += " on parameter ";
                        fDiagnostics += description.Name;
                        fDiagnostics += "\n";
                }
        }
        return space;
}
MUniformParameter::DataSemantic hlslShader::ConvertSemantic( D3DXHANDLE parameter, D3DXPARAMETER_DESC& description)
{
        MUniformParameter::DataSemantic msemantic = MUniformParameter::kSemanticUnknown;
        
        if( description.Semantic && *description.Semantic)
        {
                         if( !stricmp( description.Semantic, "World"))                                                          msemantic = MUniformParameter::kSemanticWorldMatrix;
                else if( !stricmp( description.Semantic, "WorldInverse"))                                               msemantic = MUniformParameter::kSemanticWorldInverseMatrix;
                else if( !stricmp( description.Semantic, "WorldInverseTranspose"))                              msemantic = MUniformParameter::kSemanticWorldInverseTransposeMatrix;
                else if( !stricmp( description.Semantic, "View"))                                                               msemantic = MUniformParameter::kSemanticViewMatrix;
                else if( !stricmp( description.Semantic, "ViewInverse"))                                                msemantic = MUniformParameter::kSemanticViewInverseMatrix;
                else if( !stricmp( description.Semantic, "ViewInverseTranspose"))                               msemantic = MUniformParameter::kSemanticViewInverseTransposeMatrix;
                else if( !stricmp( description.Semantic, "Projection"))                                                 msemantic = MUniformParameter::kSemanticProjectionMatrix;
                else if( !stricmp( description.Semantic, "ProjectionInverse"))                                  msemantic = MUniformParameter::kSemanticProjectionInverseMatrix;
                else if( !stricmp( description.Semantic, "ProjectionInverseTranspose"))                 msemantic = MUniformParameter::kSemanticProjectionInverseTransposeMatrix;
                else if( !stricmp( description.Semantic, "WorldView"))                                                  msemantic = MUniformParameter::kSemanticWorldViewMatrix;
                else if( !stricmp( description.Semantic, "WorldViewInverse"))                                   msemantic = MUniformParameter::kSemanticWorldViewInverseMatrix;
                else if( !stricmp( description.Semantic, "WorldViewInverseTranspose"))                  msemantic = MUniformParameter::kSemanticWorldViewInverseTransposeMatrix;
                else if( !stricmp( description.Semantic, "WorldViewProjection"))                                msemantic = MUniformParameter::kSemanticWorldViewProjectionMatrix;
                else if( !stricmp( description.Semantic, "WorldViewProjectionInverse"))                 msemantic = MUniformParameter::kSemanticWorldViewProjectionInverseMatrix;
                else if( !stricmp( description.Semantic, "WorldViewProjectionInverseTranspose"))msemantic = MUniformParameter::kSemanticWorldViewProjectionInverseTransposeMatrix;
                else if( !stricmp( description.Semantic, "Diffuse"))                                                    msemantic = MUniformParameter::kSemanticColor;
                else if( !stricmp( description.Semantic, "Specular"))                                                   msemantic = MUniformParameter::kSemanticColor;
                else if( !stricmp( description.Semantic, "Ambient"))                                                    msemantic = MUniformParameter::kSemanticColor;
                else if( !stricmp( description.Semantic, "Color"))                                                              msemantic = MUniformParameter::kSemanticColor;
                else if( !stricmp( description.Semantic, "Normal"))                                                             msemantic = MUniformParameter::kSemanticNormal;
                else if( !stricmp( description.Semantic, "Bump"))                                                               msemantic = MUniformParameter::kSemanticBump;
                else if( !stricmp( description.Semantic, "Environment"))                                                msemantic = MUniformParameter::kSemanticEnvironment;
                else if( !stricmp( description.Semantic, "Time"))                                                               msemantic = MUniformParameter::kSemanticTime;
                else if( !stricmp( description.Semantic, "Position"))                                                   msemantic = ConvertSpace( parameter, description, MUniformParameter::kSemanticWorldPos);
                else if( !stricmp( description.Semantic, "Direction"))                                                  msemantic = ConvertSpace( parameter, description, MUniformParameter::kSemanticViewDir);
                else 
                {
                        fDiagnostics += "Unrecognised semantic ";
                        fDiagnostics += description.Semantic;
                        fDiagnostics += " on parameter ";
                        fDiagnostics += description.Name;
                        fDiagnostics += "\n";
                }
        }
        
        if( msemantic == MUniformParameter::kSemanticUnknown)
        {
                LPCSTR sasSemantic;
                if( GetAnnotation( parameter, "SasBindAddress", sasSemantic) && *sasSemantic)
                {
                        MString str( sasSemantic);
                                 if( !stricmp( sasSemantic, "Sas.Skeleton.MeshToJointToWorld[0]"))      msemantic = MUniformParameter::kSemanticWorldMatrix;
                        else if( !stricmp( sasSemantic, "Sas.Camera.WorldToView"))                              msemantic = MUniformParameter::kSemanticViewMatrix;
                        else if( !stricmp( sasSemantic, "Sas.Camera.Projection"))                               msemantic = MUniformParameter::kSemanticProjectionMatrix;
                        else if( !stricmp( sasSemantic, "Sas.Time.Now"))                                                msemantic = MUniformParameter::kSemanticTime;
                        else if( str.rindexW( ".Position") >= 0)                                                                msemantic = ConvertSpace( parameter, description, MUniformParameter::kSemanticWorldPos);
                        else if( str.rindexW( ".Direction") >= 0 && str.rindexW( ".Direction") != str.rindexW( ".Directional")) msemantic = ConvertSpace( parameter, description, MUniformParameter::kSemanticViewDir);
                        else 
                        {
                                fDiagnostics += "Unrecognised semantic ";
                                fDiagnostics += sasSemantic;
                                fDiagnostics += " on parameter ";
                                fDiagnostics += description.Name;
                                fDiagnostics += "\n";
                        }
                }
        }
        
        if( msemantic == MUniformParameter::kSemanticUnknown)
        {
                LPCSTR sasSemantic;
                if( GetAnnotation( parameter, "SasUiControl", sasSemantic) && *sasSemantic)
                {
                                 if( !stricmp( sasSemantic, "ColorPicker"))                                                     msemantic = MUniformParameter::kSemanticColor;
                }
        }
        
        
        if( msemantic == MUniformParameter::kSemanticUnknown)
        {
                MString name( description.Name);
                if( name.rindexW( "Position") >= 0)                                                                     msemantic = ConvertSpace( parameter, description, MUniformParameter::kSemanticWorldPos);
                else if( name.rindexW( "Direction") >= 0 && name.rindexW( "Direction") != name.rindexW( "Directional")) msemantic = ConvertSpace( parameter, description, MUniformParameter::kSemanticWorldDir);
                else if( name.rindexW( "Color") >= 0 || name.rindexW( "Colour") >= 0 || name.rindexW( "Diffuse") >= 0 || name.rindexW( "Specular") >= 0 || name.rindexW( "Ambient") >= 0)
                                                                                                                                                                        msemantic = MUniformParameter::kSemanticColor;
        }
        return msemantic;
}
MTypeId     hlslShader::sId( 0xF3560C30 );
MRenderProfile hlslShader::sProfile;
MObject     hlslShader::sShader;
MObject     hlslShader::sTechnique;
MObject     hlslShader::sTechniques;
MObject     hlslShader::sDescription;
MObject     hlslShader::sDiagnostics;
#define M_CHECK(assertion)  if (assertion) ; else throw ((hlsl::InternalError*)__LINE__)
namespace hlsl
{
#ifdef _WIN32
        class InternalError;    
        
#else
        struct InternalError
        {
                char* message;
        };
        
#endif
}
hlslShader::hlslShader()
: fErrorCount( 0), fD3DEffect( NULL), fD3DTechnique( NULL), 
  fD3DVertexDeclaration( NULL), fVertexStructure( "VertexStructure", MVaryingParameter::kStructure), 
  fDeviceManager( me()),
  fTechniqueHasBlending( false )
{
}
void
hlslShader::postConstructor()
{
        
        
        
        
}
hlslShader::~hlslShader()
{
        release();
}
void hlslShader::release()
{
        releaseVertexDeclaration();
        if( fD3DEffect) 
        {
                HLSLTextureManager::sInstance.release( fD3DEffect);
                fD3DEffect->Release();
                fD3DEffect = NULL;
        }
        fD3DTechnique = NULL;
        fTechniqueHasBlending = false;
}
void hlslShader::releaseVertexDeclaration()
{
        if( fD3DVertexDeclaration) 
        {
                for( unsigned int p = 0; p < fD3DTechniqueDesc.Passes; p++)
                        if( fD3DVertexDeclaration[ p])
                                fD3DVertexDeclaration[ p]->Release();
                delete[] fD3DVertexDeclaration;
                fD3DVertexDeclaration = NULL;
        }
}
void* hlslShader::creator()
{
        return new hlslShader();
}
MStatus
hlslShader::initialize()
{
        MStatus ms;
        try
        {
                initializeNodeAttrs();
        }
        catch ( ... )
        {
                
                MGlobal::displayError( "hlslShader internal error: Unhandled exception in initialize" );
                ms = MS::kFailure;
        }
        sProfile.addRenderer( MRenderProfile::kMayaD3D);
        return ms;
}
void
hlslShader::initializeNodeAttrs()
{
        MFnTypedAttribute       typedAttr;
        MFnStringData           stringData;
        MFnStringArrayData      stringArrayData;
        MStatus                         stat, stat2;
        
        
        
        sShader = typedAttr.create("shader", "s", MFnData::kString, stringData.create(&stat2), &stat); 
        M_CHECK( stat );
        typedAttr.setInternal( true); 
        typedAttr.setKeyable( false); 
        stat = addAttribute(sShader); 
        M_CHECK( stat );
        
        
        
        sTechnique = typedAttr.create("technique", "t", MFnData::kString, stringData.create(&stat2), &stat); 
        M_CHECK( stat );
        typedAttr.setInternal( true);
        typedAttr.setKeyable( true);
        stat = addAttribute(sTechnique);
        M_CHECK( stat );
        
        
        
        sTechniques = typedAttr.create("techniques", "ts", MFnData::kStringArray, stringArrayData.create(&stat2), &stat); 
        M_CHECK( stat );
        typedAttr.setInternal( true);
        typedAttr.setKeyable( false);
        typedAttr.setStorable( false);
        typedAttr.setWritable( false);
        stat = addAttribute(sTechniques);
        M_CHECK( stat );
        
        
        sDescription = typedAttr.create("description", "desc", MFnData::kString, stringData.create(&stat2), &stat); 
        M_CHECK( stat );
        typedAttr.setKeyable( false); 
        typedAttr.setWritable( false); 
        typedAttr.setStorable( false); 
        stat = addAttribute(sDescription); 
        M_CHECK( stat );
        
        
        sDiagnostics = typedAttr.create("diagnostics", "diag", MFnData::kString, stringData.create(&stat2), &stat); 
        M_CHECK( stat );
        typedAttr.setKeyable( false); 
        typedAttr.setWritable( false); 
        typedAttr.setStorable( false); 
        stat = addAttribute(sDiagnostics); 
        M_CHECK( stat );
        
        
        
        attributeAffects( sShader, sTechniques);
        attributeAffects( sShader, sTechnique);
}
void
hlslShader::copyInternalData( MPxNode* pSrc )
{
        const hlslShader& src = *(hlslShader*)pSrc;
        fTechnique = src.fTechnique;
        fTechniqueHasBlending = src.fTechniqueHasBlending;
        setShader( src.fShader);
}
bool hlslShader::setInternalValueInContext( const MPlug& plug,
                                                                                          const MDataHandle& handle,
                                                                                          MDGContext& context)
{
        bool retVal = true;
        try
        {
                if (plug == sShader)
                {
                        setShader( handle.asString());
                }
                else if (plug == sTechnique)
                {
                        setTechnique( handle.asString());
                }
                else
                {
                        retVal = MPxHardwareShader::setInternalValue(plug, handle);
                }
        }
        catch ( ... )
        {
                reportInternalError( __FILE__, __LINE__ );
                retVal = false;
        }
        return retVal;
}
bool hlslShader::getInternalValueInContext( const MPlug& plug,
                                                                                          MDataHandle& handle,
                                                                                          MDGContext&)
{
        bool retVal = true;
        try
        {
                if (plug == sShader)
                {
                        handle.set( fShader);
                }
                else if (plug == sTechnique)
                {
                        handle.set( fTechnique);
                }
                else if (plug == sTechniques)
                {
                        handle.set( MFnStringArrayData().create( fTechniques));
                }
                else
                {
                        retVal = MPxHardwareShader::getInternalValue(plug, handle);
                }
        }
        catch ( ... )
        {
                reportInternalError( __FILE__, __LINE__ );
                retVal = false;
        }
        return retVal;
}
MStatus hlslShader::render( MGeometryList& iter)
{
        MD3D9Renderer *pRenderer = MD3D9Renderer::theRenderer();
        if (pRenderer == NULL) 
        {
                
                return MStatus::kFailure;
        }
        IDirect3DDevice9* d3dDevice = pRenderer->getD3D9Device();       
        if ( NULL == d3dDevice ) 
        {
                
                return MStatus::kFailure;       
        }
        if (fDeviceManager.deviceState() == hlslDeviceManager::kReset)
        {
                fDeviceManager.resetShader();
        }
        
        
        
        HLSLStateManager::sInstance.fD3DDevice = d3dDevice;
        if( fD3DEffect && fD3DVertexDeclaration)
        {
                UINT numPasses = 0;
                fD3DEffect->Begin( &numPasses, 0); 
                bool firstShape = true;
                for( ; !iter.isDone(); iter.next())
                {
                        
                        for( int u = fUniformParameters.length(); u--; )
                        {
                                MUniformParameter uniform = fUniformParameters.getElement( u);
                                if( uniform.hasChanged( iter))
                                {
                                        D3DXHANDLE d3dParameter = (D3DXHANDLE)uniform.userData();
                                        if( d3dParameter)
                                        {
                                                switch( uniform.type())
                                                {
                                                        case MUniformParameter::kTypeFloat: 
                                                                {
                                                                const float* data = uniform.getAsFloatArray( iter);
                                                                if( data) fD3DEffect->SetValue( d3dParameter, data, uniform.numElements() * sizeof( float));
                                                                }
                                                                break;
                                                        case MUniformParameter::kTypeInt: 
                                                                fD3DEffect->SetInt( d3dParameter, uniform.getAsInt( iter));
                                                                break;
                                                        case MUniformParameter::kTypeBool: 
                                                                fD3DEffect->SetBool( d3dParameter, uniform.getAsBool( iter));
                                                                break;
                                                        case MUniformParameter::kTypeString: 
                                                                fD3DEffect->SetString( d3dParameter, uniform.getAsString( iter).asChar());
                                                                break;
                                                        default:
                                                                if( uniform.isATexture())
                                                                        HLSLTextureManager::sInstance.bind( uniform.getAsString( iter).asChar(), uniform, fD3DEffect, d3dParameter);
                                                                break;
                                                }
                                        }
                                }
                        }
                        MGeometry& geometry = iter.geometry( MGeometryList::kNone);
                        const void* data;
                        unsigned int elements, count;
                        if( fVertexStructure.numElements() && fVertexStructure.getBuffer( geometry, data, elements, count) == MStatus::kSuccess)
                        {
                                MGeometryPrimitive primitives = geometry.primitiveArray( 0);
                                HLSLStateManager::sInstance.shapeCullMode( iter.cullMode());
                                for( UINT p = 0; p < numPasses; p++)
                                {
                                        if( !fD3DVertexDeclaration[ p]) continue;
                                        if( numPasses > 1 || firstShape) 
                                                HLSLStateManager::sInstance.BeginPass( fD3DEffect, p);
                                        else 
                                                fD3DEffect->CommitChanges(); 
                                        firstShape = false;
                                        d3dDevice->SetVertexDeclaration( fD3DVertexDeclaration[ p]); 
#ifdef MAX_SEGMENTED_BATCH_SIZE
                                        unsigned int numPrimitives = primitives.elementCount() / 3;
                                        unsigned int batchSize = numPrimitives / (numPrimitives / MAX_SEGMENTED_BATCH_SIZE + 1) + 1;
                                        for( unsigned int start = 0; start < numPrimitives; )
                                        {
                                                unsigned int end = start + batchSize;
                                                if( end > numPrimitives) end = numPrimitives;
                                                d3dDevice->DrawIndexedPrimitiveUP( D3DPT_TRIANGLELIST, 0, count, end - start, ((const unsigned int*)primitives.data()) + (start * 3), D3DFMT_INDEX32, data, elements);
                                                start = end;
                                        }
#else
                                        d3dDevice->DrawIndexedPrimitiveUP( D3DPT_TRIANGLELIST, 0, count, primitives.elementCount() / 3, primitives.data(), D3DFMT_INDEX32, data, elements);
#endif
                                        if( numPasses > 1) fD3DEffect->EndPass();
                                }
                        }
                }
                if( numPasses == 1) fD3DEffect->EndPass();
                fD3DEffect->End();
        }
        else
        {
                
                
                D3DMATERIAL9 Material;
                Material.Emissive.r = 0.0f; 
                Material.Emissive.g = 0.6f; 
                Material.Emissive.b = 0.0f; 
                Material.Emissive.a = 1.0f; 
                d3dDevice->SetMaterial( &Material);
                d3dDevice->LightEnable( 0, false);
                d3dDevice->LightEnable( 1, false);
                d3dDevice->SetFVF( D3DFVF_XYZ );
                for( ; !iter.isDone(); iter.next())
                {
                        MGeometry& geometry = iter.geometry( MGeometryList::kNone );
                        const MGeometryData position = geometry.position();
                        if( position.data())
                        {
                                
                                
                                
                                const MMatrix& mtm = iter.objectToWorldMatrix();
                                D3DXMATRIXA16 tm( (float)mtm.matrix[0][0], (float)mtm.matrix[0][1], (float)mtm.matrix[0][2], (float)mtm.matrix[0][3], 
                                                                  (float)mtm.matrix[1][0], (float)mtm.matrix[1][1], (float)mtm.matrix[1][2], (float)mtm.matrix[1][3], 
                                                                  (float)mtm.matrix[2][0], (float)mtm.matrix[2][1], (float)mtm.matrix[2][2], (float)mtm.matrix[2][3], 
                                                                  (float)mtm.matrix[3][0], (float)mtm.matrix[3][1], (float)mtm.matrix[3][2], (float)mtm.matrix[3][3]);
                                
                                d3dDevice->SetTransform( D3DTS_WORLD, &tm);
                                
                                const MMatrix& mproject = iter.projectionMatrix();
                                D3DXMATRIXA16 projection( (float)mproject.matrix[0][0], (float)mproject.matrix[0][1], (float)mproject.matrix[0][2], (float)mproject.matrix[0][3], 
                                                                  (float)mproject.matrix[1][0], (float)mproject.matrix[1][1], (float)mproject.matrix[1][2], (float)mproject.matrix[1][3], 
                                                                  (float)mproject.matrix[2][0], (float)mproject.matrix[2][1], (float)mproject.matrix[2][2], (float)mproject.matrix[2][3], 
                                                                  (float)mproject.matrix[3][0], (float)mproject.matrix[3][1], (float)mproject.matrix[3][2], (float)mproject.matrix[3][3]);
                                d3dDevice->SetTransform( D3DTS_PROJECTION, &projection );
                                const MMatrix& mview = iter.viewMatrix();
                                D3DXMATRIXA16 view( (float)mview.matrix[0][0], (float)mview.matrix[0][1], (float)mview.matrix[0][2], (float)mview.matrix[0][3], 
                                                                  (float)mview.matrix[1][0], (float)mview.matrix[1][1], (float)mview.matrix[1][2], (float)mview.matrix[1][3], 
                                                                  (float)mview.matrix[2][0], (float)mview.matrix[2][1], (float)mview.matrix[2][2], (float)mview.matrix[2][3], 
                                                                  (float)mview.matrix[3][0], (float)mview.matrix[3][1], (float)mview.matrix[3][2], (float)mview.matrix[3][3]);
                                d3dDevice->SetTransform( D3DTS_VIEW, &view );
                                HLSLStateManager::sInstance.shapeCullMode( iter.cullMode(), true);
                                MGeometryPrimitive primitives = geometry.primitiveArray( 0);
                                d3dDevice->DrawIndexedPrimitiveUP( D3DPT_TRIANGLELIST, 0, position.elementCount(), primitives.elementCount() / 3, primitives.data(), D3DFMT_INDEX32, position.data(), 3 * sizeof( float));
                        } 
                        else 
                        {
                                 MStatus::kFailure;
                        }
                }
        }
        return MStatus::kSuccess;
}
unsigned int hlslShader::transparencyOptions()
{
        if (fTechniqueHasBlending)
                return ( kIsTransparent | kNoTransparencyFrontBackCull | kNoTransparencyPolygonSort );
        return 0;
}
const MRenderProfile& hlslShader::profile() { return sProfile; }
void hlslShader::setupUniform( D3DXHANDLE d3dParameter, const MString& prefix)
{
        if( d3dParameter)
        {
                D3DXPARAMETER_DESC parameterDesc;
                fD3DEffect->GetParameterDesc( d3dParameter, ¶meterDesc);
                if( parameterDesc.Class == D3DXPC_STRUCT)
                {
                        for( unsigned int p = 0; p < parameterDesc.StructMembers; p++)
                        {
                                setupUniform( fD3DEffect->GetParameter( d3dParameter, p), prefix + MString( parameterDesc.Name) + ".");
                        }
                }
                else
                {
                        
                        if( !stricmp( parameterDesc.Semantic, "SasGlobal"))
                        {
                                LPCSTR sasDescription;
                                if( GetAnnotation( d3dParameter, "SasEffectDescription", sasDescription) && *sasDescription)
                                        fDescription += sasDescription;
                                return;
                        }
                        else if( !stricmp( parameterDesc.Name, "description") && parameterDesc.Type == D3DXPT_STRING)
                        {
                                LPCSTR Value; 
                                if( fD3DEffect->GetString( d3dParameter, &Value) == D3D_OK) 
                                        fDescription += Value;
                                return;
                        }
                        MUniformParameter::DataType type = ConvertType( d3dParameter, parameterDesc);
                        if( type != MUniformParameter::kTypeUnknown)
                        {
                                MUniformParameter::DataSemantic semantic = ConvertSemantic( d3dParameter, parameterDesc);
                                int rows = parameterDesc.Rows;
                                int columns = parameterDesc.Columns;
                                
                                
                                
                                if( semantic == MUniformParameter::kSemanticUnknown && (type == MUniformParameter::kTypeFloat || type == MUniformParameter::kTypeString))
                                {
                                        BOOL visible = true;
                                        if( GetAnnotation( d3dParameter, "SasUiVisible", visible) && !visible)
                                                return;
                                }
                                MUniformParameter uniform( prefix + parameterDesc.Name, type, semantic, rows, columns, (void*)d3dParameter);
                                switch( type)
                                {
                                        case MUniformParameter::kTypeFloat: { FLOAT Value[ 16]; if( fD3DEffect->GetFloatArray( d3dParameter, Value, 16) == D3D_OK) uniform.setAsFloatArray( Value, 16); break; }
                                        case MUniformParameter::kTypeString: { LPCSTR Value; if( fD3DEffect->GetString( d3dParameter, &Value) == D3D_OK) uniform.setAsString( MString( Value)); break; }
                                        case MUniformParameter::kTypeBool: { BOOL Value; if( fD3DEffect->GetBool( d3dParameter, &Value) == D3D_OK) uniform.setAsBool( Value ? true : false); break; }
                                        case MUniformParameter::kTypeInt: { INT Value; if( fD3DEffect->GetInt( d3dParameter, &Value) == D3D_OK) uniform.setAsInt( Value); break; }
                                        default:
                                                if( type >= MUniformParameter::kType1DTexture && type <= MUniformParameter::kTypeEnvTexture)
                                                {
                                                        LPCSTR resource;
                                                        if( GetAnnotation( d3dParameter, "ResourceName", resource) && *resource)
                                                                uniform.setAsString( findResource( MString( resource), fShader));
                                                        else if( GetAnnotation( d3dParameter, "SasResourceAddress", resource) && *resource)
                                                                uniform.setAsString( findResource( MString( resource), fShader));
                                                }
                                }
                                fUniformParameters.append( uniform);
                        }
                }
        }
}
MStatus hlslShader::setShader( const MString& shader)
{
        fDiagnostics = "";
        fDescription = "";
        fShader = shader;
        MD3D9Renderer *pRenderer = MD3D9Renderer::theRenderer();
        if (pRenderer != NULL) {
                IDirect3DDevice9* pDevice = pRenderer->getD3D9Device();
                if( pDevice )
                {
                        release();
                        fTechniques.setLength( 0);
                        LPD3DXBUFFER errors = NULL;
                        
                        
                        
                        MFileObject fileObject;
                        fileObject.setRawFullName( shader);
                        MString resolvedPath = fileObject.resolvedPath();
                        TCHAR pwd[ MAX_PATH];
                        if( resolvedPath.length() > 0)
                        {
                                ::GetCurrentDirectory( MAX_PATH, pwd);
                                ::SetCurrentDirectory( resolvedPath.asChar());
                        }
                        
                        
                        
                        
#ifndef D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY
#define D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY 0
#endif
                        if( FAILED( D3DXCreateEffectFromFile( pDevice, shader.asChar(), NULL, NULL, D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY, NULL, &fD3DEffect, &errors)) 
#ifdef D3DXSHADER_USE_LEGACY_D3DX9_31_DLL
                         && FAILED( D3DXCreateEffectFromFile( pDevice, shader.asChar(), NULL, NULL, D3DXSHADER_USE_LEGACY_D3DX9_31_DLL, NULL, &fD3DEffect, NULL))
#endif
                                )
                        {
                                fDiagnostics += "Error trying to create effect " + shader + ":\n\t";
                                if( errors)
                                        fDiagnostics += (const char*)errors->GetBufferPointer();
                                fDiagnostics += "\n";
                        }
                        else
                        {
                                if( errors)
                                        fDiagnostics += (const char*)errors->GetBufferPointer();
                                fD3DEffect->SetStateManager( &HLSLStateManager::sInstance);
                                fD3DEffect->GetDesc( &fD3DEffectDesc);
                                for( unsigned int t = 0; t < fD3DEffectDesc.Techniques; t++)
                                {
                                        D3DXHANDLE technique = fD3DEffect->GetTechnique( t);
                                        if( technique)
                                        {
#ifdef VALIDATE_TECHNIQUE_LIST
                                                if( fD3DEffect->ValidateTechnique( technique))
#endif
                                                {
                                                        D3DXTECHNIQUE_DESC techniqueDesc;
                                                        fD3DEffect->GetTechniqueDesc( technique, &techniqueDesc);
                                                        fTechniques.append( techniqueDesc.Name);
                                                }
                                        }
                                }
                        }
                        
                        if( resolvedPath.length() > 0)
                        {
                                ::SetCurrentDirectory( pwd);
                        }
                        
                        if( fD3DEffect)
                        {
                                fUniformParameters.setLength( 0);
                                for( unsigned int p = 0; p < fD3DEffectDesc.Parameters; p++)
                                {
                                        setupUniform( fD3DEffect->GetParameter( NULL, p), "");
                                }
                                setUniformParameters( fUniformParameters);
                                
                                
                                
                                MPlug( thisMObject(), sTechnique).setValue( fTechnique);
                        }
                }
        }
        
        MPlug diagnosticsPlug( thisMObject(), sDiagnostics);
        diagnosticsPlug.setValue( fDiagnostics);
        MPlug descriptionPlug( thisMObject(), sDescription);
        descriptionPlug.setValue( fDescription);
        return MS::kSuccess;
}
bool hlslShader::passHasTranparency( D3DXHANDLE d3dPass )
{
        bool hasTransparency = false;
        
        BOOL boolParameter;
        INT intParameter1, intParameter2;
        boolParameter = false;
        {
                BOOL getAnnot = GetAnnotation( d3dPass, "Zenable", boolParameter);
                
                getAnnot = GetAnnotation( d3dPass, "ZWriteEnable", boolParameter);
                
        }
        BOOL getAnnot = false;
        {
                D3DXHANDLE d3dSemantic = fD3DEffect->GetAnnotationByName( d3dPass, "AlphaBlendEnable");
                if (d3dSemantic)
                {
                        fD3DEffect->GetBool( d3dSemantic, &boolParameter);
                        getAnnot = true;
                }
        }
        
        if (getAnnot && boolParameter)
        {
                hasTransparency = true;
                {
                        D3DXHANDLE d3dSemantic = fD3DEffect->GetAnnotationByName( d3dPass, "SrcBlend");
                        if (d3dSemantic)
                                fD3DEffect->GetInt( d3dSemantic, &intParameter1);
                }
                {
                        D3DXHANDLE d3dSemantic = fD3DEffect->GetAnnotationByName( d3dPass, "DestBlend");
                        if (d3dSemantic)
                                fD3DEffect->GetInt( d3dSemantic, &intParameter2);
                }
        }                               
        return hasTransparency;
}
MStatus hlslShader::setTechnique( const MString& technique)
{
        
        releaseVertexDeclaration();
        
        
        if( fD3DEffect && fTechniques.length())
        {
                
                fD3DTechnique = fD3DEffect->GetTechniqueByName( technique.asChar());
#ifdef VALIDATE_TECHNIQUES
                if( !fD3DTechnique || !fD3DEffect->ValidateTechnique( fD3DTechnique))
#else
                if( !fD3DTechnique)
#endif
                {
                        fD3DTechnique = fD3DEffect->GetTechniqueByName( fTechnique.asChar());
#ifdef VALIDATE_TECHNIQUES
                        if( !fD3DTechnique || !fD3DEffect->ValidateTechnique( fD3DTechnique))
#else
                        if( !fD3DTechnique)
#endif
                        {
#ifdef VALIDATE_TECHNIQUES
                                if( FAILED( fD3DEffect->FindNextValidTechnique( fD3DTechnique, &fD3DTechnique)))
                                {
                                        fD3DTechnique = NULL;
                                }
#else
                                fD3DTechnique = fD3DEffect->GetTechnique( 0);
#endif
                        }
                }
                
                fD3DEffect->GetTechniqueDesc( fD3DTechnique, &fD3DTechniqueDesc);
                fTechnique = fD3DTechniqueDesc.Name;
                
                fD3DEffect->SetTechnique( fD3DTechnique);
                
                fVertexStructure.removeElements();
                fD3DVertexDeclaration = new IDirect3DVertexDeclaration9*[ fD3DTechniqueDesc.Passes];
                int offset = 0;
                for( unsigned int p = 0; p < fD3DTechniqueDesc.Passes; p++)
                {
                        D3DXHANDLE d3dPass = fD3DEffect->GetPass( fD3DTechnique, p);
#if defined(_BLENDPARSING_READY_)
                        if (p == 0)
                                fTechniqueHasBlending = passHasTranparency( d3dPass );
#endif
                        D3DXPASS_DESC passDesc;
                        fD3DEffect->GetPassDesc( d3dPass, &passDesc);
                        D3DXSEMANTIC Semantics[ MAXD3DDECLLENGTH];
                        D3DVERTEXELEMENT9 VertexElements[ MAXD3DDECLLENGTH + 1];
                        UINT NumSemantics = 0;
                        D3DXGetShaderInputSemantics( passDesc.pVertexShaderFunction, Semantics, &NumSemantics);
                        for( unsigned int s = 0; s < NumSemantics; s++)
                        {
                                const SemanticInfo& Info = gSemanticInfo[ Semantics[ s].Usage];
                                MString Name = Info.Name; 
                                if( Info.Type != MVaryingParameter::kPosition && Info.Type != MVaryingParameter::kNormal)
                                        Name += Semantics[ s].UsageIndex;
                                MVaryingParameter varying( Name, MVaryingParameter::kFloat, Info.MinElements, Info.MaxElements, Info.Type, Info.Type == MVaryingParameter::kTexCoord ? true : false);
                                fVertexStructure.addElement( varying);
                                VertexElements[ s].Stream = 0;
                                VertexElements[ s].Offset = (WORD)offset;
                                VertexElements[ s].Type = Info.D3DType;
                                VertexElements[ s].Method = D3DDECLMETHOD_DEFAULT;
                                VertexElements[ s].Usage = (BYTE)Semantics[ s].Usage;
                                VertexElements[ s].UsageIndex = (BYTE)Semantics[ s].UsageIndex;
                                offset += varying.getMaximumStride();
                        }
                        static D3DVERTEXELEMENT9 VertexElementEnd = D3DDECL_END();
                        VertexElements[ NumSemantics] = VertexElementEnd;
                        
                        
                        fD3DVertexDeclaration[p] = NULL;
                        MD3D9Renderer* pRenderer = MD3D9Renderer::theRenderer();
                        if (pRenderer != NULL) {
                                IDirect3DDevice9* d3dDevice = pRenderer->getD3D9Device();
                                if( d3dDevice) {
                                        d3dDevice->CreateVertexDeclaration( VertexElements, &fD3DVertexDeclaration[ p]);
                                }
                        }
                }
                MVaryingParameterList list;
                if( fVertexStructure.numElements() > 0)
                {
                        
                        
                        list.append( fVertexStructure);
                }
                setVaryingParameters( list);
        }
        return MS::kSuccess;
}
void hlslShader::reportInternalError( const char* function, size_t errcode )
{
        MString es = "hlslShader";
        try
        {
                if ( this )
                {
                        if ( ++fErrorCount > ERROR_LIMIT ) 
                                return;
                        MString s;
                        s += "\"";
                        s += name();
                        s += "\": ";
                        s += typeName();
                        es = s;
                }
        }
        catch ( ... )
        {}
        es += " internal error ";
        es += (int)errcode;
        es += " in ";
        es += function;
        MGlobal::displayError( es );
}                                      
void parameterRequirements(const MVaryingParameter& parameter, MGeometryRequirements& requirements)
{
        if (parameter.numElements() == 0) {
                switch( parameter.semantic())
                {
                case (MVaryingParameter::kTexCoord) :
                        requirements.addTexCoord(parameter.name());     
                        break;
                case (MVaryingParameter::kPosition) :
                        requirements.addPosition();
                        break;
                case (MVaryingParameter::kNormal) :
                        requirements.addNormal();
                        break;
                case (MVaryingParameter::kColor) :
                        requirements.addColor(parameter.name());
                        break;
                default:
                        
                        break;
                }
        }
        else {
                for (unsigned int i = 0; i < parameter.numElements(); ++i) {
                        parameterRequirements(parameter.getElement(i), requirements);
                }
        }
}
 
MStatus hlslShader::renderSwatchImage(MImage& image)
{
#if defined _USE_OPENGL_        // 
        MStatus status = MStatus::kFailure;
        
        MHardwareRenderer *pRenderer = MHardwareRenderer::theRenderer();
        if (pRenderer)
        {
                const MString& backEndStr = pRenderer->backEndString();
                
                MDagPath path;                                                  
                MGeometryRequirements requirements;
                requirements.addPosition();
                requirements.addNormal();
                requirements.addTexCoord(MString("map1"));      
                requirements.addComponentId();
                MGeometryManager::GeometricShape shape = MGeometryManager::kDefaultSphere;
                MGeometryList* geomIter = MGeometryManager::referenceDefaultGeometry(shape, requirements);
                if(geomIter == NULL) {
                        return MStatus::kFailure;
                }
                
                
                
                unsigned int width, height;
                image.getSize(width, height);
                MStatus status2 = pRenderer->makeSwatchContextCurrent( backEndStr, width, height );
                glPushAttrib(GL_ALL_ATTRIB_BITS);
                glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
                if( status2 != MS::kSuccess ) {
                        MGeometryManager::dereferenceDefaultGeometry(geomIter);
                }
                
                
                {    
                        static float  specular[] = { 0.7f, 0.7f, 0.7f, 1.0f};
                        static float  shine[] = { 100.0f };
                        static float  ambient[] = { 0.2f, 0.2f, 0.2f, 1.0f };
                        glEnable(GL_LIGHTING);
                        glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
                        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
                        glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shine);
                        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient);
                        float lightPos[4];
                        pRenderer->getSwatchLightDirection( lightPos[0], lightPos[1], lightPos[2], lightPos[3] );
                        static float default_ambient_light[]={0.4f, 0.4f, 0.4f, 1.0f};
                        static float default_diffuse_light[]={0.8f, 0.8f, 0.8f, 1.0f};
                        static float default_specular_light[]={1.0f, 1.0f, 1.0f, 1.0f};
                        glLightfv(GL_LIGHT0, GL_AMBIENT, default_ambient_light);
                        glLightfv(GL_LIGHT0, GL_DIFFUSE, default_diffuse_light);
                        glLightfv(GL_LIGHT0, GL_SPECULAR, default_specular_light);
                        glPushMatrix();
                        glLoadIdentity();
                        glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
                        glEnable(GL_LIGHT0);
                        glPopMatrix();
                }
                
                
                {
                        
                        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 );
                        
                }
                
                
                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);
                for( ; !geomIter->isDone(); geomIter->next())
                {
                        MGeometry& geometry = geomIter->geometry(MGeometryList::kNone);
                        const MMatrix& mtm = geomIter->objectToWorldMatrix();
                        glMatrixMode(GL_MODELVIEW);
                        glLoadMatrixd(mtm[0]);
                        
                        MGeometryPrimitive primitives = geometry.primitiveArray(0);
                        const MGeometryData pos = geometry.position();
                        const MGeometryData normal = geometry.normal();
                        
                        if (pos.data() != NULL && primitives.data() != NULL) {
                                glEnableClientState(GL_VERTEX_ARRAY);
                                glVertexPointer(3, GL_FLOAT, 0, (float*) pos.data());
                                if (normal.data()) {
                                        glEnableClientState(GL_NORMAL_ARRAY);
                                        glNormalPointer(GL_FLOAT, 0,  normal.data());
                                }
                                
                                bool boundTexture = false;
                                MString defaultMap("map1");
                                MGeometryData uvCoord = geometry.texCoord(defaultMap);
                                
                                for( int u = fUniformParameters.length(); u--; ){
                                        MUniformParameter uniform = fUniformParameters.getElement( u);
                                        if ( uniform.isATexture()) {
                                                
                                                if( uniform.type() == MUniformParameter::kType2DTexture) 
                                                {
                                                        
                                                        
                                                        
                                                        
                                                        bool wasDirty = uniform.hasChanged( *geomIter);
                                                        MPlug plug = uniform.getSource();
                                                        if( wasDirty) uniform.setDirty();
                                                        MImageFileInfo::MHwTextureType hwType;
                                                        if (MS::kSuccess == MHwTextureManager::glBind(plug, hwType))
                                                        {
                                                                boundTexture = true;
                                                                break;
                                                        }
                                                }
                                        }
                                }
                                if (uvCoord.data() && boundTexture) {
                                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
                                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
                                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
                                        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
                                        glTexCoordPointer(2, GL_FLOAT, 0, uvCoord.data());
                                        
                                        glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
                                }
                                else {
                                        glDisable(GL_TEXTURE_2D);
                                        glBindTexture(GL_TEXTURE_2D, 0);
                                        glColor4f(0.1f, 0.7f, 0.7f, 1.0f);
                                }
                                MGeometryPrimitive primitives = geometry.primitiveArray(0);
                                
                                glDrawElements(GL_TRIANGLES, primitives.elementCount(), GL_UNSIGNED_INT, primitives.data());
                                
                                pRenderer->readSwatchContextPixels( backEndStr, image );
                                
                                
                                image.getSize( width, height );
                                glPopAttrib();
                                glPopClientAttrib();
                                status = MStatus::kSuccess;
                        }
                }
                MGeometryManager::dereferenceDefaultGeometry(geomIter);
        }
#else
        MStatus status = MStatus::kFailure;
        unsigned int width, height;
        image.setRGBA(true);
        image.getSize(width, height);
        
        ShaderContext context;                                  
        MGeometryRequirements requirements;
        populateRequirements(context, requirements);
        MD3D9Renderer*  Render = MD3D9Renderer::theRenderer();
        if (Render != NULL) {
                Render->makeSwatchContextCurrent(width, height);
                
                Render->setBackgroundColor(MColor(0.1f, 0.1f, 0.1f));
                MGeometryList* geomIter = MGeometryManager::referenceDefaultGeometry(MGeometryManager::kDefaultSphere, 
                        requirements);
                if (geomIter == NULL) {
                        return status;
                }
                
                
                
                if (render(*geomIter) != MStatus::kSuccess) {
                        
                        
                }
                
                Render->readSwatchContextPixels(image);
                
                MGeometryManager::dereferenceDefaultGeometry(geomIter);
                status = MStatus::kSuccess;
        }
#endif
        return status;
}