#ifndef _hlslShader_h_
#define _hlslShader_h_
#include <maya/MPxHardwareShader.h>
#include <maya/MTypeId.h> 
#include <maya/MStringArray.h> 
#include <maya/MVaryingParameter.h>
#include <maya/MUniformParameter.h>
#include <maya/MUniformParameterList.h>
#include <maya/MRenderProfile.h>
#include <maya/MHwrCallback.h>
#include <d3d9.h>
#include <d3dx9.h>
class hlslShader;
class hlslDeviceManager : public MHwrCallback 
{
public:
    typedef enum
    {
        kInvalid,
        kReset,
        kValid
    } hlslDeviceState;
    inline hlslDeviceManager( hlslShader& shader) : fShader( shader), fState( kValid) { addCallback( this); }
    ~hlslDeviceManager() { removeCallback( this); }
    virtual void deviceNew();   
    virtual void deviceLost();
    virtual void deviceReset();
    virtual void deviceDeleted();
    inline hlslDeviceState  deviceState() { return fState; }
    void resetShader();
private:
    
    void operator=( const hlslDeviceManager&) {};
protected:
    hlslDeviceState fState;
    hlslShader& fShader;
};
class hlslShader : public MPxHardwareShader
{
public:
    friend class hlslDeviceManager;
    
                        hlslShader();
    virtual void        postConstructor();
    virtual             ~hlslShader(); 
    static  void*       creator();
    static  MStatus     initialize();
    static  void        initializeNodeAttrs();
    
    virtual void        copyInternalData( MPxNode* pSrc );
    virtual bool        getInternalValueInContext( const MPlug&,
                                              MDataHandle&,
                                              MDGContext&);
    virtual bool        setInternalValueInContext( const MPlug&,
                                              const MDataHandle&,
                                              MDGContext&);
    
    virtual MStatus     render( MGeometryList& iterator);
    
    virtual unsigned int    transparencyOptions();
    
    
    virtual const MRenderProfile& profile();
    
    virtual MStatus renderSwatchImage( MImage & image );
public:
    
    void                release();
    
    
    
    
    
    static  MTypeId sId;
    
    
    static MRenderProfile sProfile;
    
    
    
    
    
    
    static  MObject sShader;
    static  MObject sTechnique;
    static  MObject sTechniques;
    static  MObject sDescription;
    static  MObject sDiagnostics;
    
protected:
    
    MStatus         setShader( const MString& shader);
    MStatus         setTechnique( const MString& technique);
    bool            passHasTranparency( D3DXHANDLE passHandle ); 
    
    hlslDeviceManager   fDeviceManager;
    void            releaseVertexDeclaration();
    
    MString         fShader;
    MString         fTechnique;
    MStringArray    fTechniques;
    
    MString         fDescription;
    MString         fDiagnostics;
    
    LPD3DXEFFECT    fD3DEffect;
    D3DXHANDLE      fD3DTechnique;
    D3DXEFFECT_DESC fD3DEffectDesc;
    D3DXTECHNIQUE_DESC fD3DTechniqueDesc;
    
    MVaryingParameter fVertexStructure;
    IDirect3DVertexDeclaration9** fD3DVertexDeclaration;
    MUniformParameterList fUniformParameters;
    bool                  fTechniqueHasBlending;
    
    void            setupUniform( D3DXHANDLE d3dParameter, const MString& prefix);
    bool            GetAnnotation( D3DXHANDLE parameter, const char* name, LPCSTR& value);
    bool            GetAnnotation( D3DXHANDLE parameter, const char* name, BOOL& value);
    MUniformParameter::DataSemantic ConvertSemantic( D3DXHANDLE parameter, D3DXPARAMETER_DESC& description);
    MUniformParameter::DataType     ConvertType( D3DXHANDLE parameter, D3DXPARAMETER_DESC& description);
    MUniformParameter::DataSemantic ConvertSpace( D3DXHANDLE parameter, D3DXPARAMETER_DESC& description, MUniformParameter::DataSemantic defaultSpace);
    
    inline hlslShader& me() { return *this; }
    
    int             fErrorCount;
    void            reportInternalError( const char* function, size_t errcode );
};
#endif