/***************************************************************************
 *                                                                         *
 * Module  : rppvsdef.h                                                    *
 *                                                                         *
 * Purpose : Culling of WSector                                            *
 *                                                                         *
 **************************************************************************/

#ifndef PVSDEF_H
#define PVSDEF_H

/****************************************************************************
 Includes
 */

#include "rwcore.h"
#include "rpworld.h"

/****************************************************************************
 Globals (across program)
 */
#define PVSRASTERWIDTH     128
#define PVSRASTERHEIGHT    128


#define PVSINOUT_TOL    1000.0

#define PVSENCODEID(_col, _id)                                  \
MACRO_START                                                     \
{                                                               \
    (_col)->red =   (RwUInt8) (((_id) & 0x00000f00) >> 4)+4;      \
    (_col)->green = (RwUInt8) (((_id) & 0x000000f0) >> 0)+4;      \
    (_col)->blue =  (RwUInt8) (((_id) & 0x0000000f) << 4)+4;      \
    (_col)->alpha = (RwUInt8) 255;                              \
}                                                               \
MACRO_STOP

#define PVSDECODEID(_id, _col)                  \
MACRO_START                                     \
{                                               \
    (_id) = (((_col)->red   & 0xf0) << 4) |     \
            (((_col)->green & 0xf0) >> 0) |     \
            (((_col)->blue  & 0xf0) >> 4);      \
}                                               \
MACRO_STOP


#define PVSVISMAPSETSECTOR(_vismap, _id)        \
    (_vismap)[(_id) >> 5] |= (1 << ((_id) & 31))

#define PVSVISMAPGETSECTOR(_vismap, _id)                \
    ((_vismap)[(_id) >> 5] & (1 << ((_id) & 31)))

#define PVSVISMAPGETSECTORVER2(_vismap, _id)            \
    ((_vismap)[(_id) >> 3] & (1 << ((_id) & 7)))


#define PVSCACHEFROMWORLD(world)                                          \
    ((RpPVSCache *)(((char *)(world))+rpPVSGlobals.worldOffset))        \

#define PVSCACHEFROMCONSTWORLD(world)                                     \
    ((const RpPVSCache *)(((const char *)(world))+rpPVSGlobals.worldOffset))

#define PVSFROMWORLDSECTOR(sector)                                          \
    ((RpPVS *)(((char *)(sector))+rpPVSGlobals.sectorOffset))

#define PVSFROMCONSTWORLDSECTOR(sector)                                     \
    ((const RpPVS *)(((const char *)(sector))+rpPVSGlobals.sectorOffset))

#define PVSVERSION1   1
#define PVSVERSION2   2

#define PVSVERSION    3

/* Temporary structure to support V2.0 PVS data. */
typedef struct RpPVSCacheSizeVer2 RpPVSCacheSizeVer2;
struct RpPVSCacheSizeVer2
{
        RwUInt32            version;
        RwUInt32            count;
        RwUInt32            length;
        RwUInt32            size;
        RwUInt32            subSectorDepth;
        RwUInt32            numSubSectors;
};

/* Warning! This structure must be allocated on a 4 byte boundary */
typedef struct RpPVSVer2 RpPVSVer2;
struct RpPVSVer2
{
        RwUInt32            sectorID;
        RwUInt8             x_cut, y_cut, z_cut;
        RwChar              vismap[1];
};

/* Warning! This structure must be allocated on a 4 byte boundary */
typedef struct RpPVS RpPVS;
struct RpPVS
{
        RwUInt32            sectorID;
        RwUInt8             x_segs;
        RwUInt8             y_segs;
        RwUInt8             z_segs;
        RwUInt8             pad;
        RpPVSVisMap         *vismap;        /* x_cut * y_cut * z_cut vismaps */
};



typedef struct RpPVSCacheSize RpPVSCacheSize;
struct RpPVSCacheSize
{
        RwUInt32            version;
        RwUInt32            viscount;       /* how many _vismaps_ in total */
        RwUInt32            vislen;         /* vismap length in units of RpPVSVisMap */
        RwReal              oomaxdim;       /* recip max length of a subsector edge */
};

typedef struct RpPVSCache RpPVSCache;
struct RpPVSCache
{
        RpPVSCacheSize      sectorCache;
        char               *sectorBlocks;   /* all vismaps (indicates PVS existence) */

        /* currently selected sector + (sub)vismap */
        RpWorldSector      *spCOP;
        RpPVSVisMap        *sectorVismap;

        /* pipeline hooking */
        RpWorldSectorCallBackRender fpRender;
        RwBool              hooked;

        /* stats collection */
        RwInt32             ptotal;
        RwInt32             paccept;

        /* used during vismap allocation */
        RwUInt32            nextID;
        char               *ppNext;

        /* used during construction */
        RpPVSProgressCallBack progressCallBack;
        RwInt32             maxNumVert;
        RwInt32             maxNumPoly;
        RwIm3DVertex       *im3DVert;
        RwImVertexIndex    *imVertIndex;
};

typedef struct _RpPVSCallBack _RpPVSCallBack;
struct _RpPVSCallBack
{
        RpPVSCallBack       callback;
        void               *pData;
};

typedef struct rpPVSGlobalVars RpPVSGlobalVars;
struct rpPVSGlobalVars
{
    RwInt32   engineOffset;  /* Offset into global data */
    RwInt32   sectorOffset;  /* Offset into global data */
    RwInt32   worldOffset;   /* Offset into global data */

    RpWorld     *world;
    RwCamera    *camera;
    RwImage     *image;

    RwInt32      progress_count;

    RwReal       inout_tol;
    RwReal       gran;
    RwReal       diag;

    RwInt32      rasterW, rasterH;

    RpPVSCacheSizeVer2       sectorCacheVer2;
};

extern RpPVSGlobalVars rpPVSGlobals;

#if (defined(RWDEBUG))
extern long rpPVSStackDepth;
#endif /* (defined(RWDEBUG)) */

#endif /* PVSDEF_H */
