#ifndef _dx11ShaderNode_h_
#define _dx11ShaderNode_h_
#include <maya/MPxHardwareShader.h>
#include <maya/MStringArray.h>
#include <maya/MVaryingParameterList.h>
#include <maya/MUniformParameterList.h>
#include <maya/MHWGeometry.h>
#include <maya/MPlugArray.h>
#include <maya/MMessage.h>
#define WIN32_LEAN_AND_MEAN
#include <d3d11.h>
#if _MSC_VER >= 1700
#include <dxgi.h>
#else
#include <d3dx11.h>
#endif
#define HAVE_D3DX11EFFECT_LIBRARY_BUILT
#if defined(HAVE_D3DX11EFFECT_LIBRARY_BUILT)
#if defined(JAMBUILD)
    #include <maya/d3dx11effect.h>
#else
    
    #include <../Samples/C++/Effects11/Inc/d3dx11effect.h>
    #ifndef USE_BOOL
    #define USE_BOOL // use BOOL instead of bool
    #endif
#endif
    #define dx11ShaderDX11Device ID3D11Device
    #define dx11ShaderDX11DeviceContext ID3D11DeviceContext
    #define dx11ShaderDX11Effect ID3DX11Effect
    #define dx11ShaderDX11EffectTechnique ID3DX11EffectTechnique
    #define dx11ShaderDX11Pass ID3DX11EffectPass
    #define dx11ShaderDX11InputLayout ID3D11InputLayout
    #define dx11ShaderDX11InputElementDesc D3D11_INPUT_ELEMENT_DESC
    #define dx11ShaderDX11EffectVariable ID3DX11EffectVariable
    #define dx11ShaderDX11EffectShaderResourceVariable ID3DX11EffectShaderResourceVariable
    #define dx11ShaderDX11RasterizerState ID3D11RasterizerState
    #define dx11ShaderDX11DepthStencilState ID3D11DepthStencilState
    #define dx11ShaderDX11BlendState ID3D11BlendState
#else
    #define dx11ShaderDX11Device void
    #define dx11ShaderDX11DeviceContext void
    #define dx11ShaderDX11Effect void
    #define dx11ShaderDX11EffectTechnique void
    #define dx11ShaderDX11Pass void
    #define dx11ShaderDX11InputLayout void
    #define dx11ShaderDX11InputElementDesc void
    #define dx11ShaderDX11EffectVariable void
    #define dx11ShaderDX11EffectShaderResourceVariable void
    #define dx11ShaderDX11RasterizerState void
    #define dx11ShaderDX11DepthStencilState void
    #define dx11ShaderDX11BlendState void
#endif
#include <map>
#include <set>
#include <vector>
class CUniformParameterBuilder;
    class MLightParameterInformation;
    class MTexture;
    class MDrawContext;
}
#define USE_GL_TEXTURE_CACHING
{
private:
    
    enum ERenderType
    {
        RENDER_SCENE,               
        RENDER_SCENE_NON_MATERIAL,  
        RENDER_SWATCH,              
        RENDER_SWATCH_PROXY,        
        RENDER_UVTEXTURE            
    };
    
    inline bool isRenderScene(ERenderType renderType) const { return (renderType == RENDER_SCENE || renderType == RENDER_SCENE_NON_MATERIAL); }
    inline bool isRenderSwatch(ERenderType renderType) const { return (renderType == RENDER_SWATCH); }
    inline bool isRenderNonMaterialItem(ERenderType renderType) const { return (renderType == RENDER_SCENE_NON_MATERIAL); }
    
    inline bool needUpdateImplicitLightConnections(ERenderType renderType) const { return (renderType == RENDER_SCENE || renderType == RENDER_SWATCH); }
    inline bool needUpdateExplicitLightConnections(ERenderType renderType) const { return (renderType == RENDER_SCENE); }
    inline bool overrideRasterizerState(ERenderType renderType) const { return !isRenderScene(renderType); }
    inline bool needUpdateMayaSwatchRenderVar(ERenderType renderType) const { return (renderType == RENDER_SWATCH || renderType == RENDER_SWATCH_PROXY); }
    struct RenderItemDesc
    {
        bool isFatLine;
        bool isFatPoint;
    };
    
public:
    enum ELightType
    {
        eInvalidLight,
        eUndefinedLight,
        eSpotLight,
        ePointLight,
        eDirectionalLight,
        eAmbientLight,
        eVolumeLight,
        eAreaLight,
        eDefaultLight,
        eLightCount
    };
    
    enum ETransparencyState
    {
        eOpaque,                
        eTransparent,           
        eTestOpacitySemantics,  
        eScriptedTest           
    };
    struct ContextStates
    {
        ContextStates() : rasterizerState(NULL), depthStencilState(NULL), blendState(NULL) {}
        dx11ShaderDX11RasterizerState*      rasterizerState;
        dx11ShaderDX11DepthStencilState*    depthStencilState;
        UINT                                stencilRef;
        dx11ShaderDX11BlendState*           blendState;
        float                               blendFactor[4];
        UINT                                sampleMask;
    };
    class LightParameterInfo
    {
        typedef dx11ShaderNode::ELightType ELightType;
    public:
        LightParameterInfo(ELightType lightType = dx11ShaderNode::eInvalidLight, bool hasLightTypeSemantics = false);
        ELightType  lightType() const;
    public:
        ELightType  fLightType;
        bool        fHasLightTypeSemantics;
        bool        fIsDirty;
        
        typedef std::map<int, int> TConnectableParameters;
        TConnectableParameters fConnectableParameters;
    };
public:
    
                        dx11ShaderNode();
    virtual             ~dx11ShaderNode();
    static  void*       creator();
    static  void        initializeNodeAttrs();
    
    
public:
    
    static  void        postDuplicateCB( void *data );
    
    
public:
    bool rebuildAlways(size_t baseVersionId) const;
    bool isDirty(size_t baseVersionId) const;
    size_t geometryVersionId() const;
private:
    bool hasUpdatedVaryingInput() const;
    void setTopoDirty();
    
public:
    static bool reloadAll(
const MString& effectName);
 
    bool reload();
    dx11ShaderDX11Effect* effect() const;
    double boundingBoxExtraScale() const;
private:
    bool loadEffect( 
const MString& effectName );
 
    bool loadFromFile( 
const MString& fileName, dx11ShaderDX11Device* dxDevice);
 
    bool loadFromBuffer( 
const MString& identifier, 
const void* pData, 
unsigned int dataSize, dx11ShaderDX11Device* dxDevice);
 
    bool initializeEffect();
    void resetData(bool clearEffect = true);
    
public:
    inline int techniqueCount() const;
    bool techniqueIsTransparent() const;
    bool techniqueSupportsAdvancedTransparency() const;
    bool techniqueOverridesDrawState() const;
    bool techniqueOverridesNonMaterialItems() const;
    bool techniqueHandlesConsolidatedGeometry() const;
    bool techniqueIsSelectable() const;
    
    bool passHandlesContext(
const MStringArray& passSemantics, 
unsigned int passIndex, ERenderType renderType, 
const RenderItemDesc* renderItemDesc = NULL) 
const;
 
    
    int activeTechnique() const;
    
    dx11ShaderDX11EffectTechnique* technique() const;
    
    const MString& activeTechniqueName() 
const;
 
    
    const MString& techniqueIndexBufferType() 
const;
 
private:
    bool initializeTechniques();
    bool setTechnique( 
const MString& techniqueName );
 
    bool setTechnique( int techniqueNumber );
    void initTechniqueParameters();
    void storeDefaultTextureNames();
    void restoreDefaultTextureNames();
    
public:
    
    int techniquePassCount() const;
private:
    dx11ShaderDX11Pass* activatePass( dx11ShaderDX11Device *dxDevice, dx11ShaderDX11DeviceContext *dxContext, dx11ShaderDX11EffectTechnique* dxTechnique, unsigned int passId, ERenderType renderType ) const;
    dx11ShaderDX11Pass* activatePass( dx11ShaderDX11Device *dxDevice, dx11ShaderDX11DeviceContext *dxContext, dx11ShaderDX11EffectTechnique* dxTechnique, 
unsigned int passId, 
const MStringArray& passSem, ERenderType renderType, 
const RenderItemDesc* renderItemDesc = NULL ) 
const;
    bool passHasHullShader(dx11ShaderDX11Pass* dxPass) const;
    dx11ShaderDX11InputLayout* getInputLayout(dx11ShaderDX11Device* dxDevice, dx11ShaderDX11Pass* dxPass, unsigned int numLayouts, const dx11ShaderDX11InputElementDesc* layoutDesc) const;
    
public:
    
    
    
    
    
private:
    typedef std::vector<const MHWRender::MRenderItem*> RenderItemList;
    
    bool renderTechnique(dx11ShaderDX11Device *dxDevice, dx11ShaderDX11DeviceContext *dxContext, dx11ShaderDX11EffectTechnique* dxTechnique,
                    const RenderItemList& renderItemList,
    bool renderPass(dx11ShaderDX11Device *dxDevice, dx11ShaderDX11DeviceContext *dxContext, dx11ShaderDX11Pass* dxPass,
                    const RenderItemList& renderItemList,
    
    bool renderTechnique(dx11ShaderDX11Device *dxDevice, dx11ShaderDX11DeviceContext *dxContext, dx11ShaderDX11EffectTechnique* dxTechnique, unsigned int numPasses,
    bool renderPass(dx11ShaderDX11Device *dxDevice, dx11ShaderDX11DeviceContext *dxContext, dx11ShaderDX11Pass* dxPass,
    
    bool renderTechnique(dx11ShaderDX11Device *dxDevice, dx11ShaderDX11EffectTechnique* dxTechnique, unsigned int numPasses,
public:
    void backupStates(dx11ShaderDX11DeviceContext *dxContext, ContextStates &states) const;
    void restoreStates(dx11ShaderDX11DeviceContext *dxContext, ContextStates &states) const;
private:
    typedef std::map< dx11ShaderDX11EffectShaderResourceVariable*, MHWRender::MTexture* > ResourceTextureMap;
    void updateOverrideNonMaterialItemParameters( 
const MHWRender::MRenderItem* item, RenderItemDesc& renderItemDesc ) 
const;
 
public:
    void updateShaderBasedGeoChanges();
    void updateLightsInformation();
private:
    typedef std::map<int, bool> TshadowFlagBackupState;
    void initShadowFlagBackupState(TshadowFlagBackupState& stateBackup ) const;
    void setPerGeometryShadowOnFlag(bool receivesShadows, TshadowFlagBackupState& stateBackup ) const;
    
public:
    void clearParameters();
private:
    
    void preBuildUniformParameterList();
    bool buildUniformParameterList();
    bool buildVaryingParameterList();
    bool buildVertexDescriptorFromVaryingParameters();
    
    void initMayaParameters();
    
public:
    int getIndexForUIGroupName(
const MString& uiGroupName, 
bool appendGroup = 
false);
 
    MString getLightConnectionInfo(
int lightIndex);
 
    MStringArray getLightableParameters(
int lightIndex, 
bool showSemantics);
 
    int getIndexForLightName(
const MString& lightName, 
bool appendLight = 
false);
 
    bool getVariableNameAsAttributeName(){ return fVariableNameAsAttributeName; }
private:
    bool appendParameterNameIfVisible(
int paramIndex, 
MStringArray& paramArray) 
const;
 
    
public:
    void refreshLightConnectionAttributes(bool inSceneUpdateNotification=false);
    void connectLight(
int lightIndex, 
MDagPath light);
 
    void disconnectLight(int lightIndex);
private:
    void refreshView() const;
    void setLightRequiresShadows(
const MObject& lightObject, 
bool requiresShadow) 
const;
 
private:
    void updateImplicitLightParameterCache(std::vector<CUniformParameterBuilder*>& builders);
    void clearLightConnectionData();
private:
    void getLightParametersToUpdate(std::set<int>& parametersToUpdate, ERenderType renderType) const;
    bool connectExplicitAmbientLight(
const LightParameterInfo& lightInfo, 
const MObject& sourceLight) 
const;
 
    void turnOffLight(const LightParameterInfo& lightInfo) const;
    void setLightParameterLocking(const LightParameterInfo& lightInfo, bool locked) const;
    
private:
    void assignTexture(dx11ShaderDX11EffectShaderResourceVariable* resourceVariable, 
const MString& textureName, 
const MString& layerName, 
int alphaChannelIdx, ResourceTextureMap& resourceTexture, 
MObject node = 
MObject()) 
const;
 
    void releaseAllTextures(ResourceTextureMap& resourceTexture) const;
    void releaseAllTextures();
  
      MString &textureName, 
MString& layerName, 
int &alphaChannelIdx, 
int &mipmapLevels);
 
public:
    bool getTextureFile(
const MString& uniformName, 
MString& textureFile) 
const;
 
    
private:
    void setParameterAsVector(int paramIndex, float* data) const;
    void setParameterAsScalar(int paramIndex, float data) const;
    void setParameterAsScalar(int paramIndex, bool data) const;
    void setParameterAsScalar(int paramIndex, int data) const;
    void setParameterAsMatrix(
int paramIndex, 
MMatrix& data) 
const;
 
    void setParameterAsResource(int paramIndex, ID3D11ShaderResourceView* inResource) const;
    void setParameterFromUniformAsVector(
int paramIndex,
const MHWRender::MDrawContext& context, 
const float *data = NULL) 
const;
 
public:
    
private:
    void displayErrorAndWarnings() const;
    void reportInternalError( const char* function, size_t errcode ) const;
    
private:
private:
    struct PassSpec
    {
        bool forFatLine;
        bool forFatPoint;
    };
    unsigned int findMatchingPass(const PassSpec& passSpecTest) const;
private:
    
    size_t                          fGeometryVersionId;
    
    bool                            fShaderChangesGeo;
    double                          fLastTime;
    bool                            fIgnoreLightLimits;
    
    bool                            fVariableNameAsAttributeName;
    
    mutable MUint64                 fLastFrameStamp;
    
    dx11ShaderNode*                 fDuplicateNodeSource;
    MCallbackId                     fPostDuplicateCallBackId;
    
    
    dx11ShaderDX11Effect*           fEffect;
    
    
    int                             fTechniqueIdx;
    
    
    dx11ShaderDX11EffectTechnique*  fTechnique;
    
    int                             fTechniqueTextureMipMapLevels;
    
    bool                            fTechniqueIsSelectable;
    ETransparencyState              fTechniqueIsTransparent;
    bool                            fTechniqueSupportsAdvancedTransparency;
    bool                            fTechniqueOverridesNonMaterialItems;
    bool                            fTechniqueHandlesConsolidatedGeometry;
    bool                            fTechniqueOverridesDrawState;
    
    
    unsigned int                    fTechniquePassCount;
    typedef std::map<unsigned int, PassSpec> PassSpecMap;
    PassSpecMap                     fTechniquePassSpecs;
    
    
    size_t                                  fVaryingParametersGeometryVersionId;
    size_t                                  fVaryingParametersUpdateId;
    
    typedef std::vector<LightParameterInfo> LightParameterInfoVec;
    LightParameterInfoVec           fLightParameters;
    mutable int                     fImplicitAmbientLight;
    std::vector<std::vector<int> >  fUIGroupParameters;
    ResourceTextureMap              fResourceTextureMap;
    mutable bool                    fForceUpdateTexture;
    int                             fFixedTextureMipMapLevels;
#ifdef USE_GL_TEXTURE_CACHING
    
    int                             fUVEditorLastAlphaChannel;
    float                           fUVEditorBaseColor[4];
    bool                            fUVEditorShowAlphaMask;
    unsigned int                    fUVEditorGLTextureId;
    float                           fUVEditorGLTextureScaleU;
    float                           fUVEditorGLTextureScaleV;
#endif //USE_GL_TEXTURE_CACHING
    
    double                          fBBoxExtraScaleValue;
    
    dx11ShaderDX11EffectVariable*   fMayaSwatchRenderVar;
    
    dx11ShaderDX11EffectVariable*   fMayaGammaCorrectVar;
    dx11ShaderDX11EffectVariable*   fMayaHwFogEnabled;
    dx11ShaderDX11EffectVariable*   fMayaHwFogMode;
    dx11ShaderDX11EffectVariable*   fMayaHwFogStart;
    dx11ShaderDX11EffectVariable*   fMayaHwFogEnd;
    dx11ShaderDX11EffectVariable*   fMayaHwFogDensity;
    dx11ShaderDX11EffectVariable*   fMayaHwFogColor;
    typedef std::map< dx11ShaderDX11Pass*, bool > PassHasHullShaderMap;
    mutable PassHasHullShaderMap    fPassHasHullShaderMap;
    struct CachedInputElementDesc
    {
        unsigned int SemanticIndex;
        int Format;
        unsigned int InputSlot;
        unsigned int AlignedByteOffset;
        int InputSlotClass;
        unsigned int InstanceDataStepRate;
    };
    struct InputLayoutData
    {
        dx11ShaderDX11InputLayout* inputLayout;
        unsigned int numLayouts;
        CachedInputElementDesc* layoutDesc;
    };
    typedef std::map< dx11ShaderDX11Pass*, InputLayoutData > PassInputLayoutMap;
    mutable PassInputLayoutMap      fPassInputLayoutMap;
    mutable unsigned int            fErrorCount;
};
inline bool dx11ShaderNode::rebuildAlways(size_t baseVersionId) const
{
    return hasUpdatedVaryingInput() || isDirty(baseVersionId);
}
inline bool dx11ShaderNode::isDirty(size_t baseVersionId) const
{
    return (fGeometryVersionId != baseVersionId);
}
inline size_t dx11ShaderNode::geometryVersionId() const
{
    return fGeometryVersionId;
}
inline const MString& dx11ShaderNode::effectName()
 const 
{
    return fEffectName;
}
inline dx11ShaderDX11Effect* dx11ShaderNode::effect() const
{
    return fEffect;
}
inline double dx11ShaderNode::boundingBoxExtraScale() const
{
    return (fBBoxExtraScaleValue > 1.0f ? fBBoxExtraScaleValue : 1.0f);
}
inline const MStringArray& dx11ShaderNode::techniques()
 const 
{
    return fTechniqueNames;
}
inline int dx11ShaderNode::techniqueCount() const
{
    return (
int)fTechniqueNames.
length();
 
}
inline int dx11ShaderNode::activeTechnique() const
{
    return fTechniqueIdx;
}
inline dx11ShaderDX11EffectTechnique* dx11ShaderNode::technique() const
{
    return fTechnique;
}
inline const MString& dx11ShaderNode::activeTechniqueName()
 const 
{
    return fTechniqueName;
}
inline const MString& dx11ShaderNode::techniqueIndexBufferType()
 const 
{
    return fTechniqueIndexBufferType;
}
inline bool dx11ShaderNode::techniqueOverridesDrawState() const
{
    return fTechniqueOverridesDrawState;
}
inline bool dx11ShaderNode::techniqueSupportsAdvancedTransparency() const
{
    return fTechniqueSupportsAdvancedTransparency;
}
inline bool dx11ShaderNode::techniqueOverridesNonMaterialItems() const
{
    return fTechniqueOverridesNonMaterialItems;
}
inline bool dx11ShaderNode::techniqueHandlesConsolidatedGeometry() const
{
    return fTechniqueHandlesConsolidatedGeometry;
}
inline bool dx11ShaderNode::techniqueIsSelectable() const
{
    return fTechniqueIsSelectable;
}
inline int dx11ShaderNode::techniquePassCount() const
{
    return fTechniquePassCount;
}
inline const MStringArray& dx11ShaderNode::getUIGroups()
 const 
{
    return fUIGroupNames;
}
inline const MStringArray& dx11ShaderNode::lightInfoDescription()
 const 
{
    return fLightDescriptions;
}
#endif