/*==========================================================================;
 *
 *  Copyright (C) 1995-2000 Microsoft Corporation.  All Rights Reserved.
 *
 *  File:   vstream.h
 *  Content:    Direct3D Vertex Streams header
 *
 *
 ***************************************************************************/
#ifndef _VSTREAM_H
#define _VSTREAM_H

//---------------------------------------------------------------------
// Constants
//---------------------------------------------------------------------
const DWORD RD_MAX_NUMELEMENTS = 16;
const DWORD RD_MAX_NUMSTREAMS  = RD_MAX_NUMELEMENTS;
const DWORD RDVSD_STREAMTESS = RD_MAX_NUMSTREAMS;
const DWORD RD_MAX_SHADERINSTSTRING = 128;
const DWORD RD_MAX_SHADERTOKENSPERINST = 32;

//---------------------------------------------------------------------
// macros for parsing Declaration Token Array

// TRUE, if shader handle is DX7 FVF code
//---------------------------------------------------------------------
#define RDVSD_ISLEGACY(ShaderHandle) !(ShaderHandle & D3DFVF_RESERVED0)

enum RDVSD_DATALOAD
{
    RDVSD_LOADREGISTER = 0,
    RDVSD_SKIP
};

#define RDVSD_GETTOKENTYPE(token)           \
    ((token & D3DVSD_TOKENTYPEMASK) >> D3DVSD_TOKENTYPESHIFT)
#define RDVSD_ISSTREAMTESS(token)           \
    ((token & D3DVSD_STREAMTESSMASK) >> D3DVSD_STREAMTESSSHIFT)
#define RDVSD_GETDATALOADTYPE(token)        \
    ((token & D3DVSD_DATALOADTYPEMASK) >> D3DVSD_DATALOADTYPESHIFT)
#define RDVSD_GETDATATYPE(token)            \
    ((token & D3DVSD_DATATYPEMASK) >> D3DVSD_DATATYPESHIFT)
#define RDVSD_GETSKIPCOUNT(token)           \
    ((token & D3DVSD_SKIPCOUNTMASK) >> D3DVSD_SKIPCOUNTSHIFT)
#define RDVSD_GETSTREAMNUMBER(token)        \
    ((token & D3DVSD_STREAMNUMBERMASK) >> D3DVSD_STREAMNUMBERSHIFT)
#define RDVSD_GETVERTEXREG(token)           \
    ((token & D3DVSD_VERTEXREGMASK) >> D3DVSD_VERTEXREGSHIFT)
#define RDVSD_GETVERTEXREGIN(token)         \
    ((token & D3DVSD_VERTEXREGINMASK) >> D3DVSD_VERTEXREGINSHIFT)
#define RDVSD_GETCONSTCOUNT(token)          \
    ((token & D3DVSD_CONSTCOUNTMASK) >> D3DVSD_CONSTCOUNTSHIFT)
#define RDVSD_GETCONSTADDRESS(token)        \
    ((token & D3DVSD_CONSTADDRESSMASK) >> D3DVSD_CONSTADDRESSSHIFT)
#define RDVSD_GETCONSTRS(token)             \
    ((token & D3DVSD_CONSTRSMASK) >> D3DVSD_CONSTRSSHIFT)
#define RDVSD_GETEXTCOUNT(token)            \
    ((token & D3DVSD_EXTCOUNTMASK) >> D3DVSD_EXTCOUNTSHIFT)
#define RDVSD_GETEXTINFO(token)             \
    ((token & D3DVSD_EXTINFOMASK) >> D3DVSD_EXTINFOSHIFT)

//---------------------------------------------------------------------
//
// RDVElement: Describes a vertex element
//
//---------------------------------------------------------------------

// Function pointer that copies a vertex element into the 4-float vector.
typedef void (*PFN_RDCOPYELEMENT)(LPVOID pInputStream,
                                  RDVECTOR4* pVertexRegister);

class RDVElement
{
public:
    RDVElement()
    {
        memset( this, 0, sizeof( RDVElement ) );
    }

    // Pointer to a function to convert input vertex element data type to
    // the RDVECTOR4
    PFN_RDCOPYELEMENT  m_pfnCopy;
    DWORD   m_dwToken;       // The token that described this vertex element.
    DWORD   m_dwRegister;    // Input register index
    DWORD   m_dwDataType;    // Data type and dimension
    DWORD   m_dwStreamIndex; // API stream index
    DWORD   m_dwOffset;      // Offset in the input stream in bytes

    //
    // Tesselator support
    //
    BOOL    m_bIsTessGen;     // Is this vertex element generated by
                              // tesselator
    DWORD   m_dwRegisterIn;   // Tesselator Input register index
    DWORD   m_dwStreamIndexIn;// API stream index for m_dwRegisterIn
    DWORD   m_dwOffsetIn;     // Offset for m_dwRegisterIn in bytes

};

//---------------------------------------------------------------------
//
// RDVConstantData: Constant data that is used by a shader
//
//---------------------------------------------------------------------
class RDVConstantData: public RDListEntry
{
public:
    RDVConstantData()     {m_pData = NULL; m_dwCount = 0;}
    ~RDVConstantData()    {delete m_pData;}

    DWORD   m_dwCount;          // Number of 4*DWORDs to load
    DWORD   m_dwAddress;        // Start constant register
    DWORD*  m_pData;            // Data. Multiple of 4*DWORD
};
//-----------------------------------------------------------------------------
//
//  RDVStream: Class representing the vertex stream.
//
//-----------------------------------------------------------------------------
class RDVStream
{
public:
    RDVStream()
    {
        m_pData = NULL;
        m_pSavedData = NULL;
        m_dwHandle = 0;
        m_dwNumVertices = 0;
        m_dwSize = 0;
    }

    // Stream memory.
    LPBYTE  m_pData;
    // Temporary pointer
    LPBYTE  m_pSavedData;
    // Vertex buffer handle
    DWORD                   m_dwHandle;
    // Vertex (or index) stride in bytes
    DWORD                   m_dwStride;
    // Max number of vertices (or indices in case of index buffer) the buffer
    // can store
    DWORD                   m_dwNumVertices;
    // Buffer size in bytes
    DWORD                   m_dwSize;
    // Output array for a tessellator
    GArrayT<BYTE>           m_TessOut;
};
//-----------------------------------------------------------------------------
//
//  RDIStream: Class representing the current Index stream
//
//-----------------------------------------------------------------------------
class RDIStream: public RDVStream
{
public:
    RDIStream()
    {
        m_dwFlags = 0;
    }
    DWORD   m_dwFlags;      // User passed flags
};
//---------------------------------------------------------------------
//
// RDVStreamDecl:
//
//      Describes a stream, used by a declaration
//
//---------------------------------------------------------------------
class RDVStreamDecl
{
public:
    RDVStreamDecl();

    // Parses declaration.
    // For fixed-function pipeline computes FVF and FVF2 (used to record
    // texture presence)
    HRESULT Parse(DWORD ** ppToken, BOOL bFixedFunction, BOOL bStreamTess,
                  UINT64* pqwFVF, UINT64* pqwFVF2, DWORD* pdwNumBetas);
    HRESULT MakeVElementArray( UINT64 qwFVF );
    RDVElement  m_Elements[RD_MAX_NUMELEMENTS];  // Vertex elements in the
                                                // stream.
    DWORD       m_dwNumElements;                // Number of elements to use
    DWORD       m_dwStride;                     // Vertex size in bytes
    DWORD       m_dwStreamIndex;                // Index to device streams
    BOOL        m_bIsStreamTess;                // Is it a tesselator stream ?
};
//---------------------------------------------------------------------
//
// RDVShaderInst:
//     The object representing each shader instruction.  Used for
//     debugging, since the reference implementation directly interprets
//     the raw token stream during vshader execution.
//-----------------------------------------------------------------------------
class RDVShaderInst
{
public:
    char    m_String[RD_MAX_SHADERINSTSTRING];
    DWORD   m_Tokens[RD_MAX_SHADERTOKENSPERINST];
    DWORD*  m_pComment;
    DWORD   m_CommentSize;
};
//---------------------------------------------------------------------
//
// RDVShaderCode:
//     The object representing the compiled shader code.
//     In the reference implementation, there is really no compiling
//     happening. The compile phase consists of:
//           1) Validating the the code.
//           2) Computing the output FVF.
//           3) Saving the original bits for later interpretation.
//    In the execution phase (in the RefVM) these saved bits are
//    interpreted.
//-----------------------------------------------------------------------------
class RDVShaderCode
{
public:
    RDVShaderCode() { memset( this, 0, sizeof( this ) ); }
    ~RDVShaderCode(){ delete m_pRawBits; if (m_pInst) delete m_pInst; }
    inline UINT GetInstructionCount( void ) { return m_InstCount; }

    LPDWORD      m_pRawBits;      // Raw code bits
    DWORD        m_dwSize;        // Number of DWORDs

    UINT         m_InstCount;     // Instruction count (for debug monitor)
    RDVShaderInst*   m_pInst;     // Instruction array (for debug monitor)

    // Output FVF for this shaders
    UINT64 m_qwFVFOut;
};
//---------------------------------------------------------------------
//
// RDVDeclaration:
//     The object representing the parsed and compiled declaration.
//-----------------------------------------------------------------------------
class RDVDeclaration
{
public:
    RDVDeclaration()
    {
        memset( this, 0, sizeof( RDVDeclaration ) );
    }
    ~RDVDeclaration();
    HRESULT Parse( DWORD * decl, BOOL bFixedFunction );
    HRESULT MakeVElementArray( UINT64 qwFVF );

    // List of streams, which are used by the declaration
    // The additional one is used for the Tesselator stream.
    RDVStreamDecl   m_StreamArray[RD_MAX_NUMSTREAMS + 1];

    // Number of active streams
    DWORD           m_dwNumActiveStreams;

    // Corresponding FVF for fixed-function pipeline
    // This is OR of all streams input FVF
    UINT64          m_qwInputFVF;

    // Constant data that should be loaded when shader becomes active
    RDVConstantData* m_pConstants;

    // The description of all vertex elements to be loaded into input
    // registers. The array is built by going through active streams and
    // elements inside each stream
    RDVElement       m_VertexElements[RD_MAX_NUMELEMENTS];

    // Number of used members of m_VertexElements
    DWORD           m_dwNumElements;

    // Stride computed for the implicit tesselator stream
    DWORD           m_dwStreamTessStride;
};
//-----------------------------------------------------------------------------
//
// RDVShader: Vertex Shader Class
//
//-----------------------------------------------------------------------------
class RDVShader
{
public:
    RDVShader();
    ~RDVShader();
    HRESULT Initialize(DWORD* lpdwDeclaration, DWORD* lpdwFunction);

    RDVDeclaration   m_Declaration;
    RDVShaderCode*   m_pCode;

    inline BOOL IsFixedFunction()
    {
        return (m_pCode == NULL);
    }
};
typedef RDVShader *PRDVSHADER;


#endif _VSTREAM_H
