/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *
 *   This file is part of
 *       _______   ______________  ______     _____
 *      / ____/ | / /  _/ ____/  |/  /   |   |__  /
 *     / __/ /  |/ // // / __/ /|_/ / /| |    /_ <
 *    / /___/ /|  // // /_/ / /  / / ___ |  ___/ /
 *   /_____/_/ |_/___/\____/_/  /_/_/  |_| /____/.
 *
 *   Copyright © 2003-2010 Brain Control, all rights reserved.
 *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#ifndef GRAPHICS_API_DX11_HPP
#define GRAPHICS_API_DX11_HPP

#ifdef eDEBUG
#define eShaderSource const eString &
#else
#define eShaderSource const eShaderByteCode &
#endif

struct eShaderByteCode
{
    eShaderByteCode(eConstPtr d, eU32 l) 
    {
        data = d;
        length = l;
    }

    eConstPtr data;
    eU32 length;
};

enum eClearMode
{
    eCLEAR_COLORBUFFER   = 0x01,
    eCLEAR_DEPTHBUFFER   = 0x02,
    eCLEAR_STENCILBUFFER = 0x04,
    eCLEAR_ALLBUFFERS    = eCLEAR_COLORBUFFER | eCLEAR_DEPTHBUFFER | eCLEAR_STENCILBUFFER,
    eCLEAR_DEPTHCOLOR    = eCLEAR_COLORBUFFER | eCLEAR_DEPTHBUFFER
};

enum eCullingMode
{
    eCULLING_NONE,
    eCULLING_FRONT,
    eCULLING_BACK
};

enum eZFunction
{
    eZFUNC_NEVER,
    eZFUNC_LESS,
    eZFUNC_EQUAL,
    eZFUNC_LESSEQUAL,
    eZFUNC_GREATER,
    eZFUNC_NOTEQUAL,
    eZFUNC_GREATEREQUAL,
    eZFUNC_ALWAYS
};

enum eBlendMode
{
    eBLEND_ZERO,
    eBLEND_ONE,
    eBLEND_SRCCOLOR,
    eBLEND_INVSRCCOLOR,
    eBLEND_SRCALPHA,
    eBLEND_INVSRCALPHA,
    eBLEND_DSTALPHA,
    eBLEND_INVDSTALPHA,
    eBLEND_DSTCOLOR,
    eBLEND_INVDSTCOLOR,
};

enum eBlendOp
{
    eBLENDOP_ADD,
    eBLENDOP_SUB,
    eBLENDOP_INVSUB,
    eBLENDOP_MIN,
    eBLENDOP_MAX
};

enum eRenderCap
{
    eCAP_BLENDING,
    eCAP_ZBUFFER,
    eCAP_ZWRITE,
    eCAP_COLORWRITE,
    eCAP_SCISSORTEST,

    eMAX_CAP_COUNT
};

enum eTextureType
{
    eTEXTURE_2D,
    eTEXTURE_3D,
    eTEXTURE_CUBE
};

enum eTextureFilter
{
    eTEXFILTER_NEAREST,
    eTEXFILTER_BILINEAR,
    eTEXFILTER_TRILINEAR,
};

enum eTextureAddressMode
{
    eTEXADDRMODE_WRAP,
    eTEXADDRMODE_CLAMP,
    eTEXADDRMODE_MIRROR,
};

enum eFormat
{
    eFORMAT_ARGB8,
    eFORMAT_ARGB16,
    eFORMAT_ARGB16F,
    eFORMAT_DEPTH16,
    eFORMAT_DEPTH24X8,
    eFORMAT_R16F,
    eFORMAT_R32F,
    eFORMAT_GR16F,
    eFORMAT_GR32F
};

enum ePrimitiveType
{
    ePRIMTYPE_TRIANGLELIST,
    ePRIMTYPE_TRIANGLESTRIPS,
    ePRIMTYPE_LINESTRIPS,
    ePRIMTYPE_LINELIST,
};

enum eMessage
{
    eMSG_BUSY,
    eMSG_IDLE,
    eMSG_QUIT
};

enum eShaderConst
{
    // Vertex shader constants
    eVSCONST_LIGHT_VIEWPOS      = 0,
    eVSCONST_LIGHT_WORLDPOS     = 1,
    eVSCONST_LIGHT_INVRANGE     = 2,

    eVSCONST_CAMERA_WORLDPOS    = 3,

    eVSCONST_VIEW_MATRIX        = 4,
    eVSCONST_PROJ_MATRIX        = 8,
    eVSCONST_MVP_MATRIX         = 12,

    // Pixel shader constants
    ePSCONST_LIGHT_VIEWPOS      = 0,
    ePSCONST_LIGHT_WORLDPOS     = 1,
    ePSCONST_LIGHT_INVRANGE     = 2,
    ePSCONST_LIGHT_PENUMBRA     = 3,
    ePSCONST_LIGHT_SHADOWBIAS   = 4,

    ePSCONST_LIGHT_DIFFUSE      = 5,
    ePSCONST_LIGHT_TOTALAMBIENT = 6,
    ePSCONST_LIGHT_SPECULAR     = 7,

    ePSCONST_MAT_REFRACTION     = 8,
    ePSCONST_MAT_REFRINTENSITY  = 9, 
    ePSCONST_MAT_DIFFUSE        = 10,
    ePSCONST_MAT_SPECULAR       = 11,
    ePSCONST_MAT_SHININESS      = 12,
    ePSCONST_MAT_INDEX          = 13,

    ePSCONST_SHADOW_PROJZ       = 14,
    ePSCONST_SHADOW_MAP_SIZE    = 15,

    eSHADER_CONSTANT_COUNT      = 32
};

enum eVertexType
{
    eVTXTYPE_DEFAULT,
    eVTXTYPE_PARTICLE,
    eVTXTYPE_INSTANCE,

    eVTXTYPE_COUNT
};

enum eBufferLock
{
    eLOCK_DEFAULT,
    eLOCK_DISCARD,
    eLOCK_NOOVERWRITE,

    eBUFFERLOCK_COUNT
};

enum eCubeMapFace
{
    eCMFACE_POSX,
    eCMFACE_NEGX,
    eCMFACE_POSY,
    eCMFACE_NEGY,
    eCMFACE_POSZ,
    eCMFACE_NEGZ,
    eCMFACE_COUNT
};

// Render API related structures.

struct eViewport
{
    eU32                        x;
    eU32                        y;
    eU32                        width;
    eU32                        height;
};

struct eRenderStats
{
    eU32                        batches;
    eU32                        triangles;
    eU32                        vertices;
    eU32                        lines;
    eF32                        fps;
    eF32                        gpuTimeMs;
};

class eTexture3dDx11;
class eTexture2dDx11;
class eTextureCubeDx11;
class eVertexShaderDx11;
class ePixelShaderDx11;
class eComputeShaderDx11;
class eHullShaderDx11;
class eDomainShaderDx11;
class eGeometryShaderDx11;
class eIndexBufferDx11;
class eVertexBufferDx11;
class eConstantBufferDx11;
class eTextureDx11;
class eShaderDx11;
class eStateDx11;
class eDepthStencilStateDx11;
class eRasterizerStateDx11;
class eBlendStateDx11;
class eSamplerStateDx11;
class eInputLayoutDx11;

struct ID3D11Device;
struct ID3D11Buffer;
struct ID3D11Query;
struct ID3D11DeviceContext;
struct ID3D11RenderTargetView;
struct ID3D11Texture2D;
struct ID3D11DepthStencilState;
struct ID3D11DepthStencilView;
struct ID3D11RasterizerState;
struct ID3D11BlendState;
struct ID3D11SamplerState;
struct ID3D11InputLayout;
struct ID3D11ShaderResourceView;
struct ID3D11Resource;
struct ID3D11DeviceChild;

struct D3D11_MAPPED_SUBRESOURCE;

enum DXGI_FORMAT;

struct IDXGIFactory;
struct IDXGIFactory1;
struct IDXGIAdapter;
struct IDXGIAdapter1;
struct IDXGIOutput;
struct IDXGISwapChain;

class eGraphicsApiDx11
{
public:
    enum
    {
        MAX_TEX_UNITS           = 10,
		MAX_VERTEX_BUFFERS		= 8,
        MAX_TARGETS             = 4
    };

    static eTexture2d *        TARGET_SCREEN;

public:
    eGraphicsApiDx11();
#ifdef eEDITOR
    virtual                     ~eGraphicsApiDx11();
    void                        shutdown();
#endif
    eBool                       initialize();
    eBool                       openWindow(eU32 width, eU32 height, eBool fullScreen=eFALSE, eBool vsync=eTRUE, ePtr hwnd=eNULL);
    void                        closeWindow();
    void                        setWindowTitle(const eString &title);
    void                        handleMessages(eMessage &msg);
    void                        resizeBackbuffer(eU32 width, eU32 height);
    void                        clear(eClearMode mode, const eColor &color) const;
    void                        renderStart();
    void                        renderEnd();

    ID3D11Device *              getDevice() const;
    eBool                       getInitialized() const;
    eU32                        getResolutionCount() const;
    const eSize &               getResolution(eU32 index) const;
    eRenderStats                getRenderStats() const;
    eBool                       getFullScreen() const;
    eU32                        getWindowWidth() const;
    eU32                        getWindowHeight() const;
    eSize                       getWindowSize() const;

    void                        setViewport(eU32 x, eU32 y, eU32 width, eU32 height);
    void                        setScissorRect(eRect rect);
    void                        setRenderTargets(eU32 numRenderTargets, eITexture **renderTargets, eCubeMapFace *cubeFaces, eTexture2d *depthStencilTarget);
    void                        setVertexBuffers(eU32 count, eVertexBuffer **buffers, eU32 *offsets, eInputLayout &inputLayout);
    void                        setIndexBuffer(eIndexBuffer *ib);
	void						setPSConstantBuffer(eConstantBufferDx11 *buffer);
	void						setVSConstantBuffer(eConstantBufferDx11 *buffer);
    void                        setShader(eShader *s);
    void                        setTextures(eU32 count, eITexture **tex);
    void                        setState(eU32 index, eState &state);

    void                        drawPrimitives(ePrimitiveType type, eU32 startVertex, eU32 primitiveCount);
    void                        drawIndexedPrimitives(ePrimitiveType type, eU32 startVertex, eU32 vertexCount, eU32 startIndex, eU32 primitiveCount, eU32 instanceCount);

    eVertexShader *             createVertexShader(eShaderSource data) const;
    ePixelShader *              createPixelShader(eShaderSource data) const;
	eGeometryShader *           createGeometryShader(eShaderSource data) const;
	eHullShader *               createHullShader(eShaderSource data) const;
	eDomainShader *             createDomainShader(eShaderSource data) const;
	eComputeShader *            createComputeShader(eShaderSource data) const;
    eInputLayout *              createInputLayout(eVertexType type, eShader *shader) const;
    eVertexBuffer *             createVertexBuffer(eU32 count, eU32 vertexSize, eBool dynamic) const;
    eIndexBuffer *              createIndexBuffer(eU32 indexCount, eBool dynamic) const;
    eTexture2d *                createTexture2d(eU32 width, eU32 height, const ePtr data, eBool renderTarget, eBool mipMapped, eBool dynamic, eFormat format) const;
    eTexture3d *                createTexture3d(eU32 width, eU32 height, eU32 depth, eBool mipMapped, eBool dynamic, eFormat format);
    eTextureCube *              createTextureCube(eU32 width, eBool renderTarget, eBool mipMapped, eBool dynamic, eFormat format) const;
    eTexture2d *                createChessTexture(eU32 width, eU32 height, eU32 step, const eColor &col0, const eColor &col1) const;

#ifndef eINTRO
    eBool                       loadImage(const eByteArray &fileData, eColor *&image, eU32 &width, eU32 &height) const;
#endif

private:
    eF32                        _getFpsRate() const;
    ePtr                        _createWindow(eU32 width, eU32 height, eBool fullScreen);
    eBool                       _createDeviceAndSwapChain();
    eBool                       _createRenderTargetView();
    eBool                       _createDepthStencilView();

private:
    static const eChar          WINDOW_TITLE[];
    static const int            FRAMES = 2;

    eBool                       m_startPull;
    eU32                        m_frame;
    eRenderStats                m_renderStats;
    eU32                        m_videoCardMemory;
    IDXGIFactory1*              m_dxgiFactory;
    IDXGIAdapter1*              m_adapter;
    IDXGIOutput*                m_adapterOutput;
    IDXGISwapChain*             m_swapChain;
    ID3D11Device*               m_device;
    ID3D11DeviceContext*        m_deviceContext;
    ID3D11RenderTargetView*     m_renderTargetView;
    ID3D11Texture2D*            m_depthStencilBuffer;
    ID3D11DepthStencilView*     m_depthStencilView;

    ID3D11DepthStencilView *    m_activeDepthStencilView;
    ID3D11RenderTargetView *    m_activeRenderTargetView[MAX_TARGETS];

    eSizeArray                  m_resolutions;
    eBool                       m_deviceLost;
    ePtr                        m_hwnd;
    eBool                       m_ownWindow;
    eBool                       m_fullScreen;
    eBool                       m_vsync;
    eU32                        m_wndWidth;
    eU32                        m_wndHeight;
};

#endif // GRAPHICS_API_DX9_HPP