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

#ifndef NODEPS2OBJALLINONE_H
#define NODEPS2OBJALLINONE_H

#include <rwcore.h>

#include "wrldpipe.h"

#define _rwInitMeshPacketMacro(_packet, _self, _DMASessionRecord,            \
                               _PS2Mesh, _mesh, _cacheEntryRef)              \
MACRO_START                                                                  \
{                                                                            \
    RxCluster *status;                                                       \
    RxCluster *clDMASessionRecord;                                           \
    RxCluster *clMesh;                                                       \
                                                                             \
    clDMASessionRecord = RxClusterLockWrite((_packet),                       \
                                            0 /* RxClPS2DMASessionRecord */, \
                                            (_self));                        \
    RWASSERT(clDMASessionRecord != NULL);                                    \
    clMesh = RxClusterLockWrite((_packet),                                   \
                                1 /* RxClPS2Mesh */,                         \
                                (_self));                                    \
                                                                             \
    RWASSERT(clMesh != NULL);                                                \
                                                                             \
    /* so... all packets share the same physical DMASessionRecord            \
     * - owned by object packet, externally referenced by mesh packet -      \
     * cunning,                                                              \
     * eh? */                                                                \
    status = RxClusterSetExternalData(clDMASessionRecord,                    \
                                      (_DMASessionRecord),                   \
                                      sizeof(RxPS2DMASessionRecord),         \
                                      1);                                    \
    /* Assert that DMA session cluster could be pointed at external data */  \
    RWASSERT(status != NULL);                                                \
                                                                             \
    (_PS2Mesh)->mesh = (_mesh);                                              \
    (_PS2Mesh)->cacheEntryRef = (_cacheEntryRef);                            \
    status = RxClusterSetExternalData(clMesh,                                \
                                      (_PS2Mesh),                            \
                                      sizeof(RxPS2Mesh),                     \
                                      1);                                    \
                                                                             \
    /* Assert initialisation of (_PS2Mesh) cluster */                        \
    RWASSERT(status != NULL);                                                \
                                                                             \
    /* Share the mesh too (save heapallocs here/later)                       \
       - but this must be editable */                                        \
    clMesh->flags |= rxCLFLAGS_EXTERNALMODIFIABLE;                           \
                                                                             \
    clMesh->numUsed = 1;                                                     \
}                                                                            \
MACRO_STOP

/* RWPUBLIC */

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

/**
 * \ingroup rpworldp2sky2
 * \typedef  RxWorldApplyLightFunc
 * RxWorldApplyLightFunc is a call back function for lighting
 */
typedef void
(*RxWorldApplyLightFunc) (const void *voidLight,
                          const RwMatrix * inverseMat,
                          RwReal invScale,
                          const RwSurfaceProperties * surfaceProps);

/* LEGACY-SUPPORT define for old typedef name */
#define rxWorldApplyLightFunc RxWorldApplyLightFunc

/**
 * \ingroup rpworldp2sky2
 * \typedef RxWorldLightingCallBack
 * RxWorldLightingCallBack is a call back function for lighting
 */
typedef void
(*RxWorldLightingCallBack) (RwInt32 objectType,
                            void *object,
                            RwSurfaceProperties * surface,
                            RxWorldApplyLightFunc lightingFunc);

/* LEGACY-SUPPORT define for old typedef name */
#define rxWorldLightingCallback RxWorldLightingCallBack

typedef struct RxPipelineNodePS2ObjAllInOneData RxPipelineNodePS2ObjAllInOneData;
struct RxPipelineNodePS2ObjAllInOneData
{
    RwBool              groupMeshes; /**< If TRUE, all meshes are output to the first output
                                      * of this node, *not* to their associated
                                      * material->pipeline */
    RxWorldLightingCallBack lightingCallback;
    RwBool              genericVU1Index; /**< Hacky flag used to make the code generate the
                                          * VU1CodeArray index properly for our new generic
                                          * VU code that supports back-face culling. In our next
                                          * non-bugfix release, we'll move index calculation into
                                          * instance CBs or something... */
};

/* LEGACY-SUPPORT define for old struct name */
#define RxNodePS2ObjAllInOneData RxPipelineNodePS2ObjAllInOneData

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

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

extern RxNodeDefinition *
RxNodeDefinitionGetPS2ObjAllInOne(RwInt32 objType);

#define RxPipelineNodePS2ObjAllInOneSetGrouping(_node,          \
                                                _groupMeshes)   \
        RxPS2ObjAllInOneSetGrouping(_node,                      \
                                    _groupMeshes)

extern RxPipelineNode  *
RxPipelineNodePS2ObjAllInOneSetGrouping(RxPipelineNode * node,
                                        RwBool groupMeshes);

#define RxPipelineNodePS2ObjAllInOneSetLighting(_node,                  \
                                                _newLightingFunc)       \
        RxPS2ObjAllInOneSetLighting(_node,                              \
                                    _newLightingFunc)

extern void
RxPipelineNodePS2ObjAllInOneSetLighting(RxPipelineNode * node,
                                        RxWorldLightingCallBack
                                        newLightingFunc);

/* RWPUBLICEND */

/* These exposed so nodePS2Manager can get at them */
extern RwBool
_rwPS2ObjAllInOnePipelineNodeInit(RxPipelineNode * self);

extern RwBool
_rwRabinsObjAllInOneCode(RxPS2DMASessionRecord * DMASessionRecord,
                         RxPipelineNodePS2ObjAllInOneData * pvtData);

extern RwBool
_rwIm3DObjAllInOneCode(RxPS2DMASessionRecord * DMASessionRecord,
                       RxPipelineNodePS2ObjAllInOneData * pvtData);

extern __inline RxPacket *
_rwInitMeshPacket(RxPacket * packet,
                  RxPipelineNodeInstance * self,
                  RxPS2DMASessionRecord * DMASessionRecord,
                  RxPS2Mesh * PS2Mesh,
                  const RpMesh * mesh,
                  RwResEntry ** cacheEntryRef);

extern void
_rxWorldLightingDefaultCallback(RwInt32 objectType,
                                void *object,
                                RwSurfaceProperties * surface,
                                RxWorldApplyLightFunc lightingFunc);

/* RWPUBLIC */

/* For nodeps2all.c */
extern RwReal * _skyLightFillPos;
extern RwUInt32 _skyLightQWordsWritten;
#ifndef USENULLLIGHTING
#define LIGHTBLOCKQWORDS 32
extern RwUInt128 lightBuffer[];
#endif /* !USENULLLIGHTING */

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */

/* RWPUBLICEND */

#endif                          /* NODEPS2OBJALLINONE_H */
