
/****************************************************************************
 *                                                                          *
 * module : ps2Allim3d.h                                                    *
 *                                                                          *
 * purpose: see ps2Allim3d.c                                                *
 *                                                                          *
 ****************************************************************************/

#ifndef NODEPS2ALLIM3D_H
#define NODEPS2ALLIM3D_H

#include "nodeps2all.h"

/****************************************************************************
 global types
 */

/* Temporary, for the Im3D splitting stuff */

/* RWPUBLIC */

typedef struct im3DPS2AllData im3DPS2AllData;
struct im3DPS2AllData
{
    RwBool              triFan;                         /**< Internal Use */
    RwUInt32            indOffset;                      /**< Internal Use */
    RwUInt32            indPerBlock;                    /**< Internal Use */
    RwImVertexIndex     swappedTriFanIndex;             /**< Internal Use */
    RwImVertexIndex     firstTriFanIndex;               /**< Internal Use */
    RxObjSpace3DVertex  swappedTriFanVertex;            /**< Internal Use */
    RxObjSpace3DVertex  firstTriFanVertex;              /**< Internal Use */
    RxObjSpace3DVertex *tempObjVerts;                   /**< Internal Use */
};

/* RWPUBLICEND */

/****************************************************************************
 global defines
 */

/* REDEBUGPrintf and RWASSERT are NOPs in rpworld.h, for app code */
/* RWPUBLIC */
#if (!defined(REDEBUGPrintf))
#define REDEBUGPrintf(args) /* No op */
#endif /* (!defined(REDEBUGPrintf)) */
#if (defined(RWASSERT))
#define PS2ALLMACROASSERT(args) RWASSERT(args)
#else /* (!defined(RWASSERT)) */
#define PS2ALLMACROASSERT(args) /* No op */
#endif /* (!defined(RWASSERT)) */

/* Used as RwIm3DPS2AllGetMeshHeaderMeshCache (function in debug) */
#define RwIm3DPS2AllGetMeshHeaderMeshCacheMacro(_stash, _ps2AllPipeData)                                \
MACRO_START                                                                                             \
{                                                                                                       \
    _rwIm3DPoolStash  *_stch = (_stash);                                                                \
    RxPS2AllPipeData  *_p2apd = (_ps2AllPipeData);                                                      \
                                                                                                        \
    /* There'll be a static per callback that uses this - not so bad */                                 \
    /* (for the function  version there'll only be one copy, yay) */                                    \
    static RwBool     _doneMat = FALSE;                                                                 \
    static RpMaterial _mat;                                                                             \
                                                                                                        \
    _p2apd->meshCache  = &gIm3DMeshCache;                                                               \
    _p2apd->meshHeader = &(gIm3DMeshHeader[0]);                                                         \
                                                                                                        \
    /* Initialise the static meshHeader/meshCache mem */                                                \
                                                                                                        \
    _p2apd->meshHeader->numMeshes = 1;                                                                  \
    /* RPMESHGLOBAL(nextSerialNum)++ ? Probably not important (it's fake) */                            \
    _p2apd->meshHeader->serialNum = 0;                                                                  \
    _p2apd->meshHeader->totalIndicesInMesh = _stch->numIndices;                                         \
    /* Cheekily whacked on the end there :) */                                                          \
    _p2apd->meshHeader->firstMeshOffset = 0;                                                            \
                                                                                                        \
    _p2apd->meshHeader->flags = 0;                                                                      \
    RpMeshHeaderSetPrimType(_p2apd->meshHeader, _stch->primType);                                       \
    if (NULL == _stch->indices)                                                                         \
    {                                                                                                   \
        /* RwIm3DPS2AllInstance can now instance from unindexed meshes */                               \
        _p2apd->meshHeader->flags = (RxInstanceFlags)                                                   \
            (_p2apd->meshHeader->flags | rpMESHHEADERUNINDEXED);                                        \
    }                                                                                                   \
                                                                                                        \
    /* Build your own meshcache... */                                                                   \
    _p2apd->meshCache->lengthOfMeshesArray = 1;                                                         \
    _p2apd->meshCache->meshes[0] = NULL; /* Ensure DMA chain gets built */                              \
                                                                                                        \
    /* Mesh->material gets accessed in PS2All (Rabin's speculative */                                   \
    /* texture upload stuff :o| ) so we have to set it up...       */                                   \
    if (FALSE == _doneMat)                                                                              \
    {                                                                                                   \
        RwRGBA OpaqueWhite = {255, 255, 255, 255};                                                      \
        RwSurfaceProperties surfProps = {1.0f, 1.0f, 1.0f};                                             \
                                                                                                        \
        /* First time, set it up */                                                                     \
        _mat.refCount = 1;                                                                              \
        RpMaterialSetTexture(&_mat, NULL);                                                              \
        RpMaterialSetColor(&_mat, &OpaqueWhite);                                                        \
        RpMaterialSetSurfaceProperties(&_mat, &surfProps);                                              \
        _doneMat = TRUE;                                                                                \
    }                                                                                                   \
    _mat.pipeline = _p2apd->objPvtData->groupPipe;                                                      \
    ((RpMesh *)(_p2apd->meshHeader + 1))->material = &_mat;                                             \
}                                                                                                       \
MACRO_STOP

/* Used as RwIm3DPS2AllGatherObjMetrics (function in debug) */
#if (defined(RWMETRICS))
#define RwIm3DPS2AllGatherObjMetricsMacro(_stash)                                                       \
MACRO_START                                                                                             \
{                                                                                                       \
    _rwIm3DPoolStash *_stch = (_stash);                                                                 \
                                                                                                        \
    /* numVertices updated in PS2Im3DFastTransform */                                                   \
                                                                                                        \
    /* We don't count lines/points */                                                                   \
    if ((_stch->primType == rwPRIMTYPETRIFAN) ||                                                        \
        (_stch->primType == rwPRIMTYPETRISTRIP))                                                        \
    {                                                                                                   \
        RWSRCGLOBAL(metrics)->numTriangles += _stch->numIndices - 2;                                    \
    }                                                                                                   \
    else if (_stch->primType == rwPRIMTYPETRILIST)                                                      \
    {                                                                                                   \
        RWSRCGLOBAL(metrics)->numTriangles += _stch->numIndices / 3;                                    \
    }                                                                                                   \
}                                                                                                       \
MACRO_STOP
#else /* (defined(RWMETRICS)) */
#define RwIm3DPS2AllGatherObjMetricsMacro(_stash) /* No op */
#endif /* (defined(RWMETRICS)) */

/* Used as RwIm3DPS2AllObjInstanceTest (function in debug) */
/* RWPUBLICEND */
/* TODO[5]: THE FULL REINSTANCE - THIS *COULD* CHANGE SO THAT ONLY lastReverse
 *  IS RECALC'ED - OR MAYBE MAKING Im3D ALL NON-OPAQUE WOULD BE MORE EFFICIENT */
/* RWPUBLIC */
#define RwIm3DPS2AllObjInstanceTestMacro(_ps2AllPipeData)                                               \
MACRO_START                                                                                             \
{                                                                                                       \
    RxPS2AllPipeData *_p2apd = (_ps2AllPipeData);                                                       \
                                                                                                        \
    /* We always do a full reinstance for Im3D (I know... sorry :o/) */                                 \
    _p2apd->objInstance = (RxInstanceFlags)                                                             \
         ( rxINSTANCEFULLINSTANCE | rxINSTANCEALL );                                                    \
    REDEBUGPrintf(("im3d ps2AllPipeData->objInstance %x\n", (RwUInt32)_p2apd->objInstance));            \
}                                                                                                       \
MACRO_STOP

/* Used as RwIm3DPS2AllTransformSetup (function in debug) */
#define RwIm3DPS2AllTransformSetupMacro(_stash, _transform)                                             \
MACRO_START                                                                                             \
{                                                                                                       \
    _rwIm3DPoolStash *_stch = (_stash);                                                                 \
    RwMatrix       **_tnfm = (_transform);                                                              \
                                                                                                        \
    RwMatrix * const _mpLocalToWorld = (RwMatrix *)((_stch)->ltm);                                      \
    RwMatrix * const _viewMatrix = &(((RwCamera *)RWSRCGLOBAL(curCamera))->viewMatrix);                 \
                                                                                                        \
    PS2ALLMACROASSERT(RWMATRIXALIGNMENT(_mpLocalToWorld));                                              \
    PS2ALLMACROASSERT(RWMATRIXALIGNMENT(_viewMatrix));                                                  \
                                                                                                        \
    if (_mpLocalToWorld != NULL)                                                                        \
    {                                                                                                   \
        RwMatrixMultiply(*_tnfm, _mpLocalToWorld, _viewMatrix);                                         \
    }                                                                                                   \
    else                                                                                                \
    {                                                                                                   \
       *_tnfm = _viewMatrix;                                                                            \
    }                                                                                                   \
}                                                                                                       \
MACRO_STOP

/* Used as RwIm3DPS2AllFrustumTest (function in debug) */
#define RwIm3DPS2AllFrustumTestMacro(_stash, _inFrustum)                                                \
MACRO_START                                                                                             \
{                                                                                                       \
    RwFrustumTestResult *_infm = (_inFrustum);                                                          \
                                                                                                        \
    *_infm = rwSPHEREBOUNDARY;                                                                          \
    if ((_stash)->flags & rwIM3D_NOCLIP) *_infm = rwSPHEREINSIDE;                                       \
}                                                                                                       \
MACRO_STOP


/* Used as RwIm3DPS2AllResEntryAlloc (function in debug) */
/* RWPUBLICEND */
/* TODO[9]: WHERE WE MARK THE MEMORY TO BE FREED MIGHT HAVE CHANGED TO
 * RwIm3DPS2AllPostMeshCallBack(SEE _rwIm3DPS2AllIm3DPostMeshCallBack) */
/* RWPUBLIC */
#define RwIm3DPS2AllResEntryAllocMacro(_ps2AllPipeData, _repEntry, _size, _destroyCallBack)             \
MACRO_START                                                                                             \
{                                                                                                       \
    RxPS2AllPipeData *_p2apd = (_ps2AllPipeData);                                                       \
    RwResEntry      **_rslt  = (_repEntry);                                                             \
    RwUInt32          _cyze  = (_size);                                                                 \
                                                                                                        \
    /* Im3D changes every frame (for now no caching), so don't use  */                                  \
    /* a resEntry (fake one), use Malloc. We mark this memory to be */                                  \
    /* freed with _sweAddPkt() in PS2MatBridge at the end of        */                                  \
    /* _rwRabinsBridgeNodeCode(). You could also use circularMalloc */                                  \
    /* with (SWE_PKT_CIRCALLOC | SWE_PKT_LOCAL) flags               */                                  \
   *_rslt = (RwResEntry *)circularMalloc(circAllocator, sizeof(RwResEntry) + _cyze, calDCACHE_ALLOC);   \
    /* OLD: result = RwMalloc(sizeof(RwResEntry) + size); */                                            \
                                                                                                        \
    /* We have to set up this space as if it were a resentry */                                         \
    /* cos later pipe code assumes this is done... for now   */                                         \
    (*_rslt)->link.prev = (RwLLLink *)NULL;                                                             \
    (*_rslt)->link.next = (RwLLLink *)NULL;                                                             \
    (*_rslt)->owner = _p2apd->sourceObject;                                                             \
    (*_rslt)->size = _cyze;                                                                             \
    (*_rslt)->ownerRef = (RwResEntry **)NULL;                                                           \
    (*_rslt)->destroyNotify = (void (*)(RwResEntry *))_destroyCallBack;                                 \
    /* We mark the memory to be freed with _sweAddPkt() in _rwIm3DPS2AllIm3DPostMeshCallBack */         \
}                                                                                                       \
MACRO_STOP

/* Used as RwIm3DPS2AllGatherMeshMetrics (function in debug) */
#if (defined(RWMETRICS))
#define RwIm3DPS2AllGatherMeshMetricsMacro(_stash, _ps2AllPipeData)                                     \
MACRO_START                                                                                             \
{                                                                                                       \
    _rwIm3DPoolStash *_stch = (_stash);                                                                 \
    RxPS2AllPipeData *_p2apd = (_ps2AllPipeData);                                                       \
                                                                                                        \
    /* We don't count lines */                                                                          \
    if (!(_p2apd->transType & rxSKYTRANSTYPELINE))                                                      \
    {                                                                                                   \
        if (_p2apd->transType & rxSKYTRANSTYPELIST)                                                     \
        {                                                                                               \
            RWSRCGLOBAL(metrics)->numProcTriangles += _stch->numIndices / 3;                            \
        }                                                                                               \
        else                                                                                            \
        {                                                                                               \
            RWSRCGLOBAL(metrics)->numProcTriangles += _stch->numIndices - 2;                            \
        }                                                                                               \
    }                                                                                                   \
}                                                                                                       \
MACRO_STOP
#else /* (defined(RWMETRICS)) */
#define RwIm3DPS2AllGatherMeshMetricsMacro(_stash, _ps2AllPipeData) /* No op */
#endif /* (defined(RWMETRICS)) */

/* Used as _rwIm3DPS2AllMeshEnd (function in debug) */
/* RWPUBLICEND */
/* Undo vertex increment for unindexed prims (DELIBERATE lack of predication here) */
/* RWPUBLIC */
#define _rwIm3DPS2AllMeshEndMacro(_stash, _ps2AllPipeData)                                              \
    ((_stash)->objVerts = gIm3DData.tempObjVerts)


/* RWPUBLICEND */

/****************************************************************************
 global prototypes
 */

/* RWPUBLIC */

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

/* Default RW callbacks */
extern RwBool RwIm3DPS2AllObjectSetupCallBack(
    RxPS2AllPipeData *ps2AllPipeData,
    RwMatrix **transform,
    RxWorldApplyLightFunc lightingFunc);
extern RwResEntry *RwIm3DPS2AllResEntryAllocCallBack(
    RxPS2AllPipeData *ps2AllPipeData,
    RwResEntry **repEntry,
    RwUInt32 size,
    RwResEntryDestroyNotify destroyCallBack);
extern RwBool RwIm3DPS2AllInstanceCallBack(
    RxPS2AllPipeData *ps2AllPipeData,
    void **clusters,
    RwUInt32 numClusters);
extern RwBool RwIm3DPS2AllBridgeCallBack(
    RxPS2AllPipeData *ps2AllPipeData);
extern RwBool RwIm3DPS2AllPostMeshCallBack(
    RxPS2AllPipeData *ps2AllPipeData);
/* RWPUBLICEND */
/* Mesh-split-specific ones */
extern RwBool _rwIm3DPS2AllIm3DPreMeshCallBack(
    RxPS2AllPipeData *ps2AllPipeData);
extern RwBool _rwIm3DPS2AllIm3DPostMeshCallBack(
    RxPS2AllPipeData *ps2AllPipeData);
extern RwBool _rwIm3DPS2AllMeshSplitCallBack(
    RxPS2AllPipeData *ps2AllPipeData);

/* RWPUBLIC */

/* Standard instance func for Im3D */
extern RwBool RwIm3DPS2AllInstance(RxPS2AllPipeData *ps2AllPipeData);

/* Callback components, for use in user callbacks */
/* ObjectSetupCB */
extern void RwIm3DPS2AllGetMeshHeaderMeshCacheFunc(
    _rwIm3DPoolStash *stash,
    RxPS2AllPipeData *ps2AllPipeData);
extern void RwIm3DPS2AllGatherObjMetricsFunc(
    _rwIm3DPoolStash *stash);
extern void RwIm3DPS2AllObjInstanceTestFunc(
    RxPS2AllPipeData *ps2AllPipeData);
extern void RwIm3DPS2AllTransformSetupFunc(
    _rwIm3DPoolStash *stash,
    RwMatrix **transform);
extern void RwIm3DPS2AllFrustumTestFunc(
    _rwIm3DPoolStash *stash,
    RwFrustumTestResult *inFrustum);
/* ResEntryAllocCB */
extern void RwIm3DPS2AllResEntryAllocFunc(
    RxPS2AllPipeData *ps2AllPipeData,
    RwResEntry **repEntry,
    RwUInt32 size,
    RwResEntryDestroyNotify destroyCallBack);
/* PostMeshCB */
extern void RwIm3DPS2AllGatherMeshMetricsFunc(
    _rwIm3DPoolStash *stash,
    RxPS2AllPipeData *ps2AllPipeData);
extern void _rwIm3DPS2AllMeshEndFunc(
    _rwIm3DPoolStash *stash,
    RxPS2AllPipeData *ps2AllPipeData);

#if (defined(RWDEBUG))
#define RwIm3DPS2AllGetMeshHeaderMeshCache  RwIm3DPS2AllGetMeshHeaderMeshCacheFunc
#define RwIm3DPS2AllGatherObjMetrics        RwIm3DPS2AllGatherObjMetricsFunc
#define RwIm3DPS2AllObjInstanceTest         RwIm3DPS2AllObjInstanceTestFunc
#define RwIm3DPS2AllTransformSetup          RwIm3DPS2AllTransformSetupFunc
#define RwIm3DPS2AllFrustumTest             RwIm3DPS2AllFrustumTestFunc
#define RwIm3DPS2AllResEntryAlloc           RwIm3DPS2AllResEntryAllocFunc
#define RwIm3DPS2AllGatherMeshMetrics       RwIm3DPS2AllGatherMeshMetricsFunc
#define _rwIm3DPS2AllMeshEnd                _rwIm3DPS2AllMeshEndFunc
#else /* (defined(RWDEBUG)) */
#define RwIm3DPS2AllGetMeshHeaderMeshCache  RwIm3DPS2AllGetMeshHeaderMeshCacheMacro
#define RwIm3DPS2AllGatherObjMetrics        RwIm3DPS2AllGatherObjMetricsMacro
#define RwIm3DPS2AllObjInstanceTest         RwIm3DPS2AllObjInstanceTestMacro
#define RwIm3DPS2AllTransformSetup          RwIm3DPS2AllTransformSetupMacro
#define RwIm3DPS2AllFrustumTest             RwIm3DPS2AllFrustumTestMacro
#define RwIm3DPS2AllResEntryAlloc           RwIm3DPS2AllResEntryAllocMacro
#define RwIm3DPS2AllGatherMeshMetrics       RwIm3DPS2AllGatherMeshMetricsMacro
#define _rwIm3DPS2AllMeshEnd                _rwIm3DPS2AllMeshEndMacro
#endif /* (defined(RWDEBUG)) */

extern RwMeshCache    gIm3DMeshCache;
extern RpMeshHeader   gIm3DMeshHeader[];
extern im3DPS2AllData gIm3DData;

#ifdef    __cplusplus
}
#endif /* __cplusplus */

/* RWPUBLICEND */


#endif /* NODEPS2ALLIM3D_H */

