/***************************************************************************
 *                                                                         *
 * Module  : basky.h                                                       *
 *                                                                         *
 * Purpose : sky device header                                             *
 *                                                                         *
 **************************************************************************/

#ifndef RWSKY_H
#define RWSKY_H

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

/* RWPUBLIC */
#ifndef _RW_EETYPES_H
#define _RW_EETYPES_H
#include <eetypes.h>
#endif /* _RW_EETYPES_H */

/* This chooses a simpler texture cache and parallel upload. Its a bit ugly */
/* to have two versions of the code present, but this will let source */
/* licensees choose the one they want */
#define ASYNCTEXTURES

/* RWPUBLICEND */
#include <libgraph.h>
#include "bacamera.h"
#include "barwtyp.h"
#include "skyinst.h"

/****************************************************************************
 Defines
 */

#define RwSky2Malloc(_s)       RwMalloc(_s)       /* RwDriverMalloc(_s) */
#define RwSky2Free(_p)         RwFree(_p)         /* RwDriverFree(_p) */
#define RwSky2Calloc(_n, _s)   RwCalloc(_n, _s)   /* RwDriverCalloc(_n, _s) */
#define RwSky2Realloc(_p, _s)  RwRealloc(_p, _s)  /* RwDriverRealloc(_p, _s) */

#define ALTTEXFORM
#define TWIDDLEEIGHT

/* RWPUBLIC */

#ifndef __MWERKS__

/* The following assembler burst let me build a 128 bit from 2x 64 bit */
#define MAKE128(RES, MSB, LSB) \
        __asm__ volatile ( "pcpyld %0, %1, %2" : "=r" (RES) : "r" (MSB), "r" (LSB))

#else /* ! __MWERKS__ */

/* The following assembler burst let me build a 128 bit from 2x 64 bit */
#define MAKE128(RES, MSB, LSB) \
do    \
{     \
    u_long128 ___ltmp;  \
    __asm__ volatile ( "pcpyld %0, %1, %2" : "=r" (___ltmp) : "r" (MSB), "r" (LSB));  \
    RES = ___ltmp; \
} while (0)

#endif /* ! __MWERKS__ */

/* RWPUBLICEND */

/****************************************************************************
 Global Types
 */

#ifndef ASYNCTEXTURES

typedef struct _SkyMemBlock _SkyMemBlock;
struct _SkyMemBlock
{
    /* Need to know wether a Block is free 
     * without having to look it up in the lists */
    RwUInt8           cUsed;      /**< Internal use */
    RwUInt8           pad;        /**< Internal use */
    RwInt8            nCacheList; /**< Internal use */
    RwInt8            pad2;       /**< Internal use */

    /* This block always lives in correct sequential order of its location in memory */
    _SkyMemBlock *mbpPrev;
    _SkyMemBlock *mbpNext;

    /* The current list this block is in (free/used/named size) */
    RwLLLink          lCacheList;
    /* Wether the block has been used this frame or not */
    RwLLLink          lUsageList;

    /* Mutual link to the raster so its pointer can be nulled on deallocation */
    RwRaster          *rpRas;

    /* Last but not least, physical details of the block */
    RwUInt32          nAddr;
    RwInt32           nSize;
};

#else /* !ASYNCTEXTURES */

typedef struct _SkyMemBlock _SkyMemBlock;
struct _SkyMemBlock
{
    RwRaster *raster;  /**< Internal use */
    RwUInt32 address;  /**< Internal use */
    RwUInt32 size;     /**< Internal use */
};

#endif /* ! ASYNCTEXTURES */

#ifndef ASYNCTEXTURES

typedef struct _SkyMemory _SkyMemory;
struct _SkyMemory
{
    /* The actual memory blocks themselves */
    RwLinkList      llUnusedBlocks;  /**< Internal use */
    _SkyMemBlock    *bpBlocks;       /**< Internal use */

    /* The list of free blocks */
    RwLinkList      llFreeMem;       /**< Internal use */
    /* The Root Block to avoid special end of list case */
    _SkyMemBlock    mbDummy;         /**< Internal use */
};

typedef struct _SkyCacheList _SkyCacheList;
struct _SkyCacheList
{
    RwInt16        bUsed;                  /**< Internal use */
    RwInt16        bMRU;                   /**< Internal use */
    /* The List of Textures */
    RwLinkList     llTextureList;          /**< Internal use */
    /* How big are the textures in this list */
    RwInt32        nListSize;              /**< Internal use */
    /* Number of Accesses per frame */
    RwInt16        nAccessCountThisFrame;  /**< Internal use */
    RwInt16        nRejectCountThisFrame;  /**< Internal use */
};

/* Some defines for the texture cache */
#define skyMAXCACHELISTS 0

/* RWPUBLIC */

/* callback type used to change the raster at the last minute
 * (based on plugin data) or just snoop uploaded rasters. */
typedef void (*SkyCacheSnoopCallBack)(RwRaster **);


/* RWPUBLICEND */

typedef struct _SkyCache _SkyCache;
struct _SkyCache
{
    /* The physical memory definition */
    _SkyMemory            mMemory;                      /**< Internal use */

    /* Size based textures */
#if (skyMAXCACHELISTS == 0)
     /* zero-sized arrays aren't fun */
    _SkyCacheList         claCacheLists[1];             /**< Internal use */
#else
    _SkyCacheList         claCacheLists[skyMAXCACHELISTS]; /**< Internal use */
#endif

    /* The list of texture blocks that are left over from the lists */
    _SkyCacheList         clTextureBucket;              /**< Internal use */
    /* The list of texture blocks that are "sticky" */
    _SkyCacheList         clLockedTextures;             /**< Internal use */

    /* These three expel old textures in a timely fashion */
    RwLinkList            llTexturesUsedThisFrame;      /**< Internal use */
    RwLinkList            llTexturesUsedLastFrame;      /**< Internal use */
    RwLinkList            llUnusedTextures;             /**< Internal use */

    /* So we know what our current GS Rendering Context */
    RwRaster             *rpCurrentRaster;              /**< Internal use */

    /* Mechanism for allowing external control over cache operation */
    RwInt32               nCacheControlFlags;           /**< Internal use */

    /* So we know whether to use the cache or not */
    /* default to true, of course */
    RwBool                bEnabled;                     /**< Internal use */

    /* If the cache is not used, the app decides what to do */
    void (*fpCacheUploadRasterCB)(RwRaster *, RwBool);  /**< Internal use */

    /* Allow an app callback to change the raster at the last minute
     * (based on plugin data) or just snoop uploaded rasters. */
    SkyCacheSnoopCallBack fpCacheSnoopRasterCB;         /**< Internal use */

    /* Save of last context used */
    RwBool                context;                      /**< Internal use */
};

#endif /* !ASYNCTEXTURES */

/* This will store the base version of TEX0 for a given raster.
 * Its done like this, rather than a single long as we don't know what the
 * alignment is going to be
 */

typedef struct _SkyRasterExt _SkyRasterExt;
struct _SkyRasterExt
{
    RwInt32           dmaRefCount;                      /**< Internal use */
    RwInt32           dmaClrCount;                      /**< Internal use */

    /* General texture setup register */
    RwUInt32          lsb;                              /**< Internal use */
    RwUInt32          msb;                              /**< Internal use */
    RwUInt32          palOffset;                        /**< Internal use */

    /* K: a 12 bit 8.4 value in bottom bits */
    /* L: a 2 bit value in 12,13 */
    RwUInt16          mipmapKL;                         /**< Internal use */
    /* NOTE: This is left shifted two */
    RwUInt8           maxMipLevel;                      /**< Internal use */
    /* Is this texture to stay in the cache? */
    RwUInt8           bLocked;                          /**< Internal use */

    /* Mipmap addresses */
    RwUInt32          miptbp1Lsb;                       /**< Internal use */
    RwUInt32          miptbp1Msb;                       /**< Internal use */
    RwUInt32          miptbp2Lsb;                       /**< Internal use */
    RwUInt32          miptbp2Msb;                       /**< Internal use */

    /* Size in bytes in system memory for pixels */
    RwUInt32          sysMemSize;                       /**< Internal use */
    /* Size in bytes in system memory for palette */
    RwUInt32          sysMemPalSize;                    /**< Internal use */

    /* Size in words in video memory for pixels + palette */
    RwUInt32          nTexCacheSize;                    /**< Internal use */

    /* Should we cache packets for this raster */
    RwUInt8           cachePkts;                        /**< Internal use */
    RwUInt8           lockedMipLevel;     /**< Currently locked mip level */
    RwUInt8           flags;                /**< Bit 0 new format texture */
                                               /**< Bit 1 twiddled (->32) */
                                              /**< Bit 2 twiddled (->16)  */
    RwUInt8           pad[1];                           /**< Internal use */
    /* Cached packet for uploading the palette */
    u_long128         *palUploadPkt;                    /**< Internal use */
    /* Cached packets for uploading the mip levels */
    u_long128         *mipUploadPkts[7];                /**< Internal use */

    /* The memory block that currently holds this texture */
    _SkyMemBlock          *mpCacheEntry;                /**< Internal use */
#if defined(GSB) && defined(GSPLUS)
    RwUInt32          lsb3;                             /**< Internal use */
    RwUInt32          msb3;                             /**< Internal use */
    RwUInt32          miptbp3Lsb, miptbp3Msb;           /**< Internal use */
    RwUInt32          miptbp4Lsb, miptbp4Msb;           /**< Internal use */
#endif /* defined(GSB) && defined(GSPLUS) */
};



/* Fiddle-factor for v1.3 of SyncDCache */

/* RWPUBLIC */

#ifdef SCE_11
#define SCESYNCDCACHEROUNDUP(x) (x)
#else
#define SCESYNCDCACHEROUNDUP(x) ((void *)(((RwUInt32)(x)) + 127 ))
#endif

typedef struct _SkyCameraExt _SkyCameraExt;
struct _SkyCameraExt
{
    RwV3d          largeFrustumVerts[8];                /**< Internal use */
    RwFrustumPlane largeFrustumPlanes[6];               /**< Internal use */
};

#define RASTEREXTFROMRASTERCONST(raster) \
    ((const _SkyRasterExt *)(((const RwUInt8 *)(raster)) + skyRasterExt))
#define CAMERAEXTFROMCAMERACONST(camera) \
    ((const _SkyCameraExt *)(((const RwUInt8 *)(camera)) + skyCameraExt))

#define RASTEREXTFROMRASTER(raster) \
    ((_SkyRasterExt *)(((RwUInt8 *)(raster)) + skyRasterExt))
#define CAMERAEXTFROMCAMERA(camera) \
    ((_SkyCameraExt *)(((RwUInt8 *)(camera)) + skyCameraExt))


#ifdef    __cplusplus
extern "C"
{
#endif                          /* __cplusplus */

/****************************************************************************
 Global Variables
 */

extern RwInt32 skyRasterExt;
extern RwInt32 skyCameraExt;
extern int skyFrameBit;
extern long skyZbuf_1;
extern long skyFrame_1;
extern long skyTest_1;
extern long skyXyoffset_1;
extern long skyFogcol;
extern long skyClamp_1;
extern long skyTex1_1;
extern long skyAlpha_1;

extern long skyPrim_State;
extern RwRaster *skyTextureRaster;
extern RwBool skyAlphaTex;
extern RwBool skyVertexAlpha;

extern RwCullMode gSkyCullState;

extern RwBool cacheOpened;
extern RwBool needCache;

extern RwUInt32 skyFSAA0VisibleWidth;
extern RwUInt32 skyFSAA0RenderWidth;
extern RwUInt32 skyFSAA0RenderHeight;
extern RwUInt32 skyFSAA0FrameCount;

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */

/* RWPUBLICEND */

#ifdef    __cplusplus
extern "C"
{
#endif                          /* __cplusplus */

extern RwBool    _rpSkyDestroyFrameBufferRasters(void);
extern RwBool    _rpSkyCreateFrameBufferRasters(void);

#ifdef SHOWUPLOADEDTEXTURES
#define SHOWUPLOADEDTEXTUREMAXTEXTURES  1024
extern RwBool    bGShowUploadTextures;
extern RwTexture *tpShowUploadedTextures[SHOWUPLOADEDTEXTUREMAXTEXTURES];
extern RwRaster  *rpShowUploadedRasters[SHOWUPLOADEDTEXTUREMAXTEXTURES];
#endif

/******** WARNING! THIS MUST NOT BE CUSTOMER VISIBLE!*********************/
#if defined(GSB) && defined(GSPLUS)
extern sceGsPlusDBuffDc sweDb;
extern long skyFrame_2;
#else /* defined(GSB) && defined(GSPLUS) */
extern sceGsDBuffDc sweDb;
#endif /* defined(GSB) && defined(GSPLUS) */
/******** END WARNING! ***************************************************/
extern RwVideoMode *skyVideoMode;


#ifdef GSB
/******** WARNING! THIS MUST NOT BE CUSTOMER VISIBLE!*********************/
/* Can't figure out how to query this info. I guess that the CP app will */
/* have to broadcast it */
#define NUM_gGSMS 4
#define NUM_gGSMS_FRAME 1
#define NUM_ZM_FRAME 1

/* RWPUBLIC */
/* The number of groups of gsms generating frames */
extern RwInt32 skyNumSeqFrms;
/* Our frame number in the sequence. This requires that we know stuff */
extern RwInt32 skyRenderSlot;
/* RWPUBLICEND */
/* Our system GSM Id. We assume that gGSM ids start at 0 */
extern RwInt32 skyGsmId;
/* Are we trying to save memory and single buffer */
extern RwBool skySingleBuffer;
/* Do we need to stall on the first true buffer flip */
extern RwInt32 skyGsmSysReadyRequired;

/* RWPUBLIC */
/* Our fake value of the global Vsync count */
extern unsigned long skyGCVTValue;
/* RWPUBLICEND */
/* A lagging version for use in the dma chain itself */
extern unsigned long skyDMAGCVTValue;

/* Have we done a wait on DrawNext yet? */
extern RwBool skyNeedDrawNext;

/* We provide a function to set these. The defines are just defaults */
extern RwInt32 skyNumGGSMS;
extern RwInt32 skyNumGGSMSFrame;
extern RwInt32 skyNumZMergFrame;

extern RwBool _rpSkySetGGSMs(RwInt32 total, RwInt32 frame, RwInt32 zm);
extern void _rpSkySetInput(RwBool state);


/******** END WARNING! ***************************************************/
#endif /* GSB */

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */

#ifdef GSB
#define RpSkySetGGSMs(_total, _frame, _zm) _rpSkySetGGSMs(_total, _frame, _zm)
#define RpSkySetInput(_state)              _rpSkySetInput(_state)
#endif /* GSB */

/* RWPUBLIC */

/****************************************************************************
 Function prototypes
 */

#ifdef    __cplusplus
extern "C"
{
#endif                          /* __cplusplus */


extern RwInt32 _rwSkyFindMSB(RwUInt32 nInt);
extern RwBool _rwSkySetRenderState(RwRenderState nState, void *param);
extern RwBool _rwSkyFSAAMode0SetVisibleWidth(RwUInt32 width);

extern RwBool RpSkySuspend(void);
extern RwBool RpSkyResume(void);

extern RwBool _skyRasterGetTwiddling(RwRaster *ras);
extern RwRaster *_skyRasterSetTwiddling(RwRaster *ras, RwBool twiddling);

extern void         _rpSkyFrameBufferRastersUpdate(void);

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */

/* LEGACY-SUPPORT macros */
#define skyFSAAMode0SetVisibleWidth(width)  \
            _rwSkyFSAAMode0SetVisibleWidth(width)


/* RWPUBLICEND */

extern RwDevice       *_rwDeviceGetHandle(void);
extern void *skyVU1Transforms[VU1CODEARRAYSIZE];

#endif /* RWSKY_H */

