/******************************************/
/*                                        */
/*    RenderWare(TM) Graphics Library     */
/*                                        */
/******************************************/

/*
 * This file is a product of Criterion Software Ltd.
 *
 * This file is provided as is with no warranties of any kind and is
 * provided without any obligation on Criterion Software Ltd.
 * or Canon Inc. to assist in its use or modification.
 *
 * Criterion Software Ltd. and Canon Inc. will not, under any
 * circumstances, be liable for any lost revenue or other damages
 * arising from the use of this file.
 *
 * Copyright (c) 1999. Criterion Software Ltd.
 * All Rights Reserved.
 */

/*************************************************************************
 *
 * Filename: <../include/sky2/rpworld.h>
 * Automatically Generated on: Tue Aug 21 11:29:25 2001
 *
 ************************************************************************/

#ifndef RPWORLD_H
#define RPWORLD_H

/*--- Check For Previous Required Includes ---*/
#ifndef RWCORE_H
#error "Include RWCORE.H before including this file"
#endif /* RWCORE_H */

/*--- System Header Files ---*/
#include <stdarg.h>
#include <stdlib.h>

/*--- Error enumerations ---*/
#include "rpworld.rpe"


/*--- Automatically derived from: pipe/p2/sky2/skyisms.h ---*/

typedef struct RwMeshCache RwMeshCache;

/**
 * \ingroup rpworldp2sky2
 * \struct RwMeshCache
 * Holds pointers to RwResEntrys for all the meshes in an object.
 */
struct RwMeshCache
{
    RwUInt32    lengthOfMeshesArray; /**< Number of meshes in the object */
    RwResEntry *meshes[1]; /**< The RwMeshCache structure will be 
                            * allocated sufficiently big that this tail 
                            * array can hold lengthOfMeshesArray pointers to 
                            * \ref RwResEntry's */
};

extern RwInt32 rwPip2GeometryOffset;
extern RwInt32 rwPip2AtomicOffset;
extern RwInt32 rwPip2WorldSectorOffset;

/* access to the atomic/worldsector extension data
 * we use for per-mesh cacheing */

#define RWMESHCACHEFROMGEOMETRY(_geometry)                             \
    ( *(RwMeshCache * *)                                               \
      (((RwUInt8 *) (_geometry)) +  rwPip2GeometryOffset) )

#define RWMESHCACHEFROMCONSTGEOMETRY(_geometry)                        \
    ( *(const RwMeshCache * *)                                         \
      (((const RwUInt8 *) (_geometry)) +  rwPip2GeometryOffset) )

#define RWMESHCACHEFROMATOMIC(_atomic)                                 \
    ( *(RwMeshCache * *)                                               \
      (((RwUInt8 *) (_atomic)) + rwPip2AtomicOffset) ) 

#define RWMESHCACHEFROMCONSTATOMIC(_atomic)                            \
    ( *(const RwMeshCache * *)                                         \
      (((const RwUInt8 *) (_atomic)) + rwPip2AtomicOffset) )

#define RWMESHCACHEFROMWORLDSECTOR(_worldSector)                       \
    ( *(RwMeshCache * *)                                               \
      (((RwUInt8 *) (_worldSector)) + rwPip2WorldSectorOffset) )

#define RWMESHCACHEFROMCONSTWORLDSECTOR(_worldSector)                  \
    ( *(const RwMeshCache * *)                                         \
      (((const RwUInt8 *) (_worldSector)) +  rwPip2WorldSectorOffset) )


/* These are used in matInstance. These are the properties
 * which, if changed, should cause a full reinstance. */
#define WORLDRENDERTYPEMASK (rpWORLDTRISTRIP | \
                             rpWORLDTEXTURED | \
                             rpWORLDPRELIT   | \
                             rpWORLDNORMALS  | \
                             rpWORLDTEXTURED2)
/* Notice that rpWORLDLIGHT and rpWORLDMODULATEMATERIALCOLOR don't cause a
 * reinstance (former is tested in objAllInOne lighting code and latter in
 * the matBridge material setup code) */
#define ATOMICRENDERTYPEMASK (rpGEOMETRYTRISTRIP  | \
                              rpGEOMETRYPOSITIONS | \
                              rpGEOMETRYTEXTURED  | \
                              rpGEOMETRYPRELIT    | \
                              rpGEOMETRYNORMALS   | \
                              rpGEOMETRYTEXTURED2)
/* rpGEOMETRYPOSITIONS included for completeness... why not? */


/*--- Automatically derived from: pipe/p2/sky2/native.h ---*/

/*--- Automatically derived from: pipe/p2/sky2/fastim3d.h ---*/

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

extern RxPipeline * RwIm3DSkyGetPS2ManagerRenderPipeline(RwPrimitiveType type);
extern RxPipeline * RwIm3DSkyGetPS2ManagerTransformPipeline(void);

extern RxPipeline * RwIm3DSkyGetPS2AllRenderPipeline(RwPrimitiveType type);
extern RxPipeline * RwIm3DSkyGetPS2AllMatPipeline(RwPrimitiveType type);


#ifdef    __cplusplus
}
#endif /* __cplusplus */


/*--- Automatically derived from: pipe/p2/sky2/wrldpipe.h ---*/

/**
 * \defgroup platformspecific Platform-Specific
 *
 * Platform-specific information
 */

/**
 * \defgroup sky2 PS2
 * \ingroup platformspecific
 *
 */

/**
 * \defgroup sky2functionoverview PS2 Functions Overview
 * \ingroup sky2
 *
 * PS2 Specific Functions, Typedefs and Structs
 */

/**
 * \defgroup rpworldp2sky2 PS2
 * \ingroup rpworldpowerpipe
 *
 * Manipulating world object custom pipelines (platform-specific) 
 */

/**
 * \defgroup rwim3dps2 PS2
 * \ingroup rwim3d
 *
 * Platform-specific
 */

/**
 * \defgroup rpworldsectorsky2 PS2
 * \ingroup rpworldsector
 *
 * Platform-specific
 */

/**
 * \defgroup rpatomicsky2 PS2
 * \ingroup rpatomic
 *
 * Platform-specific
 */

/**
 * \defgroup rpmeshsky2 PS2
 * \ingroup rpmesh
 *
 * Platform-specific
 */

/**
 * \defgroup rpmaterialsky2 PS2
 * \ingroup rpmaterial
 *
 * Platform-specific
 */

/**
 * \defgroup rpworldsubsky2 PS2
 * \ingroup rpworldsub
 *
 * Platform-specific
 */


/**
 * \ingroup sky2
 * \page platformspecificinfo Platform-Specific Information
 *
 * Listed below are references to all PlayStation 2 platform-specific 
 * information contained within this API Reference.
 *
 * \li \ref coresky2overview
 * \li \ref rpworldp2sky2overview
 *
 * Within the RenderWare Graphics API Reference there are PlayStation 2 
 * platform-specific functions which are described:
 * \li \ref sky2specific - functions that only exist for PlayStation 2
 * \li \ref platformdependent - functions that exist on all platforms which 
 * are platform dependent and therefore syntax varies between platforms.
 *
 */

/**
 * \ingroup sky2functionoverview
 * \page sky2specific PS2 Specific Functions, Typedefs and Structs
 *
 * The functions, typedefs and structs listed in the folders below have been 
 * created specifically for PlayStation 2.
 *
 * \li RwCore
 * \li RwIm3D
 * \li PowerPipe
 * \li Unsupported RwCore
 * \li RpWorld
 * \li RpAtomic
 * \li RpWorldSector
 * \li Rt2d
 *
 * \subsection rwcorespecific RwCore
 * \par Functions
 * \li \ref RpSkyGetTrueTLClipper
 * \li \ref RpSkyGetTrueTSClipper
 * \li \ref RpSkyRenderStateGet
 * \li \ref RpSkyRenderStateSet
 * \li \ref RpSkySelectDeepZBuffer
 * \li \ref RpSkySelectTrueTLClipper
 * \li \ref RpSkySelectTrueTSClipper
 * \li \ref RpSkyTexCacheAccessRaster
 * \li \ref RpSkyTexCacheAccessSpeculate
 * \li \ref RpSkyTexCacheDisable
 * \li \ref RpSkyTexCacheFlush
 * \li \ref RpSkyTexCacheRasterGetAddr
 * \li \ref RpSkyTexCacheRasterLock
 * \li \ref RpSkyTexCacheRasterUnlockAll
 * \li \ref RpSkyTexCacheReleaseRaster
 * \li \ref RpSkyTexCacheRestore
 * \li \ref RpSkyTexCacheSetCallBack
 * \li \ref RpSkyTexCacheUploadRaster
 * \li \ref RpSkyTexCacheValidateRaster
 * \li \ref RpSkyTexGetMiptbp1
 * \li \ref RpSkyTexGetMiptbp12
 * \li \ref RpSkyTexGetSize
 * \li \ref RpSkyTexGetStartAddress
 * \li \ref RpSkyTexGetTex0
 * \li \ref RpSkyTexSetMiptbp1
 * \li \ref RpSkyTexSetMiptbp12
 * \li \ref RpSkyTexSetTex0
 * \li \ref RpSkyTextureCacheSetState
 * \li \ref RpSkyTextureGetDefaultMipmapK
 * \li \ref RpSkyTextureGetDefaultMipmapL
 * \li \ref RpSkyTextureGetMipmapK
 * \li \ref RpSkyTextureGetMipmapL
 * \li \ref RpSkyTextureSetDefaultMipmapK
 * \li \ref RpSkyTextureSetDefaultMipmapL
 * \li \ref RpSkyTextureSetMipmapK
 * \li \ref RpSkyTextureSetMipmapL
 * \li \ref RpSkyUploadPixelData
 *
 * \par Structures
 * \li RwSky2DVertex
 * \li RwSky2DVertexAlignmentOverlay
 * \li RwSky2DVertexFields
 * \li RwSkyMetrics
 *
 * \par Types
 * \li \ref RwSky2DVertex
 * \li \ref RwSky2DVertexAlignmentOverlay
 * \li \ref RwSky2DVertexFields
 * \li \ref RwSkyMetrics
 * 
 * \subsection rwim3dspecific RwIm3D
 * \par Functions
 * \li \ref RwIm3DSkyGetPS2ManagerRenderPipeline
 * \li \ref RwIm3DSkyGetPS2ManagerTransformPipeline
 *
 * \par Function Information
 * \li \ref RwIm3DGetTransformPipelineplatform
 * \li \ref RwIm3DGetRenderPipelineplatform
 *
 * \subsection rwcorepowerpipespecific PowerPipe Functions
 * \par Types
 * \li \ref RxObjUnion
 * \li \ref RxPS2DMASessionRecord
 * \li \ref RxPS2Mesh
 * \li \ref RxScrSpace2DVertex
 *
 * \par Enumerated Types
 * \li \ref RxSkyTransTypeFlags
 *
 * \subsection rwcoreunsupportedspecific Unsupported Core Library Functions
 * 
 * \par Functions
 * \li \ref _rwSkyFSAAMode0SetVisibleWidth
 * \li \ref _sweAddPkt
 * \li \ref sweCloseLocalPkt
 * \li \ref sweFinaliseOpenLocalPkt
 * \li \ref sweOpenLocalPkt
 *
 * \par Defines
 * \li \ref SWEADDCONTFAST
 * \li \ref SWEADDCONTGIFFAST
 * \li \ref SWEADDPRIMFAST
 * \li \ref SWEADDPRIMGIFFAST
 *
 * \subsection rpworldspecific RpWorld
 * \par Functions
 * \li \ref RxNodeDefinitionGetPS2Manager
 * \li \ref RxNodeDefinitionGetPS2MatBridge
 * \li \ref RxNodeDefinitionGetPS2MatInstance
 * \li \ref RxNodeDefinitionGetPS2ObjAllInOne
 * \li \ref RxPipelineNodePS2MatBridgeGetVU1CodeArray
 * \li \ref RxPipelineNodePS2MatBridgeNoTexture
 * \li \ref RxPipelineNodePS2MatBridgeSetVIFOffset
 * \li \ref RxPipelineNodePS2MatBridgeSetVU1CodeArray
 * \li \ref RxPipelineNodePS2ManagerGenerateCluster
 * \li \ref RxPipelineNodePS2ManagerGetVU1CodeArray
 * \li \ref RxPipelineNodePS2ManagerGetVUBatchSize
 * \li \ref RxPipelineNodePS2ManagerNoTexture
 * \li \ref RxPipelineNodePS2ManagerSetInstanceCallBack
 * \li \ref RxPipelineNodePS2ManagerSetLighting
 * \li \ref RxPipelineNodePS2ManagerSetPointListVUBufferSize
 * \li \ref RxPipelineNodePS2ManagerSetPostObjectCallBack
 * \li \ref RxPipelineNodePS2ManagerSetVIFOffset
 * \li \ref RxPipelineNodePS2ManagerSetVU1CodeArray
 * \li \ref RxPipelineNodePS2ManagerSetVUBufferSizes
 * \li \ref RxPipelineNodePS2MatInstanceGenerateCluster
 * \li \ref RxPipelineNodePS2MatInstanceSetPointListVUBufferSize
 * \li \ref RxPipelineNodePS2MatInstanceSetVUBufferSizes
 * \li \ref RxPipelineNodePS2ObjAllInOneSetGrouping
 * \li \ref RxPipelineNodePS2ObjAllInOneSetLighting
 *
 * \par Types
 * \li \ref RxPipelineNodePS2ManagerInstanceCallBack
 * \li \ref RxPipelineNodePS2ManagerPostObjectCallBack
 * \li \ref RxWorldApplyLightFunc
 * \li \ref RxWorldLightingCallBack
 *
 * \par Enumerated Types
 * \li \ref RxPS2ClusterAttrib
 * \li \ref RxPS2ClusterFormatAttrib
 * \li \ref RxPS2ClusterType
 * \li \ref RxPS2ObjectType
 *
 * \par Structures
 * \li RwMeshCache
 *
 * \subsection rpatomicspecific RpAtomic
 *
 * \par Functions
 * \li \ref RpAtomicSkyGetAllInOnePipeline
 * \li \ref RpAtomicSkyGetPS2ManagerPipeline
 * \li \ref RpAtomicSkyGetVanillaPipeline
 *
 * \subsection rpworldsectorspecific RpWorldSector
 * 
 * \par Functions
 * \li \ref RpWorldSectorSkyGetAllInOnePipeline
 * \li \ref RpWorldSectorSkyGetPS2ManagerPipeline
 * \li \ref RpWorldSectorSkyGetVanillaPipeline
 * 
 * \subsection rt2dspecific Rt2d Toolkit
 * \par Overview
 * \li \ref rt2dps2overview
 *
 * \par Functions
 * \li \ref Rt2dFontCacheFlush
 */

/** 
 * \ingroup sky2functionoverview
 * \page platformdependent Platform Dependent
 *
 * These are functions, typedefs, structs and #defines which exist on 
 * all platforms. However, the syntax varies between platforms. They are
 * listed below in two sections:
 * \li RwCore
 * \li RpWorld
 * 
 * \subsection rwcoredependent RwCore
 *
 * \par Types
 * \li \ref RxColorUnion
 * \li \ref RxObjSpace3DLitVertex 
 * \li \ref RxObjSpace3DVertex 
 * \li \ref RwIm3DVertex 
 * \li \ref RwIm2DVertex 
 * \li \ref RxVertexIndex 
 * \li \ref RwImVertexIndex 
 *
 * \par Structures
 * \li RxColorUnion
 * \li RxObjSpace3DVertex 
 *
 * \par Defines
 * \li \ref RWIM2DVERTEX
 * \li \ref RwIm3DVertex
 * \li \ref RWIMVERTEXINDEX
 *
 * \par Function information
 * \li \ref RwIm3DGetTransformPipelineplatform
 * \li \ref RwIm3DGetRenderPipelineplatform
 *
 * \subsection rpworlddependent RpWorld
 * \par Function information
 * \li \ref RpAtomicGetDefaultInstancePipelineplatform
 * \li \ref RpMaterialGetDefaultRenderPipelineplatform
 * \li \ref RpWorldGetDefaultSectorInstancePipelineplatform
 *
 */


/**
 * \ingroup sky2functionoverview
 * \page ps2allspecific PS2All Specific Functions, Typedefs and Structs
 *
 * The functions, typedefs and structs listed in the folders below have been 
 * created specifically for PlayStation 2. These are all (including the
 * RwIm3D functionality) provided with the RpWorld plugin.
 *
 * \li RpAtomic
 * \li RpMaterial
 * \li RpMesh
 * \li RpWorldSector
 * \li RwIm3D
 * \li PowerPipe
 *
 * \subsection rpatomicspecificps2all RpAtomic
 * \par Functions
 * \li \ref RpAtomicPS2AllFinalize
 * \li \ref RpAtomicPS2AllFrustumTest
 * \li \ref RpAtomicPS2AllGatherObjMetrics
 * \li \ref RpAtomicPS2AllGetMeshHeaderMeshCache
 * \li \ref RpAtomicPS2AllLightingSetup
 * \li \ref RpAtomicPS2AllMatModulateSetup
 * \li \ref RpAtomicPS2AllMorphSetup
 * \li \ref RpAtomicPS2AllObjectFinalizeCallBack
 * \li \ref RpAtomicPS2AllObjectSetupCallBack
 * \li \ref RpAtomicPS2AllObjInstanceTest
 * \li \ref RpAtomicPS2AllPrimTypeTransTypeSetup
 * \li \ref RpAtomicPS2AllResEntryAlloc
 * \li \ref RpAtomicPS2AllTransformSetup
 * \li \ref RpAtomicSkyGetPS2AllPipeline
 *
 * \subsection rpmaterialspecificps2all RpMaterial
 * \par Functions
 * \li \ref RpMaterialSkyGetDefaultPS2AllMatPipeline
 * \li \ref RpMaterialSkyGetPS2AllMatPipeline
 * \li \ref RpMaterialSkySetDefaultPS2AllMatPipeline
 * 
 * \subsection rpmeshspecificps2all RpMesh
 * \par Functions
 * \li \ref RpMeshPS2AllAsyncTextureUpload
 * \li \ref RpMeshPS2AllBridgeCallBack
 * \li \ref RpMeshPS2AllClipInfoUpload
 * \li \ref RpMeshPS2AllEndVIFUploads
 * \li \ref RpMeshPS2AllGatherMeshMetrics
 * \li \ref RpMeshPS2AllGIFTagUpload
 * \li \ref RpMeshPS2AllMatColUpload
 * \li \ref RpMeshPS2AllMeshInstanceTestCallBack
 * \li \ref RpMeshPS2AllPostMeshCallBack
 * \li \ref RpMeshPS2AllResEntryAllocCallBack
 * \li \ref RpMeshPS2AllStartVIFUploads
 * \li \ref RpMeshPS2AllSurfPropsUpload
 * \li \ref RpMeshPS2AllSyncTextureUpload
 * \li \ref RpMeshPS2AllTestMeshID
 * \li \ref RpMeshPS2AllTestNumVerts
 * \li \ref RpMeshPS2AllTextureStateUpload
 * \li \ref RpMeshPS2AllVU1CodeIndexSetup
 * \li \ref RpMeshPS2AllVU1CodeUpload
 *
 * \subsection rpworldsectorspecificps2all RpWorldSector
 * \par Functions
 * \li \ref RpWorldSectorPS2AllFrustumTest
 * \li \ref RpWorldSectorPS2AllGatherObjMetrics
 * \li \ref RpWorldSectorPS2AllGetMeshHeaderMeshCache
 * \li \ref RpWorldSectorPS2AllLightingSetup
 * \li \ref RpWorldSectorPS2AllMatModulateSetup
 * \li \ref RpWorldSectorPS2AllObjectSetupCallBack
 * \li \ref RpWorldSectorPS2AllObjInstanceTest
 * \li \ref RpWorldSectorPS2AllResEntryAlloc
 * \li \ref RpWorldSectorPS2AllTransformSetup
 * \li \ref RpWorldSectorSkyGetPS2AllPipeline
 *
 * \subsection rwim3dspecificps2all RwIm3D
 * \par Functions
 * \li \ref RwIm3DPS2AllBridgeCallBack
 * \li \ref RwIm3DPS2AllFrustumTest
 * \li \ref RwIm3DPS2AllGatherMeshMetrics
 * \li \ref RwIm3DPS2AllGatherObjMetrics
 * \li \ref RwIm3DPS2AllGetMeshHeaderMeshCache
 * \li \ref RwIm3DPS2AllInstanceCallBack
 * \li \ref RwIm3DPS2AllObjectSetupCallBack
 * \li \ref RwIm3DPS2AllObjInstanceTest
 * \li \ref RwIm3DPS2AllPostMeshCallBack
 * \li \ref RwIm3DPS2AllResEntryAlloc
 * \li \ref RwIm3DPS2AllResEntryAllocCallBack
 * \li \ref RwIm3DPS2AllTransformSetup
 * \li \ref RwIm3DSkyGetPS2AllMatPipeline
 * \li \ref RwIm3DSkyGetPS2AllRenderPipeline
 *
 * \subsection rxpipelinenodespecificps2all PowerPipe Functions
 * \par Functions
 * \li \ref RxNodeDefinitionGetPS2All
 * \li \ref RxNodeDefinitionGetPS2AllMat
 * \li \ref RxPipelineNodePS2AllGroupMeshes
 * \li \ref RxPipelineNodePS2AllMatGenerateCluster
 * \li \ref RxPipelineNodePS2AllMatGetVU1CodeArray
 * \li \ref RxPipelineNodePS2AllMatGetVUBatchSize
 * \li \ref RxPipelineNodePS2AllMatSetCallBack
 * \li \ref RxPipelineNodePS2AllMatSetPointListVUBufferSize
 * \li \ref RxPipelineNodePS2AllMatSetVIFOffset
 * \li \ref RxPipelineNodePS2AllMatSetVU1CodeArray
 * \li \ref RxPipelineNodePS2AllMatSetVUBufferSizes
 * \li \ref RxPipelineNodePS2AllSetCallBack
 *
 * \par Enumerated Types
 * \li \ref RxPipelineNodePS2AllCallBackType
 * \li \ref RxPipelineNodePS2AllMatCallBackType
 * \li \ref RxInstanceFlags
 *
 * \par Types
 * \li \ref RxPipelineNodePS2AllMatBridgeCallBack
 * \li \ref RxPipelineNodePS2AllMatInstanceCallBack
 * \li \ref RxPipelineNodePS2AllMatMeshInstanceTestCallBack
 * \li \ref RxPipelineNodePS2AllMatPostMeshCallBack
 * \li \ref RxPipelineNodePS2AllMatResEntryAllocCallBack
 * \li \ref RxPipelineNodePS2AllObjectFinalizeCallBack
 * \li \ref RxPipelineNodePS2AllObjectSetupCallBack
 *
 * \par Structures
 * \li \ref RxPS2AllPipeData
 */



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

extern RxPipeline *RpMaterialSkyGetPS2AllMatPipeline(void);
extern RxPipeline *RpMaterialSkyGetDefaultPS2AllMatPipeline(void);
extern RxPipeline *RpMaterialSkySetDefaultPS2AllMatPipeline(RxPipeline *pipeline);

extern RxPipeline *RpAtomicSkyGetPS2AllPipeline(void);
extern RxPipeline *RpAtomicSkyGetPS2ManagerPipeline(void);
extern RxPipeline *RpAtomicSkyGetAllInOnePipeline(void);
extern RxPipeline *RpAtomicSkyGetVanillaPipeline(void);

extern RxPipeline *RpWorldSectorSkyGetPS2AllPipeline(void);
extern RxPipeline *RpWorldSectorSkyGetPS2ManagerPipeline(void);
extern RxPipeline *RpWorldSectorSkyGetAllInOnePipeline(void);
extern RxPipeline *RpWorldSectorSkyGetVanillaPipeline(void);


#ifdef    __cplusplus
}
#endif /* __cplusplus */


/*--- Automatically derived from: pipe/p2/sky2/ps2clusterattribs.h ---*/

/**
 * \ingroup rpworldp2sky2
 * Flags in PS2-specific cluster attributes
 * specifying data instancing behaviour. Clusters of interest to instancing
 * by MatInstance.csl or PS2Manager.csl will have at least one of the
 * following flags set 
 */
enum RxPS2ClusterAttrib
{
    CL_ATTRIB_REQUIRED    = 0x00000001, /**< Required. Data will be instanced and
                                         *   uploaded for this cluster */
    CL_ATTRIB_READ        = 0x00000002, /**< Read access required by user node(s)/callback(s) */
    CL_ATTRIB_WRITE       = 0x00000004, /**< Write access required by user node(s)/callback(s) */
    CL_ATTRIB_READWRITE   = 0x00000006, /**< Simply (CL_ATTRIB_READ ¦ CL_ATTRIB_WRITE)
                                         * if either are set, the data is 'broken out'
                                         * (it's a contiguous array DMA'd by reference) */
    CL_ATTRIB_DONT_FILL   = 0x00000008, /**< Don't initialize the data. Will be
                                         * overwritten by user node(s)/callback(s) */
    CL_ATTRIB_PLACEHOLDER = 0x00000010, /**< VU mem place holder - space will be reserved on
                                         * VU1 but no data will be allocated CPU-side or uploaded.
                                         * NOTE: REQUIRED and PLACEHOLDER should not both be set.
                                         * If both are, REQUIRED overrides PLACEHOLDER */

    CL_ATTRIB_OPAQUE      = 0x00002000, /**<For internal use */
    CL_ATTRIB_STATIC      = 0x00008000, /**<For internal use */

    rxRXPS2CLUSTERATTRIBSFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum RxPS2ClusterAttrib RxPS2ClusterAttrib;

/**
 * \ingroup rpworldp2sky2
 *  Flags in PS2-specific cluster attributes
 * defining the format of cluster data in DMA packets. These formats get
 * expanded by the VIF on upload to VU1. 
 */
enum RxPS2ClusterFormatAttrib
{
    CL_S32   = 0x60000000, /**< See the EE user manual section 4.3.4 */
    CL_V2_32 = 0x64000000, /**< See the EE user manual section 4.3.4 */
    CL_V2_16 = 0x65000000, /**< See the EE user manual section 4.3.4 */
    CL_V3_32 = 0x68000000, /**< See the EE user manual section 4.3.4 */
    CL_V4_32 = 0x6c000000, /**< See the EE user manual section 4.3.4 */
    CL_V4_16 = 0x6d000000, /**< See the EE user manual section 4.3.4 */
    CL_V4_8  = 0x6e000000, /**< See the EE user manual section 4.3.4 */

    CL_USN   = 0x00004000, /**<Treat the data as unsigned */

    CL_TYPE_MASK = 0xff004000, /**<We allocate 9 bits for use as a format specifier,
                                * matching the bits in the VIF UNPACK command */
    rxRXPS2CLUSTERFORMATATTRIBSFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum RxPS2ClusterFormatAttrib RxPS2ClusterFormatAttrib;


/**
 * \ingroup rpworldp2sky2
 *  Values specifying the type of
 * PS2-specific clusters. See \ref RxPipelineNodePS2MatInstanceGenerateCluster
 * and \ref RxPipelineNodePS2ManagerGenerateCluster. There are only eight
 * possible clusters uploadable to VU1 on PS2 currently. The first four
 * are always uploaded to VU1 in the order listed VU (some can be missing)
 * and the user data clusters come after that. The data format of the four
 * standard clusters is fixed, changing the attributes value for
 * that won't work 
 */
enum RxPS2ClusterType
{
    CL_XYZ     = 0, /**< Vertex positions, fixed to CL_V3_32 format */
    CL_UV      = 1, /**< Vertex texture coordinates, fixed to CL_V2_32 format */
    CL_UV2     = 2, /**< Vertex texture coordinates, fixed to CL_V4_32 format */
    CL_RGBA    = 3, /**< Vertex prelight colors, fixed to (CL_V4_8 ¦ CL_USN) format */
    CL_NORMAL  = 4, /**< Vertex normals, fixed to CL_V4_8 format */
    CL_USER1   = 5, /**< First user data cluster, modifiable attributes */
    CL_USER2   = 6, /**< Second user data cluster, modifiable attributes */
    CL_USER3   = 7, /**< Third user data cluster, modifiable attributes */
    CL_USER4   = 8, /**< Fourth user data cluster, modifiable attributes */
    CL_MAXCL   = 9, /**< Nine clusters supported at the moment */
    rxPS2CLUSTERTYPFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum RxPS2ClusterType RxPS2ClusterType;


/*--- Automatically derived from: pipe/p2/nodeWorldSectorInstance.h ---*/

#if (!defined(RXPIPELINE))
#define RXPIPELINE
#endif /* (!defined(RXPIPELINE)) */

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

extern RxNodeDefinition *RxNodeDefinitionGetWorldSectorInstance(void);

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */


/*--- Automatically derived from: pipe/p2/nodeWorldSectorEnumerateLights.h ---*/

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

extern RxNodeDefinition *RxNodeDefinitionGetWorldSectorEnumerateLights(void);

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */


/*--- Automatically derived from: pipe/p2/nodeSubmitWith2DCull.h ---*/

#if (!defined(RXPIPELINE))
#define RXPIPELINE
#endif /* (!defined(RXPIPELINE)) */

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

extern RxNodeDefinition *RxNodeDefinitionGetSubmitWith2DCull(void);

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */



/*--- Automatically derived from: pipe/p2/nodePreLight.h ---*/

#if (!defined(RXPIPELINE))
#define RXPIPELINE
#endif /* (!defined(RXPIPELINE)) */

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

extern RxNodeDefinition *RxNodeDefinitionGetPreLight(void);

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */


/*--- Automatically derived from: pipe/p2/nodePostLight.h ---*/

#if (!defined(RXPIPELINE))
#define RXPIPELINE
#endif /* (!defined(RXPIPELINE)) */

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

extern RxNodeDefinition *RxNodeDefinitionGetPostLight(void);

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */


/*--- Automatically derived from: pipe/p2/nodeMaterialScatter.h ---*/

#if (!defined(RXPIPELINE))
#define RXPIPELINE
#endif /* (!defined(RXPIPELINE)) */

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

extern RxNodeDefinition *RxNodeDefinitionGetMaterialScatter(void);

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */


/*--- Automatically derived from: pipe/p2/nodeLight.h ---*/

#if (!defined(RXPIPELINE))
#define RXPIPELINE
#endif /* (!defined(RXPIPELINE)) */

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

extern RxNodeDefinition *RxNodeDefinitionGetLight(void);

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */


/*--- Automatically derived from: pipe/p2/nodeFastPathSplitter.h ---*/

#if (!defined(RXPIPELINE))
#define RXPIPELINE
#endif /* (!defined(RXPIPELINE)) */

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

extern RxNodeDefinition *RxNodeDefinitionGetFastPathSplitter(void);

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */


/*--- Automatically derived from: pipe/p2/nodeAtomicInstance.h ---*/

#if (!defined(RXPIPELINE))
#define RXPIPELINE
#endif /* (!defined(RXPIPELINE)) */

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

extern RxNodeDefinition *RxNodeDefinitionGetAtomicInstance(void);

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */


/*--- Automatically derived from: pipe/p2/nodeAtomicEnumerateLights.h ---*/

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

extern RxNodeDefinition *RxNodeDefinitionGetAtomicEnumerateLights(void);

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */


/*--- Automatically derived from: ./bamateri.h ---*/

/*
 * Handling surface materials
 * Materials describe how things are to appear when rendered
 *
 * Copyright (c) 1998 Criterion Software Ltd.
 */

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


typedef struct RpMaterialChunkInfo RpMaterialChunkInfo;
typedef struct RpMaterialChunkInfo _rpMaterial;

struct RpMaterialChunkInfo
{
    RwInt32             flags;  /**<  Material flags - unused currently - 
                                   for future expansion */
    RwRGBA              color;  /**<  Colour of material. */
    RwInt32             unused;  /**<  Not used */
    RwBool              textured;  /**<  Are we textured? */
#ifdef RXPIPELINE
    RwSurfaceProperties surfaceProps;   /**<  Surface properties - only relevant for PowerPipe */
                                        /**<  Included in PipeLine 1 for file compatibility */
#else /* RXPIPELINE */
    RwSurfaceProperties ignoredSurfaceProps;
#endif /* RXPIPELINE */
};

#if (!defined(RwMaterialAssign))
#define RwMaterialAssign(_target, _source)             \
    ( *(_target) = *(_source) )
#endif /* (!defined(RwMaterialAssign)) */

/**
 * \ingroup rpworlddatatypes
 * \typedef RpMaterial 
 * Material object. This should be 
 * considered an opaque type. Use the RpMaterial API functions to access.
 */
typedef struct RpMaterial RpMaterial;

#if (!defined(DOXYGEN))
struct RpMaterial
{
        RwTexture           *texture; /**< texture */
        RwRGBA              color; /**< color */              
#if (defined(RXPIPELINE))
        RxPipeline          *pipeline; /**< pipeline */     

        RwSurfaceProperties surfaceProps; /**< surfaceProps */
#else /* (defined(RXPIPELINE)) */
        /* Not used by the Pipeline1 rendering
         * but present so pp files can be loaded and
         * saved and the values not destroy
         */
        RwSurfaceProperties ignoredSurfaceProps;    

#endif /* (defined(RXPIPELINE)) */

        RwInt16             refCount;          /* C.f. rwsdk/world/bageomet.h:RpGeometry */
        RwInt16             pad;
};
#endif /* (!defined(DOXYGEN)) */

/**
 * \ingroup rpworlddatatypes
 * \typedef RpMaterialCallBack
 \ref RpMaterialCallBack 
 * represents the function called from \ref RpGeometryForAllMaterials and 
 * \ref RpWorldForAllMaterials for all materials referenced by polygons in a 
 * given geometry. This function should return a pointer to the current 
 * material to indicate success. The callback may return NULL to terminate 
 * further callbacks on the materials.
 * 
 * \param  material   Pointer to the current material
 * \param  data  Pointer to developer-defined data structure.
 * 
 * \return Pointer to the current material.
 */
typedef RpMaterial *(*RpMaterialCallBack)(RpMaterial *material, void *data);

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

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


/* Creating, destroying and referencing materials */
extern RpMaterial *RpMaterialCreate(void);
extern RwBool RpMaterialDestroy(RpMaterial *material);
extern RpMaterial *RpMaterialAddRef(RpMaterial *material);
extern RpMaterial *RpMaterialClone(RpMaterial *material);

/* Textures */
extern RpMaterial *RpMaterialSetTexture(RpMaterial *material, RwTexture *texture);
extern RwTexture *RpMaterialGetTexture(const RpMaterial *material);

/* Setting and getting colors */
extern RpMaterial *RpMaterialSetColor(RpMaterial *material, const RwRGBA *color);
extern const RwRGBA *RpMaterialGetColor(const RpMaterial *material);

/* Setting and getting surface properties */
extern RpMaterial *RpMaterialSetSurfaceProperties(RpMaterial * material, const RwSurfaceProperties * surfaceProperties);
extern const RwSurfaceProperties *RpMaterialGetSurfaceProperties(const RpMaterial * material);

/* Attaching toolkits */
extern RwInt32 RpMaterialRegisterPlugin(RwInt32 size, RwUInt32 pluginID,
                                        RwPluginObjectConstructor constructCB,
                                        RwPluginObjectDestructor destructCB,
                                        RwPluginObjectCopy copyCB);
extern RwInt32 RpMaterialRegisterPluginStream(RwUInt32 pluginID,
                                              RwPluginDataChunkReadCallBack readCB,
                                              RwPluginDataChunkWriteCallBack writeCB,
                                              RwPluginDataChunkGetSizeCallBack getSizeCB);
extern RwInt32 RpMaterialSetStreamAlwaysCallBack(
                        RwUInt32 pluginID,
                        RwPluginDataChunkAlwaysCallBack alwaysCB);
extern RwInt32 RpMaterialGetPluginOffset(RwUInt32 pluginID);
extern RwBool RpMaterialValidatePlugins(const RpMaterial *material);

/* Binary format */
extern RwUInt32 RpMaterialStreamGetSize(const RpMaterial *material);
extern RpMaterial *RpMaterialStreamRead(RwStream *stream);
extern const RpMaterial *RpMaterialStreamWrite(const RpMaterial *material, RwStream *stream);
extern RpMaterialChunkInfo *
RpMaterialChunkInfoRead(RwStream *stream, RpMaterialChunkInfo *materialChunkInfo, RwInt32 *bytesRead);

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */


/*--- Automatically derived from: ./bamatlst.h ---*/
/****************************************************************************
 Global Types
 */

typedef struct RpMaterialList RpMaterialList;
struct RpMaterialList
{
    RpMaterial     **materials;
    RwInt32        numMaterials;
    RwInt32        space;
};

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

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

#define rpMaterialListGetNumMaterials(mlist) ((mlist)->numMaterials)

/* Setting up and destroying material lists */
extern RpMaterialList *_rpMaterialListInitialize(RpMaterialList *matList);
extern RpMaterialList *_rpMaterialListDeinitialize(RpMaterialList *matList);

/* Accessing material lists */
extern RpMaterial     ** _rpMaterialListAlloc(RwUInt32 count);
extern RpMaterial *_rpMaterialListGetMaterial(const RpMaterialList *matList,
                                             RwInt32 matIndex);
extern RpMaterialList * _rpMaterialListSetSize(RpMaterialList * matList, 
                                               RwInt32 size);
extern RpMaterialList *_rpMaterialListCopy(RpMaterialList *matListOut,
                                          const RpMaterialList *matListIn);
extern RwInt32 _rpMaterialListAppendMaterial(RpMaterialList *matList,
                                            RpMaterial *material);
extern RwInt32 _rpMaterialListFindMaterialIndex(const RpMaterialList *matList,
                                               const RpMaterial *material);

/* Binary format */
extern RwUInt32 _rpMaterialListStreamGetSize(const RpMaterialList *matList);
extern RpMaterialList *_rpMaterialListStreamRead(RwStream *stream,
                                                RpMaterialList *matList);
extern const RpMaterialList *_rpMaterialListStreamWrite(const RpMaterialList *matList,
                                                       RwStream *stream);

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */

#define rpMaterialListInitialize(_matList) \
    _rpMaterialListInitialize(_matList)

#define rpMaterialListDeinitialize(_matList) \
    _rpMaterialListDeinitialize(_matList)

#define rpMaterialListGetMaterial(_matList, _matIndex) \
    _rpMaterialListGetMaterial(_matList, _matIndex)

#define rpMaterialListCopy(_matListOut, _matListIn) \
    _rpMaterialListCopy(_matListOut, _matListIn)

#define rpMaterialListAppendMaterial(_matList, _material) \
    _rpMaterialListAppendMaterial(_matList, _material)

#define rpMaterialListStreamRead(_stream, _matList) \
    _rpMaterialListStreamRead(_stream, _matList)

#define rpMaterialListStreamWrite(_matList, _stream) \
    _rpMaterialListStreamWrite(_matList, _stream)


/*--- Automatically derived from: ./bamesh.h ---*/

/*
 *
 * Purpose: Provide construction and enumeration facilities for meshes.
 *
 * Copyright (c) 1998 Criterion Software Ltd.
 */

#define RPMESHGLOBAL(var)                                   \
    (RWPLUGINOFFSET(rpMeshGlobals,                          \
                    RwEngineInstance,                       \
                    meshModule.globalsOffset)->var)

#define rwPRIMTYPEOR                            \
    (rwPRIMTYPELINELIST |                       \
      rwPRIMTYPEPOLYLINE |                      \
      rwPRIMTYPETRILIST |                       \
      rwPRIMTYPETRISTRIP |                      \
      rwPRIMTYPETRIFAN   |                      \
      rwPRIMTYPEPOINTLIST)

#define rpMESHHEADERPRIMTYPEOR                  \
    (0 /* rpMESHHEADERTRILIST*/ |               \
      rpMESHHEADERTRISTRIP |                    \
      rpMESHHEADERTRIFAN  |                     \
      rpMESHHEADERLINELIST |                    \
      rpMESHHEADERPOLYLINE |                    \
      rpMESHHEADERPOINTLIST)

/****************************************************************************
 Global variables
 */

extern RwModuleInfo meshModule;

/****************************************************************************
 Global types
 */

/**
 * \ingroup rpworlddatatypes
 * \typedef RpMeshHeader
 * typedef for header structure listing all meshes
 * constituting a single RpGeometry or RpWorldSector
 */
typedef struct RpMeshHeader RpMeshHeader;

/**
 * \ingroup rpworlddatatypes
 * \ref RpMeshHeaderFlags
 * represents the different types of mesh.
 * \see RpMeshHeader
 */
enum RpMeshHeaderFlags
{
    /* NOTE: trifans are denoted by absence of any other primtype
     *       flags so be careful that you test:
     *        (flags&triListFlag == triListFlag)
     *       and not:
     *        (flags&triListFlag)
     */
    rpMESHHEADERTRISTRIP = 0x0001,  /**< Render as tristrips */
    rpMESHHEADERTRIFAN = 0x0002,    /**< On PS2 these will be converted to trilists */
    rpMESHHEADERLINELIST = 0x0004,  /**< Render as linelists */
    rpMESHHEADERPOLYLINE = 0x0008,  /**< On PS2 these will be converted to linelists */
    rpMESHHEADERPOINTLIST = 0x0010, /**< Pointlists are supported only if rendered by
                                     *   custom pipelines; there is no default RenderWare 
                                     *   way to render pointlists. */

    rpMESHHEADERPRIMMASK = 0x00FF,  /**< All bits reserved for specifying primitive type */
    rpMESHHEADERUNINDEXED = 0x0100, /**< Topology is defined implicitly by vertex
                                     *   order, ergo the mesh contains no indices */
    rpMESHHEADERFLAGSFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};

/*
 * Typedef for RpMeshHeaderFlags enumeration
 * representing the different types of mesh
 */
typedef enum RpMeshHeaderFlags RpMeshHeaderFlags;


typedef struct RpBuildMeshTriangle RpBuildMeshTriangle;

/**
 * \ingroup rpworlddatatypes
 * \struct RpBuildMeshTriangle
 * This type represents an array of indices into
 * the object vertex array. Used during the construction
 * of tristrips.
 *
 * See API functions
 * \see RpBuildMeshGeneratePreprocessTriStrip
 * \see RpBuildMeshGenerateExhaustiveTriStrip
 * \see RpBuildMeshGenerateTrivialTriStrip
 * \see RpBuildMeshGenerateDefaultTriStrip
 * and
 * \see RpMeshSetTriStripMethod
 * \see RpMeshGetTriStripMethod
 */
struct RpBuildMeshTriangle
{
    RwUInt16            vertIndex[3]; /**< indices into object vertex
                                       *   array. */
    RpMaterial         *material;     /**< pointer to material used to
                                       *   render the mesh. */
};

typedef struct RpBuildMesh RpBuildMesh;

/**
 * \ingroup rpworlddatatypes
 * \struct RpBuildMesh
 * This type represents a mesh ready for tri stripping.
 *
 * See API functions
 * \see RpBuildMeshGeneratePreprocessTriStrip
 * \see RpBuildMeshGenerateExhaustiveTriStrip
 * \see RpBuildMeshGenerateTrivialTriStrip
 * \see RpBuildMeshGenerateDefaultTriStrip
 * and
 * \see RpMeshSetTriStripMethod
 * \see RpMeshGetTriStripMethod
 */
struct RpBuildMesh
{
    RwUInt32            triangleBufferSize; /**< number of triangles
                                             *   space has been allocated
                                             *   for. */
    RwUInt32            numTriangles;       /**< number of triangles to be
                                             *   tristripped. */
    RpBuildMeshTriangle *meshTriangles;     /**< pointer to build mesh
                                             *   triangles. */
};

typedef struct RpMesh RpMesh;

/**
 * \ingroup rpworlddatatypes
 * \struct RpMesh
 * This type represents a single polygon mesh.
 * A mesh is defined as a collection of triangles derived from an RpGeometry
 * or RpWorldSector which have a common material.
 *
 * See API functions \see RpGeometryForAllMeshes and
 * \see RpWorldSectorForAllMeshes and
 * the corresponding function callback types:
 */
struct RpMesh
{
    RxVertexIndex      *indices;    /**< vertex indices defining the mesh */
    RwUInt32            numIndices; /**< number of vertices in mesh */
    RpMaterial         *material;   /**< pointer to material used to
                                     *   render the mesh. */
};

/**
 * \ingroup rpworlddatatypes
 * \struct RpMeshHeader
 * Header for all meshes that constitute a single RpGeometry or RpWorldSector
 */
struct RpMeshHeader
{
    RwUInt32            flags;    /**< \see RpMeshHeaderFlags */
    RwUInt16            numMeshes; /**< Number of meshes in object */
    RwUInt16            serialNum; /**< Determine if mesh has changed
                                    * since last instance */
    RwUInt32            totalIndicesInMesh; /**< Total triangle index
                                             * count in all meshes
                                             */
    RwUInt32            firstMeshOffset; /**< Offset in bytes from end this
                                          * structure RpMeshHeader
                                          * to the first mesh
                                          */
};

/**
 * \ingroup rpworlddatatypes
 * \typedef RpMeshCallBack
 *  \ref RpMeshCallBack is the callback
 * function supplied to \ref RpGeometryForAllMeshes and
 * \ref RpWorldSectorForAllMeshes for all meshes in a given geometry.
 *
 * This function should return a pointer to the current mesh to indicate
 * success. The callback may return NULL to terminate further callbacks
 * on the meshes.
 *
 * \param  mesh   Pointer to the current mesh, supplied by
 * iterator.
 * \param  meshHeader   Pointer to the meshes header
 * \param  data  Pointer to developer-defined data structure.
 *
 * \return
 * Returns a pointer to the current mesh if successful or NULL if an error
 * occurred.
 */
typedef RpMesh     *(*RpMeshCallBack) (RpMesh * mesh,
                                       RpMeshHeader * meshHeader,
                                       void *pData);

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

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

/* Opening and closing module */
extern void        *_rpMeshOpen(void *instance, RwInt32 offset,
                                RwInt32 size);
extern void        *_rpMeshClose(void *instance, RwInt32 offset,
                                 RwInt32 size);

extern RwInt16      _rpMeshGetNextSerialNumber(void);

/* Create a build mesh with nothing in */
extern RpBuildMesh *_rpBuildMeshCreate(RwUInt32 bufferSize);

/* Destroy a build mesh */
extern RwBool       _rpBuildMeshDestroy(RpBuildMesh * mesh);

/* Destroy a build mesh */
extern RwBool       _rpMeshDestroy(RpMeshHeader * mesh);

/* Add a triangle to a mesh */
extern RpBuildMesh *_rpBuildMeshAddTriangle(RpBuildMesh * mesh,
                                            RpMaterial * material,
                                            RwInt32 vert1,
                                            RwInt32 vert2,
                                            RwInt32 vert3);

/* Get primtype from a mesh header */
extern RwPrimitiveType RpMeshHeaderGetPrimType(RpMeshHeader *
                                               meshHeader);

/* Set primtype for a mesh header */
extern RpMeshHeader *RpMeshHeaderSetPrimType(RpMeshHeader *
                                             meshHeader,
                                             RwPrimitiveType
                                             primType);

/* Enumerate meshes within a mesh header */
extern RpMeshHeader *_rpMeshHeaderForAllMeshes(RpMeshHeader *
                                               meshHeader,
                                               RpMeshCallBack
                                               fpCallBack,
                                               void *pData);

/* Mesh serialisation functions */
extern RwStream    *_rpMeshWrite(const RpMeshHeader * meshHeader,
                                 const void *object,
                                 RwStream * stream,
                                 const RpMaterialList * matList);
extern RpMeshHeader *_rpMeshRead(RwStream * stream,
                                 const void *object,
                                 const RpMaterialList * matList);
extern RwInt32      _rpMeshSize(const RpMeshHeader * meshHeader);
/* Mesh header create/destroy functions */
extern void          _rpMeshHeaderDestroy(RpMeshHeader * meshHeader);
extern RpMeshHeader * _rpMeshHeaderCreate(RwUInt32 size);


#ifdef    __cplusplus
}
#endif                          /* __cplusplus */

#define rpMeshWrite(_meshHeader, _object, _stream, _matList) \
    _rpMeshWrite(_meshHeader, _object, _stream, _matList)

#define rpMeshRead(_stream, _object, _matList) \
    _rpMeshRead(_stream, _object, _matList)

#define rpMeshSize(_meshHeader) \
    _rpMeshSize(_meshHeader)


/*--- Automatically derived from: ./basector.h ---*/

/*
 * Handling atomic sectors
 * Atomic sectors are use to divide up the world into manageable portions
 *
 * Copyright (c) 1998 Criterion Software Ltd.
*/

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

/* Type ID */
#define rpWorldSector 0xff     /* Not a true 'type'! */

#define rpMINDISTANCEBETWEENVERTICES (RwReal)(0.0001)

#define RPV3DFROMVERTEXNORMAL(v, n) \
    (v).x = (((RwReal)((n).x)) * ( (RwReal)(1.0/128))); \
    (v).y = (((RwReal)((n).y)) * ( (RwReal)(1.0/128))); \
    (v).z = (((RwReal)((n).z)) * ( (RwReal)(1.0/128)))

#define RPVERTEXNORMALFROMRWV3D(n, v)           \
    {                                           \
        RwFixed naTmp[3];                       \
                                                \
        naTmp[0] = RwRealToFixed((v).x);        \
        naTmp[1] = RwRealToFixed((v).y);        \
        naTmp[2] = RwRealToFixed((v).z);        \
                                                \
        if (naTmp[0] >= RwFixedCast(1))         \
        {                                       \
            naTmp[0] = RwFixedCast(1)-1;        \
        }                                       \
        if (naTmp[0] <= RwFixedCast(-1))        \
        {                                       \
            naTmp[0] = RwFixedCast(-1)+1;       \
        }                                       \
        if (naTmp[1] >= RwFixedCast(1))         \
        {                                       \
            naTmp[1] = RwFixedCast(1)-1;        \
        }                                       \
        if (naTmp[1] <= RwFixedCast(-1))        \
        {                                       \
            naTmp[1] = RwFixedCast(-1)+1;       \
        }                                       \
        if (naTmp[2] >= RwFixedCast(1))         \
        {                                       \
            naTmp[2] = RwFixedCast(1)-1;        \
        }                                       \
        if (naTmp[2] <= RwFixedCast(-1))        \
        {                                       \
            naTmp[2] = RwFixedCast(-1)+1;       \
        }                                       \
                                                \
        (n).x = (RwInt8)(naTmp[0]>>9);          \
        (n).y = (RwInt8)(naTmp[1]>>9);          \
        (n).z = (RwInt8)(naTmp[2]>>9);          \
    }

/* RpCollSector access macros - for pre v304 data */
#define RWCOLLSECTORGETTYPE(sect) \
    ((sect).cType&0x80)

#define RWCOLLSECTORGETPLANE(sect) \
    ((((sect).cType)>>3)&0xc)

#define RWCOLLSECTORGETON(sect) \
    (((sect).cType)&0x1f)

#define RWCOLLSECTORGETVERTEX(sect) \
    (sect).vertex

#define RWCOLLSECTORGETSTART(sect) \
    (sect).start

#define RWCOLLSECTORGETNOPOLYS(sect) \
    (sect).cType

#define RWCOLLSECTORSETPOLYGONS(sect,no,st) \
    (sect).cType = (RwUInt8)(no); \
    (sect).start = (RwUInt8)(st)

#define rwMAXCOLLISIONCUTS 7

/****************************************************************************
 Global types
 */

typedef struct RpVertexNormal RpVertexNormal;

struct RpVertexNormal
{
    RwInt8          x;
    RwInt8          y;
    RwInt8          z;
    RwUInt8         pad; /* pad character to force alignment */
};

typedef struct RpPolygon RpPolygon;

struct RpPolygon
{
    RwUInt16        matIndex;
    RwUInt16        vertIndex[3];
};

/* RpCollSector - for pre v304 data */
#define RWCOLLSECTORSETPLANE(sect,plane,vert,no,st) \
    (sect).cType = (RwUInt8)(0x80|((plane)<<3)|(no)); \
    (sect).vertex = (RwUInt8)(vert); \
    (sect).start = (RwUInt8)(st)

typedef struct RpCollSector RpCollSector;

struct RpCollSector
{
    RwUInt8 cType;    /* Bit 7   - 1 plane */
                      /*           0 polygons */
                      /* Bit 6-5 - plane */
                      /* Bit 4-0 - amount ON plane */
    RwUInt8 vertex;   /* Vertex index used for the split */
    RwUInt8 start;    /* Starting polygon */
};

/**
 * \ingroup rpworlddatatypes
 * \typedef RpWorldSector
 * World Sector object. This should be
 * considered an opaque type. Use the RpWorldSector API functions to access.
 */
typedef struct RpWorldSector RpWorldSector;

#if (!defined(DOXYGEN))
struct RpWorldSector
{
    RwInt32                 type;

    RpPolygon               *polygons;              /* Polygons themselves */

    RwV3d                   *vertices;              /* Vertex positions */
    RpVertexNormal          *normals;               /* Vertex normals */

    RwTexCoords             *texCoords[rwMAXTEXTURECOORDS]; /* Texture coordinates */

    RwRGBA                  *preLitLum;             /* Pre lit luminances */

    /* Pointer to memory allocated for vertex and poly pointers */
    RwResEntry              *repEntry;

    /* Atomics in this sectors */
    /* The pointers are frigged so they look like they are pointing to
       Atomics when they are pointing to here */
    RwLinkList              collAtomicsInWorldSector;       /* Coll priority */
    RwLinkList              noCollAtomicsInWorldSector;     /* No Coll priority */

    /* Lights in an atomic sector */
    RwLinkList              lightsInWorldSector;

    /* World space size of this sector */
    RwBBox                  boundingBox;

    /* The root of the bsp collision tree for pre v304 data */
    RpCollSector            *colSectorRoot;

    /* The mesh which groups same material polygons together */
    RpMeshHeader            *mesh;

#ifdef RXPIPELINE
    /* The WorldSector instancing pipeline for this WorldSector */
    RxPipeline    *pipeline;
#endif

    /* Material list window base
     * (triangles in a given sector can "see"
     * the 256 materials from
     * MatList[matListWindowBase] -> MatList[matListWindowBase + 255])
     */
    RwUInt16                matListWindowBase;

    RwUInt16                numVertices;            /* Num vertices */
    RwUInt16                numPolygons;            /* Num polygons */
    RwUInt16                pad;
};
#endif /* (!defined(DOXYGEN)) */

/**
 * \ingroup rpworlddatatypes
 * \typedef RpWorldSectorCallBack
 \ref RpWorldSectorCallBack
 * represents the function called from \ref RpWorldForAllWorldSectors,
 * \ref RpAtomicForAllWorldSectors and \ref RpLightForAllWorldSectors for all
 * world sectors in a given world or world sectors a given atomic or light lies
 * in. This function should return a pointer to the current world sector to
 * indicate success. The callback may return NULL to terminate further
 * callbacks on the atomic or light.
 *
 * \return Pointer to the current world sector.
 *
 * \param  sector   Pointer to the current world sector
 * \param  data  Pointer to developer-defined data structure.
 */
typedef RpWorldSector *(*RpWorldSectorCallBack)(RpWorldSector *worldSector, void *data);

typedef struct RpSector RpSector;

struct RpSector
{
    RwInt32                 type;
};

/* NOTE: The left and right pointers can point to an RpPlaneSector or
 *       an RpWorldSector
 * This is determined what the type is via the type value
 */

typedef struct RpPlaneSector RpPlaneSector;

struct RpPlaneSector
{
    RwInt32                 type;

    RwReal                  value;
    RpSector                *leftSubTree;   /* Sector 'left' (less) of the plane */
    RpSector                *rightSubTree;  /* Sector 'right' (more) of the plane */
    RwReal                  leftValue;
    RwReal                  rightValue;
};

/**
 * \ingroup rpworlddatatypes
 * \typedef RpWorldVertex
 * World vertex structure
 * This should be considered an opaque type.
 * Use the RpWorldVertex API functions to access.
 */
typedef struct RpWorldVertex RpWorldVertex;

#if (!defined(DOXYGEN))
struct RpWorldVertex
{
    RwV3d                   vOC;    /**< Vertex position */
    RwV3d                   normal; /**< Vertex normal */
    RwReal                  nU;     /**< Vertex texture co-ordinates */
    RwReal                  nV;     /**< Vertex texture co-ordinates */
};
#endif /* (!defined(DOXYGEN)) */

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

extern RwPluginRegistry sectorTKList;

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */

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

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


/* Get info from atomic sectors */
extern RwInt32 RpWorldSectorGetNumPolygons(const RpWorldSector *Sector);
extern RwInt32 RpWorldSectorGetNumVertices(const RpWorldSector *Sector);

/* Instancing and deinstancing sectors */
extern RpWorldSector * RpWorldSectorRender(RpWorldSector *worldSector);

extern const RpWorldSector *RpWorldSectorForAllMeshes(const RpWorldSector *sector,
                                                      RpMeshCallBack fpCallBack,
                                                      void *pData);

extern const RwBBox *RpWorldSectorGetBBox(const RpWorldSector *sector);

/* Plugins */
extern RwInt32 RpWorldSectorRegisterPlugin(RwInt32 size, RwUInt32 pluginID,
                                           RwPluginObjectConstructor constructCB,
                                           RwPluginObjectDestructor destructCB,
                                           RwPluginObjectCopy copyCB);
extern RwInt32 RpWorldSectorRegisterPluginStream(RwUInt32 pluginID,
                                                 RwPluginDataChunkReadCallBack readCB,
                                                 RwPluginDataChunkWriteCallBack writeCB,
                                                 RwPluginDataChunkGetSizeCallBack getSizeCB);
extern RwInt32 RpWorldSectorSetStreamAlwaysCallBack(
                    RwUInt32 pluginID,
                    RwPluginDataChunkAlwaysCallBack alwaysCB);
extern RwInt32 RpWorldSectorGetPluginOffset(RwUInt32 pluginID);
extern RwBool RpWorldSectorValidatePlugins(const RpWorldSector *sector);

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */

/*--- Automatically derived from: ./bameshop.h ---*/
 

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

/**
 * \ingroup rpworlddatatypes
 * \typedef RpTriStripMeshCallBack
 * \ref RpTriStripMeshCallBack is the callback to generate triangle strips
 * when the triangle stripped geometries or world sectors are unlocked.
 *
 * \param buildMesh pointer to the mesh which the triangle strip will be
 * generated from.
 * \param data  pointer to user-supplied data to pass to the callback
 * function.
 *
 * \return a pointer to the constructed mesh header.
 *
 */
typedef RpMeshHeader *
(*RpTriStripMeshCallBack) (RpBuildMesh *buildMesh, void *data);


/****************************************************************************
 Global types
 */


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


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

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


/* Callback mesh generating functions */
extern RpMeshHeader *
RpBuildMeshGenerateTrivialTriStrip(RpBuildMesh *buildMesh, void *data);

extern RpMeshHeader *
RpBuildMeshGenerateDefaultTriStrip(RpBuildMesh *buildmesh, void *data);

extern RpMeshHeader *
RpBuildMeshGeneratePreprocessTriStrip(RpBuildMesh *buildmesh, void *data);

extern RpMeshHeader *
RpBuildMeshGenerateExhaustiveTriStrip(RpBuildMesh *buildmesh, void *data);

extern RpMeshHeader *
RpBuildMeshGenerateDefaultIgnoreWindingTriStrip(RpBuildMesh *buildmesh, 
                                                void *data);

extern RpMeshHeader *
RpBuildMeshGeneratePreprocessIgnoreWindingTriStrip(RpBuildMesh *buildmesh, 
                                                   void *data);

extern RpMeshHeader *
RpBuildMeshGenerateExhaustiveIgnoreWindingTriStrip(RpBuildMesh *buildmesh, 
                                                   void *data);

/* Functions to set and get the global mesh tristrip algorithm */
extern RwBool
RpMeshSetTriStripMethod(RpTriStripMeshCallBack callback, void *data);

extern RwBool
RpMeshGetTriStripMethod(RpTriStripMeshCallBack *callback, void **data);


extern RpMeshHeader *
_rpTriListMeshGenerate(RpBuildMesh *buildMesh, void *data);

/* 
 * Optimise the mesh ordering 
 * (sort on material and place transparent materials last)
 */
extern RpMeshHeader *
_rpMeshOptimise(RpBuildMesh *buildmesh, RwUInt32 flags);

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */


#define _rpTriStripMeshTrivialGenerate(_buildMesh, _data)      \
    RpBuildMeshGenerateTrivialTriStrip(_buildMesh, _data)

#define _rpTriStripMeshDefaultGenerate(_buildmesh, _data)      \
    RpBuildMeshGenerateDefaultTriStrip(_buildmesh, _data)

#define _rpTriStripMeshPreprocessGenerate(_buildmesh, _data)   \
    RpBuildMeshGeneratePreprocessTriStrip(_buildmesh, _data)

#define _rpTriStripMeshExhaustiveGenerate(_buildmesh, _data)   \
    RpBuildMeshGenerateExhaustiveTriStrip(_buildmesh, _data)

#define _rpMeshSetTristripMethod(_callback, _data)             \
    RpMeshSetTriStripMethod(_callback, _data)

#define _rpMeshGetTristripMethod(_callback, _data)             \
    RpMeshGetTriStripMethod(_callback, _data)



/*--- Automatically derived from: ./balight.h ---*/

/*
 * Lighting 3D objects.
 * Lights are used to illuminate atomics and worlds
 *
 * Copyright (c) 1998 Criterion Software Ltd.
 */


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

/* Binary Light */
typedef struct RpLightChunkInfo RpLightChunkInfo;
typedef struct RpLightChunkInfo _rpLight;

struct RpLightChunkInfo
{
        RwReal              radius; /**< radius */
        RwReal              red; /**< red */
        RwReal              green; /**< green */
        RwReal              blue; /**< blue */
        RwReal              minusCosAngle; /**< minusCosAngle */
        RwUInt32            typeAndFlags; /**< typeAndFlags */
};

/* Type ID */
#define rpLIGHT 3

/* Beyond this the lights must be positioned */
#define rpLIGHTPOSITIONINGSTART 0x80

/**
 * \ingroup rpworlddatatypes
 * \ref RpLightType are
 * light sub types.  This type represents the different 
 * types of light source that can be created using the API function \ref RpLightCreate.  
 * Note that lights of types rpLIGHTPOINT, rpLIGHTSPOT and rpLIGHTSPOTSOFT have linear 
 * intensity fall-off with distance from the source, reducing to zero at the light's radius:*/
enum RpLightType
{
    rpNALIGHTTYPE = 0,

    /* These don't take part in the tie mechanism (no position) */
    rpLIGHTDIRECTIONAL, /**<Directional Light */
    rpLIGHTAMBIENT, /**<Ambient Light */

    /* These do take part in the tie mechanism (do have position) */
    rpLIGHTPOINT = rpLIGHTPOSITIONINGSTART, /**<Point Light */
    rpLIGHTSPOT, /**<Spot Light */
    rpLIGHTSPOTSOFT, /**<Soft Spot Light */
    rpLIGHTTYPEFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum RpLightType RpLightType;

/*************/

/*** FLAGS ***/

/*************/

/**
 * \ingroup rpworlddatatypes
 * \ref RpLightFlag defines what geometry is influenced by the light. 
 * The bit-field RpLightFlag specifies the options available for controlling the scope 
 * of a light source (see API function \ref RpLightSetFlags):*/
enum RpLightFlag
{
    rpLIGHTLIGHTATOMICS = 0x01, /**<The light source illuminates all atomics in a world */
    rpLIGHTLIGHTWORLD = 0x02, /**<The light source illuminates all static geometry in a world */
    rpLIGHTFLAGFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum RpLightFlag RpLightFlag;

/* rpLIGHTPRIVATENOCHROMA - turns on optimisations to do with
 *                          lights which are a shade of grey
 */
enum rpLightPrivateFlag
{
    rpLIGHTPRIVATENOCHROMA = 0x01,
    rpLIGHTPRIVATEFLAGFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum rpLightPrivateFlag rpLightPrivateFlag;

/*********************/


#define RWMINUSCOSFROMTAN(_minusCosAngle, _tanAngle)                  \
MACRO_START                                                           \
{                                                                     \
   const RwReal TanAngle2 = (_tanAngle) * (_tanAngle);                \
   const RwReal CosAngle2 = ((RwReal)1) / ( ((RwReal)1) + TanAngle2); \
   RwReal CosAngle;                                                   \
   rwSqrtMacro(CosAngle, CosAngle2);                                  \
   (_minusCosAngle) = - CosAngle;                                     \
}                                                                     \
MACRO_STOP

#define RWTANFROMMINUSCOS(_tanAngle, _minusCosAngle)                    \
MACRO_START                                                             \
{                                                                       \
    const RwReal CosAngle2 = (_minusCosAngle) * (_minusCosAngle);       \
    const RwReal TanAngle2 = (((RwReal)1) - (CosAngle2)) / (CosAngle2); \
    rwSqrtMacro(_tanAngle, TanAngle2);                                  \
}                                                                       \
MACRO_STOP


/**
 * \ingroup rpworlddatatypes
 * \typedef RpLight 
 * Light. This should be 
 * considered an opaque type. User the RpLight API functions to access.
 */
typedef struct RpLight RpLight;

#if (!defined(DOXYGEN))
struct RpLight
{
        RwObjectHasFrame    object; /**< object */

#ifndef RXPIPELINE
        RwApplyLightFunction applyLight; /**< applyLight */
#endif                          /* RXPIPELINE */
        RwReal              radius; /**< radius */
        RwRGBAReal          color; /**< color */  /* Light color */
        RwReal              minusCosAngle; /**< minusCosAngle */  
        RwLinkList          WorldSectorsInLight; /**< WorldSectorsInLight */
        RwLLLink            inWorld; /**< inWorld */
        RwUInt16            lightFrame; /**< lightFrame */
        RwUInt16            pad;
};
#endif /* (!defined(DOXYGEN)) */

/**
 * \ingroup rpworlddatatypes
 * \typedef RpLightCallBack
 * \ref RpLightCallBack 
 * represents the function called from \ref RpWorldForAllLights and 
 * \ref RpWorld SectorForAllLights for all lights in a given world or world 
 * sector. This function should return a pointer to the current light to 
 * indicate success. The callback may return NULL to terminate further 
 * callbacks on the world sector.
 *
 * \return Pointer to the current light.
 * 
 * \param  light   Pointer to the current light in the world 
 * sector.
 * \param  data  Pointer to developer-defined data structure.
 */
typedef RpLight    *(*RpLightCallBack) (RpLight * light, void *data);

typedef struct RpLightTie RpLightTie;

struct RpLightTie
{
    /* Information for an atomic sector */
    RwLLLink            lightInWorldSector; /* Lights IN this ATOMIC SECTOR */
    RpLight            *light;

    /* Information for a atomic */
    RwLLLink            WorldSectorInLight; /* Atomic sectors HOLDING this Light */
    RpWorldSector      *sect;
};

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

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


/* API Functions */
extern RpLight     *RpLightCreate(RwInt32 type);
extern RwBool       RpLightDestroy(RpLight * light);
extern RpLight     *RpLightSetFrame(RpLight * light, RwFrame * frame);
extern RwFrame     *RpLightGetFrame(const RpLight * light);
extern RpLightType  RpLightGetType(const RpLight * light);
extern RpLight     *RpLightSetFlags(RpLight * light, RwUInt32 flags);
extern RwUInt32     RpLightGetFlags(const RpLight * light);
extern RwReal       RpLightGetRadius(const RpLight * light);
extern RpLight     *RpLightSetRadius(RpLight * light, RwReal radius);
extern const RwRGBAReal *RpLightGetColor(const RpLight * light);
extern RpLight     *RpLightSetColor(RpLight * light,
                                    const RwRGBAReal * color);
extern RwReal       RpLightGetConeAngle(const RpLight * light);
extern RpLight     *RpLightSetConeAngle(RpLight * light, RwReal angle);
extern RwUInt32     RpLightStreamGetSize(const RpLight * light);
extern RpLight     *RpLightStreamRead(RwStream * stream);
extern const RpLight *RpLightStreamWrite(const RpLight * light,
                                         RwStream * stream);
extern RpLightChunkInfo *RpLightChunkInfoRead(RwStream * stream,
                                              RpLightChunkInfo *
                                              lightChunkInfo,
                                              RwInt32 * bytesRead);

/* Attaching toolkits */
extern RwInt32      RpLightRegisterPlugin(RwInt32 size, RwUInt32 pluginID,
                                          RwPluginObjectConstructor
                                          constructCB,
                                          RwPluginObjectDestructor
                                          destructCB,
                                          RwPluginObjectCopy copyCB);
extern RwInt32      RpLightRegisterPluginStream(RwUInt32 pluginID,
                                                RwPluginDataChunkReadCallBack
                                                readCB,
                                                RwPluginDataChunkWriteCallBack
                                                writeCB,
                                                RwPluginDataChunkGetSizeCallBack
                                                getSizeCB);
extern RwInt32      RpLightSetStreamAlwaysCallBack(
                        RwUInt32 pluginID,
                        RwPluginDataChunkAlwaysCallBack alwaysCB);
extern RwInt32      RpLightGetPluginOffset(RwUInt32 pluginID);
extern RwBool       RpLightValidatePlugins(const RpLight * light);

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */


/*--- Automatically derived from: ./bageomet.h ---*/

/*
 * Handling atomic's geometry
 * Geometry describe objects, and are the building blocks for atomics
 *
 * Copyright (c) 1998 Criterion Software Ltd.
*/


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

/* Type ID */
#define rpGEOMETRY 8

/**
 * \ingroup rpworlddatatypes
 * RpGeometryFlag
 * Geometry type flags 
 */
enum RpGeometryFlag
{
    rpGEOMETRYTRISTRIP = 0x01,  /**<This geometry's meshes can be rendered
                                 * as strips */
    rpGEOMETRYPOSITIONS = 0x02, /**<This geometry has positions */  
    rpGEOMETRYTEXTURED = 0x04,  /**<This geometry has one set of texture coordinates */
    rpGEOMETRYPRELIT = 0x08,    /**<This geometry has luminance values */
    rpGEOMETRYNORMALS = 0x10,   /**<This geometry has normals */
    rpGEOMETRYLIGHT = 0x20,     /**<This geometry will be lit */
    rpGEOMETRYMODULATEMATERIALCOLOR = 0x40, /**<Modulate material color 
                                               with vertex colors (pre-lit + 
                                               lit) 
                                            */
    rpGEOMETRYTEXTURED2 = 0x80, /**<This geometry has 2 set of texture coordinates */

    /*
     * These flags are stored in the flags field in an RwObject, the flag field is 8bit.
     */

    rpGEOMETRYFLAGFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum RpGeometryFlag RpGeometryFlag;

/**
 * \ingroup rpworlddatatypes
 * RpGeometryLockMode
 * Geometry lock flags 
 */
enum RpGeometryLockMode
{
    rpGEOMETRYLOCKPOLYGONS = 1, /**<Lock the polygons */
    rpGEOMETRYLOCKVERTICES = 2, /**<Lock the vertices */
    rpGEOMETRYLOCKNORMALS = 4,  /**<Lock the normals */
    rpGEOMETRYLOCKTEXCOORDS = 8, /**<Lock the texture coordinates set 1*/
    rpGEOMETRYLOCKTEXCOORDS2 = 16, /**<Lock the texture coordinates set 2*/
    rpGEOMETRYLOCKPRELIGHT = 32, /**<Lock the pre-light values */
    rpGEOMETRYLOCKALL = 63,      /**<Combination of all the above */
    rpGEOMETRYLOCKMODEFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum RpGeometryLockMode RpGeometryLockMode;

enum _rpGeometryInstanceFlags
{
    rpGEOMETRYPERSISTENT = 0x01,
    rpGEOMETRYINSTANCE   = 0x02,
    rpGEOMETRYINSTANCEFLAGSFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum _rpGeometryInstanceFlags rpGeometryInstanceFlags;

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

typedef struct rpGeometryGlobals rpGeometryGlobals;
struct rpGeometryGlobals
{
        RwFreeList         *geomFreeList;
};

/**
 * \ingroup rpworlddatatypes
 * \typedef RpGeometry 
 * Geometry object. This should be considered an opaque type. 
 * Use the RpGeometry API functions to access.
 */
typedef struct RpGeometry RpGeometry;

/**
 * \ingroup rpworlddatatypes
 * \typedef RpMorphTarget 
 * Morph target -- vertex positions and normals. 
 * This should be considered an opaque type. 
 * Use RpMorphTarget API functions to access.
 */
typedef struct RpMorphTarget RpMorphTarget;

#if (!defined(DOXYGEN))
struct RpMorphTarget
{
        RpGeometry *parentGeom; 
        RwSphere   boundingSphere;
        RwV3d      *verts;
        RwV3d      *normals;
};
#endif /* (!defined(DOXYGEN)) */

typedef struct RpTriangle RpTriangle;

/**
 * \ingroup rpworlddatatypes
 * \struct RpTriangle 
 * This type represents a triangle in a geometry specified 
 * by three indices into the geometry's vertex list (vertIndex)
 * together with an  index in to the geometry's 
 * material list (matIndex) (see API function \ref RpGeometryGetTriangles)
 */
struct RpTriangle
{
    RwUInt16            vertIndex[3]; /**< vertex indices */
    RwInt16             matIndex; /**< Index into material list */
};

#if (!defined(DOXYGEN))
struct RpGeometry
{
        RwObject            object;     /* Generic type */

        RwResEntry         *repEntry;   /* Information for an instance */

        RwUInt16            lockedSinceLastInst; /* What has been locked since we last instanced - for re-instancing */
        RwInt16             refCount; /* Reference count (for keeping track of atomics referencing geometry) */

        RpMaterialList      matList;

        RwInt32             numTriangles; /* Quantity of various things (polys, verts and morph targtes) */
        RwInt32             numVertices;
        RwInt32             numMorphTargets;

        RpTriangle         *triangles; /* The triangles */

        RwRGBA             *preLitLum; /* The pre-lighting values */

        RwTexCoords        *texCoords[rwMAXTEXTURECOORDS]; /* Texture coordinates */

#ifdef RXPIPELINE
        RwSurfaceProperties ignoredSurfaceProps; /* Not used in pp rendering, but present
                                                  * so if pipe1 files are read and written these
                                                  * values are not lost
                                                  */
#else
        RwSurfaceProperties surfaceProps; /* Surface lighting properties */
#endif

        RpMeshHeader       *mesh;   /* The mesh - groups polys of the same material */

        RpMorphTarget      *morphTarget; /* The Morph Target */

        rpGeometryInstanceFlags instanceFlags; /* Persistent instance flags */
};
#endif /* (!defined(DOXYGEN)) */

typedef struct RpGeometryChunkInfo RpGeometryChunkInfo;
typedef struct RpGeometryChunkInfo _rpGeometry;

struct RpGeometryChunkInfo
{
        RwInt32             flags;  /* Compression flags */

        RwInt32             numTriangles;
        RwInt32             numVertices;

        RwInt32             numMorphTargets;

#ifdef RXPIPELINE
        RwSurfaceProperties ignoredSurfaceProps;
#else
        /* Surface lighting information */
        RwSurfaceProperties surfaceProps;
#endif
};

/* Callbacks */

/**
 * \ingroup rpworlddatatypes
 * \typedef RpGeometryCallBack 
 * \ref RpGeometryCallBack represents the simple callback function for the \ref RpGeometry object.
 * The callback may return NULL to terminate further callbacks on 
 * the geometry.
 * 
 * \param  geometry   Pointer to the current geometry, supplied by iterator.
 * \param  data  Pointer to developer-defined data structure.
 */
typedef RpGeometry *(*RpGeometryCallBack) (RpGeometry * geometry, void *data);

#ifdef RXPIPELINE

/**
 * \ingroup rpworlddatatypes
 * \typedef RpGeometrySortByMaterialCallBack 
 * \ref RpGeometrySortByMaterialCallBack is used by
 * \ref RpGeometrySortByMaterial in order to preserve the validity of plugin
 * data when the vertices in an \ref RpGeometry are sorted (and some possibly
 * duplicated).
 *
 * A vertex map table is provided to the callback - this contains, for each
 * vertex in the new geometry, the index of the corresponding vertex in the
 * original geometry.
 *
 * \param  oldGeom   Pointer to the source geometry.
 * \param  newGeom   Pointer to the new, sorted geometry.
 * \param  remapTable   pointer to the vertex map table
 * \param  numberOfEntries   Number of vertices in the new 
 * geometry (size of the map table)
 */
typedef void        (*RpGeometrySortByMaterialCallBack) (const RpGeometry *
                                                         oldGeom,
                                                         RpGeometry * newGeom,
                                                         RwUInt16 *

                                                         remapTable,
                                                         RwUInt16
                                                         numberOfEntries);
#endif

/* macros used in release builds */
#define RpGeometryGetFlagsMacro(_geom)  rwObjectGetFlags(_geom)

#if (!defined(RpGeometrySetFlagsMacro))
#define RpGeometrySetFlagsMacro(_geom, _flag)   \
MACRO_START                                     \
{                                               \
    rwObjectSetFlags(_geom, _flag);             \
}                                               \
MACRO_STOP
#endif /* (!defined(RpGeometrySetFlagsMacro)) */



#if (! ( defined(RWDEBUG) || defined(RWSUPPRESSINLINE) ))

#define RpGeometryGetFlags(geom) RpGeometryGetFlagsMacro(geom)
#define RpGeometrySetFlags(g,f) RpGeometrySetFlagsMacro(g,f)

#endif


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

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


    /* Create geometry for a 'space' marker */
extern RpGeometry  *RpGeometryCreateSpace(RwReal radius);

#if ( defined(RWDEBUG) || defined(RWSUPPRESSINLINE) )

/* Flags */
extern RwUInt32     RpGeometryGetFlags(const RpGeometry * geometry);
extern RpGeometry  *RpGeometrySetFlags(RpGeometry * geometry,
                                       RwUInt32 flags);
#endif

/* Creation and destruction */
extern RpGeometry  *RpGeometryCreate(RwInt32 numVert,
                                     RwInt32 numTriangles, RwInt32 flags);
extern RwBool       RpGeometryDestroy(RpGeometry * geometry);
extern RwBool       _rpGeometryInstance(RpGeometry *geometry, void *atom, RwBool destroy);
extern RpGeometry  *_rpGeometryAddRef(RpGeometry * geometry);

/* Getting size of geometry */
#if ( defined(RWDEBUG) || defined(RWSUPPRESSINLINE) )
extern RwInt32 RpGeometryGetNumTriangles(const RpGeometry *geometry);
extern RwInt32 RpGeometryGetNumVertices (const RpGeometry *geometry);
extern RwInt32 RpGeometryGetNumMaterials(const RpGeometry *geometry);
extern RwInt32 RpGeometryGetNumMorphTargets(const RpGeometry *geometry);
#else
#define RpGeometryGetNumTriangles(g)    ((g)->numTriangles)
#define RpGeometryGetNumVertices(g)     ((g)->numVertices)
#define RpGeometryGetNumMaterials(g)    ((g)->matList.numMaterials)
#define RpGeometryGetNumMorphTargets(g) ((g)->numMorphTargets)
#endif

/* Morph targets */
extern RwInt32      RpGeometryAddMorphTargets(RpGeometry * geometry, RwInt32 mtcount);
extern RwInt32      RpGeometryAddMorphTarget(RpGeometry * geometry);
extern RpGeometry  *RpGeometryRemoveMorphTarget(RpGeometry * geometry,
                                                RwInt32 morphTarget);
extern RpMorphTarget *RpGeometryGetMorphTarget(const RpGeometry *
                                               geometry,
                                               RwInt32 morphTarget);
extern const RpMorphTarget *RpMorphTargetCalcBoundingSphere(const
                                                            RpMorphTarget
                                                            * morphTarget,
                                                            RwSphere *
                                                            boundingSphere);
extern RpMorphTarget *RpMorphTargetSetBoundingSphere(RpMorphTarget *
                                                     morphTarget,
                                                     const RwSphere *
                                                     boundingSphere);
extern RwSphere    *RpMorphTargetGetBoundingSphere(RpMorphTarget *
                                                   morphTarget);

/* Lighting characteristics */
extern const RwSurfaceProperties *_rpGeometryGetSurfaceProperties(const
                                                                 RpGeometry
                                                                 *
                                                                 geometry);
extern RpGeometry  *_rpGeometrySetSurfaceProperties(RpGeometry * geometry,
                                                   const
                                                   RwSurfaceProperties *
                                                   surfaceProperties);

/* Accessing geometry contents */
extern RpTriangle  *RpGeometryGetTriangles(const RpGeometry * geometry);
extern RwRGBA      *RpGeometryGetPreLightColors(const RpGeometry *
                                                geometry);
extern RwTexCoords *RpGeometryGetVertexTexCoords(const RpGeometry *
                                                 geometry,
                                                 RwTextureCoordinateIndex
                                                 index);
extern RwV3d       *RpMorphTargetGetVertices(const RpMorphTarget *
                                             morphTarget);
extern RwV3d       *RpMorphTargetGetVertexNormals(const RpMorphTarget *
                                                  morphTarget);

extern RpGeometry  *RpGeometryForAllMaterials(RpGeometry * geometry,
                                              RpMaterialCallBack
                                              fpCallBack, void *pData);

/* Accessing the inards of geometry */
extern RpGeometry  *RpGeometryLock(RpGeometry * geometry,
                                   RwInt32 lockMode);
extern RpMaterial  *RpGeometryGetMaterial(const RpGeometry * geometry,
                                          RwInt32 matNum);
extern RpGeometry  *RpGeometryUnlock(RpGeometry * geometry);
extern const RpGeometry *RpGeometryForAllMeshes(const RpGeometry *
                                                geometry,
                                                RpMeshCallBack fpCallBack,
                                                void *pData);

extern const RpGeometry *RpGeometryTriangleSetVertexIndices(const
                                                            RpGeometry *
                                                            geometry,
                                                            RpTriangle *
                                                            triangle,
                                                            RwUInt16
                                                            vert1,
                                                            RwUInt16
                                                            vert2,
                                                            RwUInt16
                                                            vert3);
extern RpGeometry  *RpGeometryTriangleSetMaterial(RpGeometry * geometry,
                                                  RpTriangle * triangle,
                                                  RpMaterial * material);
extern const RpGeometry *RpGeometryTriangleGetVertexIndices(const
                                                            RpGeometry *
                                                            geometry,
                                                            const
                                                            RpTriangle *
                                                            triangle,
                                                            RwUInt16 *
                                                            vert1,
                                                            RwUInt16 *
                                                            vert2,
                                                            RwUInt16 *
                                                            vert3);
extern RpMaterial  *RpGeometryTriangleGetMaterial(const RpGeometry *
                                                  geometry,
                                                  const RpTriangle *
                                                  triangle);

/* Transforms geometry morph target vertices */
extern RpGeometry  *RpGeometryTransform(RpGeometry * geometry,
                                        const RwMatrix * matrix);

/* Binary format */

extern RwUInt32     RpGeometryStreamGetSize(const RpGeometry * geometry);
extern RpGeometry  *RpGeometryStreamRead(RwStream * stream);
extern const RpGeometry *RpGeometryStreamWrite(const RpGeometry *
                                               geometry,
                                               RwStream * stream);
extern RpGeometryChunkInfo *RpGeometryChunkInfoRead(RwStream * stream,
                                                    RpGeometryChunkInfo *
                                                    geometryChunkInfo,
                                                    RwInt32 * bytesRead);

/* Attaching toolkits */
extern RwInt32      RpGeometryRegisterPlugin(RwInt32 size,
                                             RwUInt32 pluginID,
                                             RwPluginObjectConstructor
                                             constructCB,
                                             RwPluginObjectDestructor
                                             destructCB,
                                             RwPluginObjectCopy copyCB);
extern RwInt32      RpGeometryRegisterPluginStream(RwUInt32 pluginID,
                                                   RwPluginDataChunkReadCallBack
                                                   readCB,
                                                   RwPluginDataChunkWriteCallBack
                                                   writeCB,
                                                   RwPluginDataChunkGetSizeCallBack
                                                   getSizeCB);
extern RwInt32      RpGeometrySetStreamAlwaysCallBack(
                        RwUInt32 pluginID,
                        RwPluginDataChunkAlwaysCallBack alwaysCB);
extern RwInt32      RpGeometryGetPluginOffset(RwUInt32 pluginID);
extern RwBool       RpGeometryValidatePlugins(const RpGeometry *
                                              geometry);

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */

#define RpGeometryGetSurfaceProperties(_geometry) \
    _rpGeometryGetSurfaceProperties(_geometry)

#define RpGeometrySetSurfaceProperties(_geometry, _surfaceProperties) \
    _rpGeometrySetSurfaceProperties(_geometry, _surfaceProperties)

#define rpGeometryAddRef(_geometry) \
    _rpGeometryAddRef(_geometry) 


/*--- Automatically derived from: ./baclump.h ---*/

/*
 * Clump and atomic handling.
 * Clumps and atomics are the movable rendered objects in the world
 *
 * Copyright (c) 1998 Criterion Software Ltd.
 */


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

/****************************** Object type ID ******************************/

/* Type IDs */

#define rpATOMIC 1
#define rpCLUMP 2

/* Interpolator flags */
enum RpInterpolatorFlag
{
    rpINTERPOLATORDIRTYINSTANCE = 0x01,
    rpINTERPOLATORDIRTYSPHERE = 0x02,
    rpINTERPOLATORFLAGFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum RpInterpolatorFlag rpInterpolatorFlag;

/**
 * \ingroup rpworlddatatypes
 * The bit-field type RpAtomicFlag specifies the options available for
 * controlling the behavior of atomics. See API function \ref RpAtomicSetFlags.
 *
 * \see RpAtomicSetFlags
 * \see RpAtomicGetFlags
 * \see RpWorldSectorForAllCollisionAtomics
 */

enum RpAtomicFlag
{
    rpATOMICCOLLISIONTEST = 0x01, /**<A generic collision flag to indicate
                                   * that the atomic should be considered
                                   * in collision tests.
                                   */
    rpATOMICRENDER = 0x04,      /**<The atomic is rendered if it is
                                 * in the view frustum.
                                 */

    rpATOMICFLAGFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum RpAtomicFlag RpAtomicFlag;

/**
 * \ingroup rpworlddatatypes
 * \ref RpAtomicSetGeomFlag defines how an atomic references a new geometry
 *
 * \see RpAtomicSetGeometry
 */
enum RpAtomicSetGeomFlag
{
    rpATOMICSAMEBOUNDINGSPHERE = 0x01, /**<The bounding-sphere for the
                                        * new geometry is assumed to be the
                                        * same as the old one, if any, and
                                        * should not be recalculated.
                                        */

    rpATOMICSETGEOMFLAGFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum RpAtomicSetGeomFlag RpAtomicSetGeomFlag;

enum RpAtomicPrivateFlag
{
    rpATOMICPRIVATEWORLDBOUNDDIRTY = 0x01,
    rpATOMICPRIVATEFLAGFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum RpAtomicPrivateFlag rpAtomicPrivateFlag;


/**
 * \ingroup rpworlddatatypes
 * \typedef RpAtomic
 * Atomic Geometry object. This should be
 * considered an opaque type. Use the RpAtomic API functions to access.
 */
typedef struct RpAtomic RpAtomic;

/**
 * \ingroup rpworlddatatypes
 * \typedef RpInterpolator
 * Morph Target Interpolator.
 * This should be considered an opaque type.
 * Use the RpInterpolator API functions to access.
 */
typedef struct RpInterpolator RpInterpolator;

#if (!defined(DOXYGEN))
struct RpInterpolator
{
        RwInt32             flags; /**< flags */
        RwInt16             startMorphTarget; /**< startMorphTarget */
        RwInt16             endMorphTarget; /**< endMorphTarget */
        RwReal              time; /**< time */
        RwReal              recipTime; /**< recipTime */
        RwReal              position; /**< position */
};
#endif /* (!defined(DOXYGEN)) */

/* More callbacks */

/**
 * \ingroup rpworlddatatypes
 * \typedef RpClump
 * Clump Geometry object. This should be
 * considered an opaque type. Use the RpClump API functions to access.
 */
typedef struct RpClump RpClump;

/**
 * \ingroup rpworlddatatypes
 * \typedef RpClumpCallBack
 * \ref RpClumpCallBack represents the
 * function called from \ref RwCameraForAllClumpsInFrustum and
 * \ref RwCameraForAllClumpsNotInFrustum when a clump lies inside the current camera's
 * view frustum.  It is also called from \ref RpWorldForAllClumps.  This function should
 * return a pointer to the current clump to indicate success.  The callback may return
 * NULL to terminate further callbacks on the clumps.
 *
 * \param  clump   Pointer to the current clump, supplied by
 * iterator.
 * \param  data  Pointer to developer-defined data structure.
 *
 * \return Pointer to the current clump.
 *
 * \see RpWorldForAllClumps
 * \see RpClumpGetCallBack
 * \see RpClumpSetCallBack
 * \see RwCameraForAllClumpsInFrustum
 * \see RwCameraForAllClumpsNotInFrustum
 */
typedef RpClump    *(*RpClumpCallBack) (RpClump * clump, void *data);

#if (!defined(DOXYGEN))
struct RpClump
{
        RwObject            object;

        /* Information about all the Atomics */
        RwLinkList          atomicList;

        /* The clump in the world */
        RwLLLink            inWorldLink;

        /* Clump callback */
        RpClumpCallBack     callback;

        /* Render frame - used to prevent multiple invocations
         * of the clump frustum callback
         */
        RwUInt16            renderFrame;
        RwUInt16            pad;
};
#endif /* (!defined(DOXYGEN)) */

/**
 * \ingroup rpworlddatatypes
 * \typedef RpAtomicCallBackRender
 * \ref RpAtomicCallBackRender represents the function called from
 * \ref RpAtomicRender when the specified atomic
 * lies inside the current camera's view frustum. The default callback
 * initiates execution of the atomic rendering pipeline. This function should
 * return a pointer to the atomic to indicate success.
 *
 * \param  atomic   Pointer to the current atomic, supplied by
 * iterator.
 *
 * \see RpAtomicRender
 */
typedef RpAtomic   *(*RpAtomicCallBackRender) (RpAtomic * atomic);

#if (!defined(DOXYGEN))
struct RpAtomic
{
    RwObjectHasFrame    object;

    /* Information for an instance */
    RwResEntry         *repEntry;

    /* Triangles making the object */
    RpGeometry         *geometry;

    /* Interpolated bounding sphere (in object space and world space) */
    RwSphere            boundingSphere;
    RwSphere            worldBoundingSphere;

    /* Connections to other atomics */
    RpClump            *clump;
    RwLLLink            inClumpLink;

    /* callbacks */
    RpAtomicCallBackRender renderCallBack;

    /* Interpolation animation pointer */
    RpInterpolator      interpolator;

    /* Counter for checks of collision/render has occured already */
    RwUInt16            renderFrame;
    RwUInt16            collisionFrame;

    /* Connections to sectors */
    RwLinkList          llWorldSectorsInAtomic;

#ifdef RXPIPELINE
    /* The Atomic instancing pipeline for this Atomic */
    RxPipeline         *pipeline;
#endif
};
#endif /* (!defined(DOXYGEN)) */

/**
 * \ingroup rpworlddatatypes
 * \typedef RpAtomicCallBack
 * \ref RpAtomicCallBack represents the function called from \ref RpWorldSectorForAllAtomics and
 * \ref RpClumpForAllAtomics for all atomics in a given world sector or clump.
 * This function should return a pointer to the current atomic to indicate
 * success. The callback may return NULL to terminate further callbacks on
 * the world sector.
 *
 * \param  atomic   Pointer to the current atomic, supplied by
 * iterator.
 * \param  data  Pointer to developer-defined data structure.
 */
typedef RpAtomic   *(*RpAtomicCallBack) (RpAtomic * atomic, void *data);

typedef struct RpTie RpTie;

struct RpTie
{
    /* Information for an atomic sector */
    RwLLLink            lAtomicInWorldSector; /* Atomics IN this ATOMIC SECTOR */
    RpAtomic           *apAtom;

    /* Information for a atomic */
    RwLLLink            lWorldSectorInAtomic; /* Atomic sectors HOLDING this atomic */
    RpWorldSector      *worldSector;
};

typedef struct RpClumpChunkInfo RpClumpChunkInfo;
typedef struct RpClumpChunkInfo _rpClump;

struct RpClumpChunkInfo
{
    RwInt32             numAtomics;
};

/****************************************************************************
 <macro/inline functionality

 */

/* NB this isn't protected against self-modifiy parameters
 * like "RpAtomicRender(atom++)" */

#define RpAtomicRenderMacro(_atomic)                                    \
    ((_atomic)->renderCallBack(_atomic))

#define RpAtomicGetGeometryMacro(_atomic)                               \
    ((_atomic)->geometry)

/* NB "RpAtomicSetRenderCallBack(atom++, callback)"                     \
 * will break it */

#if (!defined(RpAtomicSetRenderCallBackMacro))

#define RpAtomicSetRenderCallBackMacro(_atomic, _callback)              \
MACRO_START                                                             \
{                                                                       \
    (_atomic)->renderCallBack = (_callback);                            \
    if (!(_atomic)->renderCallBack)                                     \
    {                                                                   \
        (_atomic)->renderCallBack = AtomicDefaultRenderCallBack;        \
    }                                                                   \
}                                                                       \
MACRO_STOP

#endif /* (!defined(RpAtomicSetRenderCallBackMacro)) */

#define RpAtomicGetRenderCallBackMacro(_atomic)                         \
    ((_atomic)->renderCallBack)

#define RpAtomicGetInterpolatorMacro(_atomic)                         \
    (&((_atomic)->interpolator))

#define RpInterpolatorGetStartMorphTargetMacro(_intrp)                  \
    ((_intrp)->startMorphTarget)

#define RpInterpolatorGetEndMorphTargetMacro(_intrp)                    \
    ((_intrp)->endMorphTarget)

#define RpInterpolatorGetValueMacro(_intrp)                             \
    ((_intrp)->position)

#define RpInterpolatorGetScaleMacro(_intrp)                             \
    ((_intrp)->time)

/* NB "RpInterpolatorSetStartMorphTarget(interp++, target)"
 * will break it */

#define RpInterpolatorSetStartMorphTargetMacro(_intrp, _target)         \
    ((_intrp)->startMorphTarget = (RwInt16) (_target),                  \
     (_intrp)->flags |= (RwInt32)(rpINTERPOLATORDIRTYINSTANCE |         \
                                  rpINTERPOLATORDIRTYSPHERE     ),      \
     (_intrp))

/* NB "RpInterpolatorSetEndMorphTarget(interp++, target)"
 * will break it */

#define RpInterpolatorSetEndMorphTargetMacro(_intrp, _target)           \
    ((_intrp)->endMorphTarget = (RwInt16) (_target),                    \
     (_intrp)->flags |= (RwInt32)(rpINTERPOLATORDIRTYINSTANCE |         \
                                  rpINTERPOLATORDIRTYSPHERE     ),      \
     (_intrp))

/* NB "RpInterpolatorSetValue(interp++, value)"
 * will break it */

#define RpInterpolatorSetValueMacro(_intrp, _value)                     \
    ((_intrp)->position = (_value),                                     \
     (_intrp)->flags |= (RwInt32)(rpINTERPOLATORDIRTYINSTANCE |         \
                                  rpINTERPOLATORDIRTYSPHERE     ),      \
     (_intrp))

/* NB "RpInterpolatorSetScale(interp++, *(scale++))"
 * will break it */

#define RpInterpolatorSetScaleMacro(_intrp, _scale)                     \
    ((_intrp)->time = (_scale),                                         \
     (_intrp)->recipTime = (RwReal) (1.0) / (_scale),                   \
     (_intrp)->flags |= (RwInt32)(rpINTERPOLATORDIRTYINSTANCE |         \
                                  rpINTERPOLATORDIRTYSPHERE     ),      \
     (_intrp))
#define RpAtomicGetClumpMacro(_atomic)                                  \
    ((_atomic)->clump)

/* NB "RpAtomicGetBoundingSphere(atomic++)" will break it */

#define RpAtomicGetBoundingSphereMacro(_atomic)                         \
    ((((_atomic)->interpolator.flags & rpINTERPOLATORDIRTYSPHERE)?      \
      _rpAtomicResyncInterpolatedSphere(_atomic), 0: 0),                \
      &((_atomic)->boundingSphere))
#define RpAtomicGetFrameMacro(_atomic)                                  \
    ((RwFrame *) rwObjectGetParent(_atomic))

/* NB "RpClumpSetFrame(clump++, frame)" will break it */
#if (!defined(RpClumpSetFrameMacro))
#define RpClumpSetFrameMacro(_clump, _frame)                            \
    (rwObjectSetParent(_clump, _frame),                                 \
     (_clump))
#endif /* (!defined(RpClumpSetFrameMacro)) */

#define RpClumpGetFrameMacro(_clump)                                    \
    ((RwFrame *) rwObjectGetParent(_clump))

/* NB "RpAtomicSetFlags(atomic++, flags)" will break it */
#if (!defined(RpAtomicSetFlagsMacro))
#define RpAtomicSetFlagsMacro(_atomic, _flags)                          \
    (rwObjectSetFlags(_atomic, _flags),                                 \
     (_atomic))
#endif /* (!defined(RpAtomicSetFlagsMacro)) */

#define RpAtomicGetFlagsMacro(_atomic)                                  \
    (rwObjectGetFlags(_atomic))

#if (! ( defined(RWDEBUG) || defined(RWSUPPRESSINLINE) ))

#define RpAtomicRender(_atomic) \
    RpAtomicRenderMacro(_atomic)

#define RpAtomicGetGeometry(_atomic) \
    RpAtomicGetGeometryMacro(_atomic)

#define RpAtomicSetRenderCallBack(_atomic, _callback) \
    RpAtomicSetRenderCallBackMacro(_atomic, _callback)

#define RpAtomicGetRenderCallBack(_atomic) \
    RpAtomicGetRenderCallBackMacro(_atomic)

#define RpAtomicGetInterpolator(_atomic) \
    RpAtomicGetInterpolatorMacro(_atomic)

#define RpInterpolatorGetStartMorphTarget(_intrp) \
    RpInterpolatorGetStartMorphTargetMacro(_intrp)

#define RpInterpolatorGetEndMorphTarget(_intrp) \
    RpInterpolatorGetEndMorphTargetMacro(_intrp)

#define RpInterpolatorGetValue(_intrp) \
    RpInterpolatorGetValueMacro(_intrp)

#define RpInterpolatorGetScale(_intrp) \
    RpInterpolatorGetScaleMacro(_intrp)

#define RpInterpolatorSetStartMorphTarget(_intrp, _target) \
    RpInterpolatorSetStartMorphTargetMacro(_intrp, _target)

#define RpInterpolatorSetEndMorphTarget(_intrp, _target) \
    RpInterpolatorSetEndMorphTargetMacro(_intrp, _target)

#define RpInterpolatorSetValue(_intrp, _value) \
    RpInterpolatorSetValueMacro(_intrp, _value)

#define RpInterpolatorSetScale(_intrp, _scale) \
    RpInterpolatorSetScaleMacro(_intrp, _scale)

#define RpAtomicGetClump(_atomic) \
    RpAtomicGetClumpMacro(_atomic)

#define RpAtomicGetBoundingSphere(_atomic) \
    RpAtomicGetBoundingSphereMacro(_atomic)

#define RpAtomicGetFrame(_atomic) \
    RpAtomicGetFrameMacro(_atomic)

#define RpClumpSetFrame(_clump, _frame) \
    RpClumpSetFrameMacro(_clump, _frame)

#define RpClumpGetFrame(_clump) \
    RpClumpGetFrameMacro(_clump)

#define RpAtomicSetFlags(_atomic, _flags) \
    RpAtomicSetFlagsMacro(_atomic, _flags)

#define RpAtomicGetFlags(_atomic) \
    RpAtomicGetFlagsMacro(_atomic)

#endif /* (! ( defined(RWDEBUG) || defined(RWSUPPRESSINLINE) )) */

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

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


/* Macro version of RpAtomicSetRenderCallBack needs this */
extern RpAtomic *
AtomicDefaultRenderCallBack(RpAtomic * atomic);

extern void
_rpAtomicResyncInterpolatedSphere(RpAtomic * atomic);

extern const RwSphere *
RpAtomicGetWorldBoundingSphere(RpAtomic *  atomic);

/* Enumeration */
extern RpClump *
RpClumpForAllAtomics(RpClump * clump,
                     RpAtomicCallBack callback,
                     void *pData);

/* Frames */
extern RpAtomic *
RpAtomicSetFrame(RpAtomic * atomic,
                 RwFrame * frame);

/* Create a space marking clump */
extern RpClump *
RpClumpCreateSpace(const RwV3d * position,
                   RwReal radius);

/* Functions to help collision detection */

/* Instancing and rendering */
extern RpClump *
RpClumpRender(RpClump * clump);

extern RpClump *
RpClumpRemoveAtomic(RpClump * clump,
                    RpAtomic * atomic);

extern RpClump *
RpClumpAddAtomic(RpClump * clump,
                 RpAtomic * atomic);

/* Creation and destruction of clumps */
extern RwBool
RpClumpDestroy(RpClump * clump);

extern RpClump *
RpClumpCreate(void);

extern RpClump *
RpClumpClone(RpClump * clump);

/* Creation and destruction of atomics*/
extern RwBool
RpAtomicDestroy(RpAtomic * atomic);

extern RpAtomic *
RpAtomicClone(RpAtomic * atomic);

extern RpAtomic *
RpAtomicCreate(void);

/* Setting and getting geometry for an atomic */
extern RpAtomic *
RpAtomicSetGeometry(RpAtomic * atomic,
                    RpGeometry * geometry,
                    RwUInt32 flags);

/* Frustum callbacks */
extern RpClump *
RpClumpSetCallBack(RpClump * clump,
                   RpClumpCallBack callback);

extern RpClumpCallBack
RpClumpGetCallBack(RpClump * clump);

/* The number of atomics in a clump */
extern RwInt32
RpClumpGetNumAtomics(RpClump * clump);

/* Atomic render callback */

/* Pipelines */

#if (!defined(RXPIPELINE))
extern RwRenderPipeline *
RpAtomicGetRenderPipeline(void);
#endif /* (!defined(RXPIPELINE)) */

/* RXPIPELINE */

/* Binary format */
extern RwUInt32
RpAtomicStreamGetSize(RpAtomic * atomic);

extern RpAtomic *
RpAtomicStreamRead(RwStream * stream);

extern RpAtomic *
RpAtomicStreamWrite(RpAtomic * atomic,
                    RwStream * stream);

extern RwUInt32
RpClumpStreamGetSize(RpClump * clump);

extern RpClump *
RpClumpStreamRead(RwStream * stream);

extern RpClump *
RpClumpStreamWrite(RpClump * clump,
                   RwStream * stream);

extern RpClumpChunkInfo *
RpClumpChunkInfoRead(RwStream * stream,
                     RpClumpChunkInfo *
                     clumpChunkInfo,
                     RwInt32 * bytesRead);

/* Attaching toolkits */
extern RwInt32
RpAtomicRegisterPlugin(RwInt32 size,
                       RwUInt32 pluginID,
                       RwPluginObjectConstructor constructCB,
                       RwPluginObjectDestructor destructCB,
                       RwPluginObjectCopy copyCB);

extern RwInt32
RpClumpRegisterPlugin(RwInt32 size,
                      RwUInt32 pluginID,
                      RwPluginObjectConstructor constructCB,
                      RwPluginObjectDestructor destructCB,
                      RwPluginObjectCopy copyCB);

extern RwInt32
RpAtomicRegisterPluginStream(RwUInt32 pluginID,
                             RwPluginDataChunkReadCallBack
                             readCB,
                             RwPluginDataChunkWriteCallBack
                             writeCB,
                             RwPluginDataChunkGetSizeCallBack
                             getSizeCB);

extern RwInt32
RpAtomicSetStreamAlwaysCallBack(RwUInt32 pluginID,
                                     RwPluginDataChunkAlwaysCallBack alwaysCB);

extern RwInt32
RpClumpRegisterPluginStream(RwUInt32 pluginID,
                            RwPluginDataChunkReadCallBack  readCB,
                            RwPluginDataChunkWriteCallBack writeCB,
                            RwPluginDataChunkGetSizeCallBack getSizeCB);

extern RwInt32
RpClumpSetStreamAlwaysCallBack(RwUInt32 pluginID,
                                    RwPluginDataChunkAlwaysCallBack alwaysCB);

extern RwInt32
RpAtomicGetPluginOffset(RwUInt32 pluginID);

extern RwInt32
RpClumpGetPluginOffset(RwUInt32 pluginID);

extern RwBool
RpAtomicValidatePlugins(const RpAtomic * atomic);

extern RwBool
RpClumpValidatePlugins(const RpClump * clump);

#if ( defined(RWDEBUG) || defined(RWSUPPRESSINLINE) )
extern RwFrame *
RpAtomicGetFrame(const RpAtomic * atomic);

extern RwFrame *
RpClumpGetFrame(const RpClump * clump);

extern RpClump *
RpClumpSetFrame(RpClump * clump,
                RwFrame * frame);

/* Flags */
extern RpAtomic *
RpAtomicSetFlags(RpAtomic * atomic,
                 RwUInt32 flags);

extern RwUInt32
RpAtomicGetFlags(const RpAtomic * atomic);

extern RwSphere *
RpAtomicGetBoundingSphere(RpAtomic * atomic);

extern RwInt32
RpInterpolatorGetEndMorphTarget(const RpInterpolator * interpolator);

extern RwInt32
RpInterpolatorGetStartMorphTarget(const RpInterpolator * interpolator);

extern RwReal
RpInterpolatorGetValue(const RpInterpolator * interpolator);

extern RwReal
RpInterpolatorGetScale(const RpInterpolator * interpolator);

extern RpInterpolator *
RpInterpolatorSetEndMorphTarget(RpInterpolator * interpolator,
                                RwInt32 morphTarget);

extern RpInterpolator *
RpInterpolatorSetStartMorphTarget(RpInterpolator *  interpolator,
                                  RwInt32 morphTarget);

extern RpInterpolator *
RpInterpolatorSetValue(RpInterpolator *  interpolator,
                       RwReal value);

extern RpInterpolator *
RpInterpolatorSetScale(RpInterpolator * interpolator,
                       RwReal scale);

extern RpAtomic *
RpAtomicRender(RpAtomic * atomic);

/* Building clumps */
extern RpClump *
RpAtomicGetClump(const RpAtomic * atomic);

extern RpInterpolator *
RpAtomicGetInterpolator(RpAtomic * atomic);

extern RpGeometry *
RpAtomicGetGeometry(const RpAtomic * atomic);

extern void
RpAtomicSetRenderCallBack(RpAtomic * atomic,
                          RpAtomicCallBackRender callback);

extern RpAtomicCallBackRender
RpAtomicGetRenderCallBack(const RpAtomic * atomic);

#endif

/* ( defined(RWDEBUG) || defined(RWSUPPRESSINLINE) ) */

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */

#ifndef RXPIPELINE
#define  RpAtomicGetRenderPipeline() RpAtomicGetRenderPipeline()
#endif                          /* RXPIPELINE */


/*--- Automatically derived from: pipe/p2/sky2/matputil.h ---*/

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

#define RWPS2RESHEADERFROMRESENTRY(resEntry) \
    ((rwPS2ResEntryHeader *)(resEntry + 1))

#if ( defined(RWDEBUG) || defined(RWSUPPRESSINLINE) )

extern RwMeshCache *
rpGeometryGetMeshCache(RpGeometry *geometry,
                       RwUInt32 numMeshes);

extern RwMeshCache *
rpAtomicGetMeshCache(RpAtomic *atomic,
                     RwUInt32 numMeshes);

extern RwMeshCache *
rpWorldSectorGetMeshCache(RpWorldSector *worldSector,
                          RwUInt32 numMeshes);

extern RwResEntry **
rwMeshCacheGetEntryRef(const RwMeshCache * meshCache,
                       RwUInt32 meshIndex);

#endif /* ( defined(RWDEBUG) || defined(RWSUPPRESSINLINE) ) */

extern void 
rpObjectDestroyMeshCache(RwMeshCache *meshCache);

extern RwMeshCache **
rpObjectGetMeshCache(RwMeshCache **meshCacheRef,
                     RwUInt32 numMeshes);

#ifdef    __cplusplus
}
#endif /* __cplusplus */


#if (! (defined(RWDEBUG) || defined(RWSUPPRESSINLINE)) )

#define rpGeometryGetMeshCache(_geometry, _numMeshes) \
    (*rpObjectGetMeshCache(&RWMESHCACHEFROMGEOMETRY(_geometry), _numMeshes))

#define rpAtomicGetMeshCache(_atomic, _numMeshes) \
    (*rpObjectGetMeshCache(&RWMESHCACHEFROMATOMIC(_atomic), _numMeshes))

#define rpWorldSectorGetMeshCache(_sector, _numMeshes) \
    (*rpObjectGetMeshCache(&RWMESHCACHEFROMWORLDSECTOR(_sector), _numMeshes))

#define rwMeshCacheGetEntryRef(_cache, _index) (&(_cache)->meshes[_index])

#endif /* (! (defined(RWDEBUG) || defined(RWSUPPRESSINLINE)) ) */


/*--- Automatically derived from: ./baworld.h ---*/

/*
 * World handling.
 * World give objects scope, and provide a mechanism for
 * efficiency static object rendering.
 *
 * Copyright (c) 1998 Criterion Software Ltd.
 *
 */

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

/* Type ID */
#define rpWORLD 7

/* RpWorld private flags (in RwObject) */
enum RpWorldPrivateFlag
{
    rpWORLDSINGLEMALLOC = 0x01,
    rpWORLDPRIVATEFLAGFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum RpWorldPrivateFlag RpWorldPrivateFlag;

/**
 * \ingroup rpworlddatatypes
 * The bit-field type \ref RpWorldFlag specifies the options available
 * for creating the static geometry component of a world (see API function \ref RpWorldSetFlags):
 */
enum RpWorldFlag
{
    rpWORLDTRISTRIP = 0x01,     /**<This world's meshes can be rendered
                                   as tri strips */
    rpWORLDTEXTURED = 0x04,     /**<This world has one set of texture coordinates */
    rpWORLDPRELIT = 0x08,       /**<This world has luminance values */
    rpWORLDNORMALS = 0x10,      /**<This world has normals */
    rpWORLDLIGHT = 0x20,        /**<This world will be lit */
    rpWORLDMODULATEMATERIALCOLOR = 0x40, /**<Modulate material color with
                                            vertex colors (pre-lit + lit) */
    rpWORLDTEXTURED2 = 0x80, /**<This world has 2 set of texture coordinates */

    /*
     * These flags are stored in the flags field in an RwObject, the flag field is 8bit.
     */

    rpWORLDSECTORSOVERLAP = 0x40000000,
    rpWORLDFLAGFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum RpWorldFlag RpWorldFlag;

/* Maximum depth of BSP tree */
#define rpWORLDMAXBSPDEPTH 64

/****************************************************************************
 Global types
 */


/**
 * \ingroup rpworlddatatypes
 * \ref RpWorldRenderOrder
 * represents the options available for
 * the rendering order of world sectors in the camera's view frustum (see
 * API function \ref RpWorldSetRenderOrder).
 */
enum RpWorldRenderOrder
{
    rpWORLDRENDERNARENDERORDER = 0,
    rpWORLDRENDERFRONT2BACK,  /**<Renders nearest sectors first */
    rpWORLDRENDERBACK2FRONT, /**<Renders furthest sectors first */
    rpWORLDRENDERORDERFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum RpWorldRenderOrder RpWorldRenderOrder;

/**
 * \ingroup rpworlddatatypes
 * \typedef RpWorldSectorCallBackRender
 * \ref RpWorldSectorCallBackRender represents the function called from
 * \ref RpWorldSectorRender when the specified world sector lies inside the
 * current camera's view frustum. The default callback initiates execution of
 * the world sector rendering pipeline. This function should return a pointer
 * to the world sector to indicate success
 *
 * \return Pointer to the world sector.
 *
 * \param  worldSector   Pointer to the world sector to be
 * rendered
 */
typedef RpWorldSector *(*RpWorldSectorCallBackRender) (RpWorldSector *
                                                       worldSector);

/**
 * \ingroup rpworlddatatypes
 * \typedef RpWorld
 * World object. This should be considered an opaque type.
 * Use the RpWorld API functions to access.
 */
typedef struct RpWorld RpWorld;

#if (!defined(DOXYGEN))
struct RpWorld
{
    RwObject            object;

    RpWorldRenderOrder  renderOrder;

    /* Materials */
    RpMaterialList      matList;

    /* The world stored as a BSP tree */
    RpSector           *rootSector;

    /* Render frame used when last rendered */
    RwInt32             numClumpsInWorld;
    RwLLLink           *currentClumpLink;

    /* All the clumps in the world */
    RwLinkList          clumpList;

    /* All of the lights in the world */
    RwLinkList          lightList;

    /* Directional lights in the world */
    RwLinkList          directionalLightList;

    /* The worlds origin offset */
    RwV3d               worldOrigin;

    /* Bounding box around the whole world */
    RwBBox              boundingBox;

    /* Surface properties */
    RwSurfaceProperties surfaceProps;

    /* The callbacks functions */
    RpWorldSectorCallBackRender renderCallBack;

#ifdef RXPIPELINE
    RxPipeline         *pipeline;
#endif                          /* RXPIPELINE */
};
#endif /* (!defined(DOXYGEN)) */

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

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

extern RwPluginRegistry worldTKList;

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */

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

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

extern RwBool       _rpWorldFindBBox(RpWorld * world,
                                    RwBBox * boundingBox);


/* These stealth-API */
extern RwBool       _rpWorldForAllGlobalLights(RpLightCallBack callBack,
                                              void *pData);
extern RpWorldSector *_rpWorldSectorForAllLocalLights(RpWorldSector *
                                                     sector,
                                                     RpLightCallBack
                                                     callBack,
                                                     void *pData);

extern RpWorldSector *_rpSectorDefaultRenderCallBack(RpWorldSector *
                                                    sector);

/* Accessing worlds geometry */
extern RpWorld     *RpWorldLock(RpWorld * world);
extern RpWorld     *RpWorldUnlock(RpWorld * world);

/* Managing a list of the worlds */
extern void         _rpWorldRegisterWorld(RpWorld * world,
                                         RwUInt32 memorySize);
extern void         _rpWorldUnregisterWorld(RpWorld * world);

/* Hook into world management */
extern RwBool       RpWorldPluginAttach(void);

/* Enumerating objects in the world */
extern RpWorld     *RpWorldForAllClumps(RpWorld * world,
                                        RpClumpCallBack fpCallBack,
                                        void *pData);
extern RpWorld     *RpWorldForAllMaterials(RpWorld * world,
                                           RpMaterialCallBack fpCallBack,
                                           void *pData);
extern RpWorld     *RpWorldForAllLights(RpWorld * world,
                                        RpLightCallBack fpCallBack,
                                        void *pData);
extern RpWorld     *RpWorldForAllWorldSectors(RpWorld * world,
                                              RpWorldSectorCallBack
                                              fpCallBack, void *pData);

/* Rendering */
extern RpWorld     *RpWorldRender(RpWorld * world);
extern RpWorld     *RpWorldSetRenderOrder(RpWorld * world,
                                          RpWorldRenderOrder renderOrder);
extern RpWorldRenderOrder RpWorldGetRenderOrder(const RpWorld * world);
#ifndef RXPIPELINE
extern RwRenderPipeline *_rpWorldGetRenderPipeline(void);
#endif                          /* RXPIPELINE */

/* Creation/destruction */
extern RwBool       RpWorldDestroy(RpWorld * world);
extern RpWorld     *RpWorldCreate(RwBBox * boundingBox);

/* Accessing a worlds materials */
extern RpMaterial  *RpWorldGetMaterial(const RpWorld * world,
                                       RwInt32 matNum);
extern RwInt32      RpWorldGetNumMaterials(const RpWorld * world);

/* Clumps */
extern RwInt32      RpWorldGetNumClumps(RpWorld * world);

/* Getting/setting */
extern const RwBBox *RpWorldGetBBox(const RpWorld * world);
extern const RwV3d *RpWorldGetOrigin(const RpWorld * world);
extern RpWorld     *_rpWorldSetSurfaceProperties(RpWorld * world,
                                                const RwSurfaceProperties
                                                * surface);
extern const RwSurfaceProperties *
   _rpWorldGetSurfaceProperties(const RpWorld *world);

/* Sector callbacks */
extern RpWorld     *RpWorldSetSectorRenderCallBack(RpWorld * world,
                                                   RpWorldSectorCallBackRender
                                                   fpCallBack);
extern RpWorldSectorCallBackRender RpWorldGetSectorRenderCallBack(const
                                                                  RpWorld
                                                                  *
                                                                  world);

/* Getting world from sector */
extern RpWorld     *RpWorldSectorGetWorld(const RpWorldSector * sector);

/* Flags */
extern RpWorld     *RpWorldSetFlags(RpWorld * world, RwUInt32 flags);
extern RwUInt32     RpWorldGetFlags(const RpWorld * world);

/* Instancing polygons */
extern const RpWorld *RpWorldWorldSectorInstancePolygon(const RpWorld *
                                                        world,
                                                        const
                                                        RpWorldSector *
                                                        worldSector,
                                                        RwInt32 polyIndex,
                                                        RpWorldVertex *
                                                        verticesOut,
                                                        RpMaterial **
                                                        materialOut);

extern RwInt32      RpWorldRegisterPlugin(RwInt32 size, RwUInt32 pluginID,
                                          RwPluginObjectConstructor
                                          constructCB,
                                          RwPluginObjectDestructor
                                          destructCB,
                                          RwPluginObjectCopy copyCB);
extern RwInt32      RpWorldRegisterPluginStream(RwUInt32 pluginID,
                                                RwPluginDataChunkReadCallBack
                                                readCB,
                                                RwPluginDataChunkWriteCallBack
                                                writeCB,
                                                RwPluginDataChunkGetSizeCallBack
                                                getSizeCB);
extern RwInt32      RpWorldSetStreamAlwaysCallBack(
                        RwUInt32 pluginID,
                        RwPluginDataChunkAlwaysCallBack alwaysCB);
extern RwInt32      RpWorldGetPluginOffset(RwUInt32 pluginID);
extern RwBool       RpWorldValidatePlugins(RpWorld * world);

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */

#define RpWorldSetSurfaceProperties(_world, _surface) \
    _rpWorldSetSurfaceProperties(_world, _surface)

#define RpWorldGetSurfaceProperties(_world) \
    _rpWorldGetSurfaceProperties(_world)

#ifndef RXPIPELINE
#define RpWorldGetRenderPipeline()  \
     _rpWorldGetRenderPipeline()
#endif                          /* RXPIPELINE */

#define rpWorldFindBBox(_world, _boundingBox) \
    _rpWorldFindBBox(_world, _boundingBox)

#define rpWorldForAllGlobalLights(_callBack, _pData) \
    _rpWorldForAllGlobalLights(_callBack, _pData)

#define rpWorldSectorForAllLocalLights(_sector, _callBack, _pData) \
    _rpWorldSectorForAllLocalLights(_sector, _callBack, _pData)

#define _rpWorldLock(_world) \
    RpWorldLock(_world)

#define _rpWorldUnlock(_world) \
    RpWorldUnlock(_world)

#define rpWorldLock(_world) \
    RpWorldLock(_world)

#define rpWorldUnlock(_world) \
    RpWorldUnlock(_world)


/*--- Automatically derived from: pipe/p2/p2stdclsw.h ---*/

#if (!defined(RXPIPELINE))
#define RXPIPELINE
#endif /* (!defined(RXPIPELINE)) */
typedef RpLight *RxLight;
#ifdef    __cplusplus
extern "C"
{
#endif                          /* __cplusplus */

extern RxClusterDefinition RxClLights; /* Uses the RxLight type (see above) */

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */


#if (((defined(SKY) || defined(SKY_OSTYPES_H)) && !defined(NULLSKY_DRVMODEL_H)))


/**
 * \ingroup rpworldp2sky2
 * \ref RxPS2ObjectType
 * Values identifying different PS2-specific object types.
 */
enum RxPS2ObjectType
{
    rxOBJTYPE_WORLDSECTOR = 0, /**< The object is an \ref RpWorldSector */
    rxOBJTYPE_ATOMIC      = 1, /**< The object is an \ref RpAtomic */
    rxOBJTYPE_IM3D        = 2, /**< The object is an _rwIm3DPoolStash */
    rxOBJTYPEFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum RxPS2ObjectType RxPS2ObjectType;

typedef union RxObjUnion RxObjUnion;
/**
 * \ingroup rpworldp2sky2
 * \union RxObjUnion
 * A union used by the \ref RxPS2DMASessionRecord structure
 */
union RxObjUnion
{
    RpWorldSector *worldSector; /**< \ref RpWorldSector pointer union member */
    RpAtomic *atomic;           /**< \ref RpAtomic pointer union member */
    void *agnostic;             /**< void pointer union member */
};


typedef struct RxPS2DMASessionRecord RxPS2DMASessionRecord;
/**
 * \ingroup rpworldp2sky2
 * \struct RxPS2DMASessionRecord
 * Describes information for an object's DMA packet(s)
 */
struct RxPS2DMASessionRecord
{
    RxPS2ObjectType objType;       /**< \ref RxPS2ObjectType type identifier */
    RxObjUnion sourceObject;       /**< \ref RxObjUnion referencing the source object */
    RwFrustumTestResult inFrustum; /**< \ref RwFrustumTestResult frustum test result */
    RwUInt16 serialNum;            /**< \ref RwUInt16 serial number used when
                                    *   choosing whether to re-instance object data */
    RwUInt8 vu1CodeIndex;             /**< \ref RwUInt8 index into VU code array,
                                    *   specifying the transform to use. */
    RwUInt8 primType;              /**< \ref RwUInt8 code for the primitive type that will
                                    *   be submitted by VU1 to the GS (see GS manual ~p113). */
    RxSkyTransTypeFlags transType; /**< \ref RxSkyTransTypeFlags flags, specifying the type
                                    *   of transform to use (ortho/persp, fog/not, etc). */
};


typedef struct RxPS2Mesh RxPS2Mesh;
/**
 * \ingroup rpworldp2sky2
 * \struct RxPS2Mesh
 * Describes PS2-specific information for a mesh
 */
struct RxPS2Mesh
{
    const RpMesh *mesh;          /**< A pointer to the source \ref RpMesh */
    RwResEntry  **cacheEntryRef; /**< A pointer to a pointer to a \ref RwResEntry
                                  *   holding the instance data for the mesh */
    RwUInt32      meshNum;       /**< The number of the current mesh within
                                  *   its parent object (from zero) */
    RwUInt32      pad;           /**< Alignment padding to 16 bytes/1 QW */
};

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

extern RxClusterDefinition RxClPS2DMAChain ;
extern RxClusterDefinition RxClPS2LightsBlock ;
extern RxClusterDefinition RxClPS2DMASessionRecord ;
extern RxClusterDefinition RxClPS2Mesh ;
extern RxClusterDefinition RxClPS2xyz ;
extern RxClusterDefinition RxClPS2uv;
extern RxClusterDefinition RxClPS2uv2;
extern RxClusterDefinition RxClPS2rgba;
extern RxClusterDefinition RxClPS2normal;

extern RxClusterDefinition RxClPS2user1;
extern RxClusterDefinition RxClPS2user2;
extern RxClusterDefinition RxClPS2user3;
extern RxClusterDefinition RxClPS2user4;

extern RwChar              RxPS2AttributeSet[];

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */

#endif /* (((defined(SKY) || defined(SKY_OSTYPES_H)) && !defined(NULLSKY_DRVMODEL_H))) */


/*--- Automatically derived from: pipe/p2/sky2/nodeps2objallinone.h ---*/

/****************************************************************************
 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);


#ifdef    __cplusplus
}
#endif                          /* __cplusplus */


/*--- Automatically derived from: pipe/p2/sky2/ps2allmat.h ---*/

#define REDEBUGx
#define DMAALIGN
#define FASTMORPH

#if (!defined(FASTMORPH))
#define FMADD (0)
#else /* (!defined(FASTMORPH)) */
#define FMADD (2)
#endif /* (!defined(FASTMORPH)) */


typedef struct rwPS2AllClusterInstanceInfo rwPS2AllClusterInstanceInfo;
struct rwPS2AllClusterInstanceInfo
{
    RwUInt32             attrib;                        /**< Internal Use */
    RwUInt32             stride;                        /**< Internal Use */
};                                                      /**< Internal Use */


typedef struct rwPS2AllFieldRec rwPS2AllFieldRec;
struct rwPS2AllFieldRec
{
    int numVerts;                                       /**< Internal Use */
#if (defined(FASTMORPH))
    int morphNumVerts;                                  /**< Internal Use */
#endif /* (defined(FASTMORPH)) */
    int dataoffset;                                     /**< Internal Use */
#if (defined(FASTMORPH))
    int morphDataoffset;                                /**< Internal Use */
#endif /* (defined(FASTMORPH)) */
    short skip;                                         /**< Internal Use */
#if (defined(FASTMORPH))
    short morphSkip;                                    /**< Internal Use */
#endif /* (defined(FASTMORPH)) */
    short reverse;                                      /**< Internal Use */
    unsigned char vuoffset;                             /**< Internal Use */
#if (!defined(FASTMORPH))
    unsigned char pad[3];                               /**< Internal Use */
#else /* (!defined(FASTMORPH)) */
    unsigned char pad[1];                               /**< Internal Use */
#endif /* (!defined(FASTMORPH)) */
};

typedef struct rwPS2AllResEntryFormat rwPS2AllResEntryFormat;
struct rwPS2AllResEntryFormat
{
    int batchSize;                                      /**< Internal Use */
    int batchesPerTag;                                  /**< Internal Use */
#if (defined(FASTMORPH))
    int morphBatchSize;                                 /**< Internal Use */
    int morphBatchesPerTag;                             /**< Internal Use */
#endif /* (defined(FASTMORPH)) */
    rwPS2AllFieldRec fieldRec[CL_MAXCL + FMADD];        /**< Internal Use */
};

/**
 * \ingroup rpworldp2sky2
 * \ref RxPipelineNodePS2AllMatCallBackType
 * PS2AllMat.csl callback types (see \ref RxPipelineNodePS2AllMatSetCallBack
 * and \ref RxPipelineNodePS2AllSetCallBack), in order of execution within
 * the node.
 */
enum RxPipelineNodePS2AllMatCallBackType
{
    rxPS2ALLMATCALLBACKNACALLBACK          = 0,
    rxPS2ALLMATCALLBACKIM3DPREMESH         = 1, /**< Temporary, for internal use */
    rxPS2ALLMATCALLBACKMESHINSTANCETEST    = 2, /**< Performs per-mesh reinstance tests
                                                 *   (see \ref RxPipelineNodePS2AllMatMeshInstanceTestCallBack) */
    rxPS2ALLMATCALLBACKRESENTRYALLOC       = 3, /**< Allocates memory for instance data
                                                 *   (see \ref RxPipelineNodePS2AllMatResEntryAllocCallBack) */
    rxPS2ALLMATCALLBACKINSTANCE            = 4, /**< Instances a mesh and performs static data uploads
                                                 *   (see \ref RxPipelineNodePS2AllMatInstanceCallBack) */
    rxPS2ALLMATCALLBACKBRIDGE              = 5, /**< Selects VU code and sets up material properties
                                                 *   (see \ref RxPipelineNodePS2AllMatBridgeCallBack) */
    rxPS2ALLMATCALLBACKIM3DPOSTMESH        = 6, /**< Temporary, for internal use */
    rxPS2ALLMATCALLBACKIM3DMESHSPLIT       = 7, /**< Temporary, for internal use */
    rxPS2ALLMATCALLBACKPOSTMESH            = 8, /**< Performs per-mesh post-render tasks
                                                 *   (see \ref RxPipelineNodePS2AllMatPostMeshCallBack) */

    rxPS2ALLMATCALLBACKFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum RxPipelineNodePS2AllMatCallBackType RxPipelineNodePS2AllMatCallBackType;

typedef struct RxPS2AllPipeData RxPS2AllPipeData;

typedef RwBool (*RxPipelineNodePS2AllMatIm3DPreMeshCallBack)
    (RxPS2AllPipeData *ps2AllPipeData);

typedef RwBool (*RxPipelineNodePS2AllMatMeshInstanceTestCallBack)
    (RxPS2AllPipeData *ps2AllPipeData);

typedef RwResEntry *(*RxPipelineNodePS2AllMatResEntryAllocCallBack)
    (RxPS2AllPipeData *ps2AllPipeData,
     RwResEntry **repEntry,
     RwUInt32 size,
     RwResEntryDestroyNotify destroyNotify);

typedef RwBool (*RxPipelineNodePS2AllMatInstanceCallBack)
    (RxPS2AllPipeData *ps2AllPipeData, void **clusterData, RwUInt32 numClusters);

typedef RwBool (*RxPipelineNodePS2AllMatBridgeCallBack)
    (RxPS2AllPipeData *ps2AllPipeData);

typedef RwBool (*RxPipelineNodePS2AllMatIm3DPostMeshCallBack)
    (RxPS2AllPipeData *ps2AllPipeData);

typedef RwBool (*RxPipelineNodePS2AllMatIm3DMeshSplitCallBack)
    (RxPS2AllPipeData *ps2AllPipeData);

typedef RwBool (*RxPipelineNodePS2AllMatPostMeshCallBack)
    (RxPS2AllPipeData *ps2AllPipeData);

typedef struct rxNodePS2AllMatPvtData rxNodePS2AllMatPvtData;
struct rxNodePS2AllMatPvtData
{
    /* Callbacks */
    RxPipelineNodePS2AllMatIm3DPreMeshCallBack im3DPreMeshCB;  /**< Internal Use */
    RxPipelineNodePS2AllMatMeshInstanceTestCallBack meshInstanceTestCB;  /**< Internal Use */
    RxPipelineNodePS2AllMatResEntryAllocCallBack resEntryAllocCB;  /**< Internal Use */
    RxPipelineNodePS2AllMatInstanceCallBack instanceCB;  /**< Internal Use */
    RxPipelineNodePS2AllMatBridgeCallBack bridgeCB;     /**< Internal Use */
    RxPipelineNodePS2AllMatIm3DPostMeshCallBack im3DPostMeshCB;  /**< Internal Use */
    RxPipelineNodePS2AllMatIm3DMeshSplitCallBack im3DMeshSplitCB;  /**< Internal Use */
    RxPipelineNodePS2AllMatPostMeshCallBack postMeshCB;  /**< Internal Use */

    /* MatBridge sub-section [first for memory coherence,
     * instance stuff is not fast-path] */
    int      vifOffset;                                 /**< Internal Use */
    void   **vu1CodeArray;                              /**< Internal Use */
    RwUInt32 codeArrayLength;                           /**< Internal Use */

    /* MatInstance sub-section
     * [Arrays are indexed by CL_xxx defines in PS2ClusterAttribs.h] */

    rwPS2AllClusterInstanceInfo clinfo[CL_MAXCL + FMADD];  /**< Internal Use */
    RwUInt32 cliIndex[CL_MAXCL + FMADD];                /**< Internal Use */

    RpMeshHeaderFlags pipeType;                         /**< Internal Use */

    RwInt32 vu1MaxTSInputSize;                          /**< Internal Use */
    RwInt32 vu1MaxTLInputSize;                          /**< Internal Use */
    RwInt32 vu1MaxPLInputSize;                          /**< Internal Use */

    RwUInt8 totallyOpaque;                              /**< Internal Use */
    RwUInt8 numStripes;                                 /**< Internal Use */
    RwUInt8 sizeOnVU;                                   /**< Internal Use */
    RwUInt8 pad0;                                       /**< Internal Use */

    rwPS2AllResEntryFormat triStrip;                    /**< Internal Use */
    rwPS2AllResEntryFormat triList;                     /**< Internal Use */

    RwUInt32 magicValue;                                /**< Internal Use */

};

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

extern RxNodeDefinition *RxNodeDefinitionGetPS2AllMat(void);


/* Pre-unlock API functions (set up permanent properties
 * of the pipeline at construction time) */


extern RxPipelineNode *
RxPipelineNodePS2AllMatGenerateCluster(RxPipelineNode      *self,
                                       RxClusterDefinition *cluster2generate,
                                       RwUInt32             type);
extern RxPipelineNode *
RxPipelineNodePS2AllMatSetVUBufferSizes(RxPipelineNode *self,
                                        RwInt32 strideOfInputVertex,
                                        RwInt32 vuTSVertexMaxCount,
                                        RwInt32 vuTLTriMaxCount);
extern RxPipelineNode *
RxPipelineNodePS2AllMatSetPointListVUBufferSize(RxPipelineNode *self,
                                                RwInt32 strideOfInputVertex,
                                                RwInt32 vuPLVertexMaxCount);


/* Post-unlock API functions (these may be called more than
 * once, to change pipe behaviour between pipe executions) */

/* Find out the batch size that's actually used (not what you asked for) */
extern RwInt32
RxPipelineNodePS2AllMatGetVUBatchSize( RxPipelineNode *self,
                                       RpMeshHeaderFlags flags);
extern RxPipelineNode *
RxPipelineNodePS2AllMatSetVIFOffset(   RxPipelineNode *self,
                                       int vifOffset);
extern RxPipelineNode *
RxPipelineNodePS2AllMatSetVU1CodeArray(RxPipelineNode *self,
                                       void **vu1CodeArray,
                                       RwUInt32 length);
extern const void **
RxPipelineNodePS2AllMatGetVU1CodeArray(RxPipelineNode * self,
                                       RwUInt32 *length);
extern RxPipelineNode *
RxPipelineNodePS2AllMatSetCallBack(    RxPipelineNode *self,
                                       RxPipelineNodePS2AllMatCallBackType type,
                                       void *func);

#ifdef    __cplusplus
}
#endif /* __cplusplus */



/*--- Automatically derived from: pipe/p2/sky2/nodeps2all.h ---*/

#define REDEBUGx
#define DMAALIGN
#define VUCONTINUEx
#define FASTMORPH
#define OVERRIDELIGHTx
#define SUBSISTLIGHTx

#if (!defined(FASTMORPH))
#define FMADD (0)
#else /* (!defined(FASTMORPH)) */
#define FMADD (2)
#endif /* (!defined(FASTMORPH)) */


/* For getting the ps2AllResHeader from a RwResEntry */
#define RWPS2ALLRESENTRYHEADERFROMRESENTRY(_resEntry) \
    ((rwPS2AllResEntryHeader *)(_resEntry + 1))

/* For getting the Object Identifier from a ps2AllResHeader */
#define RWPS2ALLRESENTRYHEADERGETOBJIDENTIFIER(_ps2AllResEntry) \
    ((_ps2AllResEntry)->objIdentifier)

/* For getting the Mesh Identifier from a ps2AllResHeader */
#define RWPS2ALLRESENTRYHEADERGETMESHIDENTIFIER(_ps2AllResEntry) \
    ((_ps2AllResEntry)->meshIdentifier)

/* We expand trifans and polylines during instancing into trilists and linelists
 * respectively and RPMESHPS2ALLCALCNUMVERTS calculates the 'numverts' in the
 * DMA chain and on VU1 (NOT counting tristrip vertex duplication). Note that
 * triFans will be instanced into triLists and polyLines into lineLists. */
#define RPMESHPS2ALLCALCNUMVERTS(_ps2AllPipeData, _numVerts)                \
MACRO_START                                                                 \
{                                                                           \
    RxPS2AllPipeData *_psald = (_ps2AllPipeData);                           \
    RwUInt32 *_nmvt = (_numVerts);                                          \
                                                                            \
   *_nmvt = _psald->mesh->numIndices;                                       \
    if (_psald->meshHeader->flags & rpMESHHEADERTRIFAN)                     \
    {                                                                       \
       *_nmvt = ((*_nmvt) - 2)*3;                                           \
    }                                                                       \
    else if (_psald->meshHeader->flags & rpMESHHEADERPOLYLINE)              \
    {                                                                       \
       *_nmvt = ((*_nmvt) - 1)*2;                                           \
    }                                                                       \
}                                                                           \
MACRO_STOP


/**
 * \ingroup rpworldp2sky2
 * \ref RxInstanceFlags
 * These flags control the decision of whether to re-instance meshes
 * during the execution of PS2All.csl and PS2AllMat.csl. See
 * \ref RxPipelineNodePS2AllSetCallBack for an overview of this process.
 */
enum RxInstanceFlags
{
    rxINSTANCENAINSTANCEFLAG    = 0x0000,
    rxINSTANCEDONTINSTANCE      = 0x0001, /**< Signifies that no per-mesh reinstancing or testing
                                           *   should occur */
    rxINSTANCEINPLACEINSTANCE   = 0x0002, /**< Some or all clusters (depending on cluster reinstance
                                           *   flags below) are to be re-instanced 'in-place', in the
                                           *   existing resEntry (see \ref RxPipelineNodePS2AllSetCallBack
                                           *   for details of the consequences) (overrides DONTINSTANCE) */
    rxINSTANCECONGRUENTINSTANCE   = 0x0004, /**< The resEntry is thrown away but its size/layout is
                                           *   cached and reused for the new ResEntry (overrides
                                           *   DONTINSTANCE and INPLACEINSTANCE) */
    rxINSTANCEFULLINSTANCE      = 0x0008, /**< Size/layout have changed, so we can't cache them
                                           *   (overrides DONTINSTANCE, INPLACEINSTANCE and
                                           *   CONGRUENTINSTANCE) */
    rxINSTANCETYPEMASK          = (rxINSTANCEINPLACEINSTANCE   |
                                   rxINSTANCECONGRUENTINSTANCE |
                                   rxINSTANCEFULLINSTANCE),

    rxINSTANCEXYZ               = 0x0010,/**< Vertex positions should be re-instanced in-place */
    rxINSTANCENORMAL            = 0x0020,/**< Vertex normals should be re-instanced in-place */
    rxINSTANCEUV                = 0x0040,/**< Vertex texture coordinates should be re-instanced in-place */
    rxINSTANCEUV2               = 0x0080,/**< Second vertex texture coordinates should be re-instanced in-place */
    rxINSTANCERGBA              = 0x0100,/**< Vertex (prelight) colors should be re-instanced in-place */
    rxINSTANCEUSER1             = 0x0200,/**< User cluster 1 should be re-instanced in-place */
    rxINSTANCEUSER2             = 0x0400,/**< User cluster 2 should be re-instanced in-place */
    rxINSTANCEUSER3             = 0x0800,/**< User cluster 3 should be re-instanced in-place */
    rxINSTANCEUSER4             = 0x1000,/**< User cluster 4 should be re-instanced in-place */
    rxINSTANCEALL               = (rxINSTANCEXYZ    |
                                   rxINSTANCENORMAL |
                                   rxINSTANCEUV     |
                                   rxINSTANCEUV2    |
                                   rxINSTANCERGBA   |
                                   rxINSTANCEUSER1  |
                                   rxINSTANCEUSER2  |
                                   rxINSTANCEUSER3  |
                                   rxINSTANCEUSER4),
    rxINSTANCEMASK              = (rxINSTANCEDONTINSTANCE |
                                   rxINSTANCETYPEMASK     |
                                   rxINSTANCEALL),

    rxINSTANCEFORCEENUMSIZEINT  = RWFORCEENUMSIZEINT
};
typedef enum RxInstanceFlags RxInstanceFlags;

/**
 * \ingroup rpworldp2sky2
 * \struct RxPS2AllPipeData
 * Describes information used within the RxPS2All.csl node
 * and passed to callbacks registered therewith.
 */
struct RxPS2AllPipeData
{
    /* Per-object stuff */
    struct rxNodePS2AllPvtData
        *objPvtData;                /**< A pointer to the private data of the currently
                                     *   executing PS2All (object-pipeline) node */
    struct rxNodePS2AllMatPvtData
        *matPvtData;                /**< A pointer to the private data of the current
                                     *   material pipeline's PS2AllMat node */
    void *sourceObject;             /**< A pointer to the source object */
    RpMeshHeader *meshHeader;       /**< A pointer to the source object's \ref RpMeshHeader */
    RwMeshCache *meshCache;         /**< A pointer to the \ref RwMeshCache associated
                                     *   with meshHeader */
    RxInstanceFlags objInstance;    /**< Set by the ObjectSetup CB, says whether to instance
                                     *   the object and if so whether to do in-place, congruent
                                     *   or full reinstancing (and if in-place which clusters
                                     *   to reinstance) */
    RwUInt32 objIdentifier;         /**< Per-object, object-type-specific data that gets
                                     *   written into the PS2ResHeader such that state changes
                                     *   since creation of the instance data can be detected by
                                     *   object-specific code */
    RwReal spExtra;                 /**< An extra RwReal that can be uploaded in the same
                                     *   quadword as the surface properties. It is initialized
                                     *   by default to zero persists between meshes. */
#if (defined(FASTMORPH))
    RwInt32 numMorphTargets;        /**< Internal Use */
    RwUInt32 fastMorphing;          /**< Internal Use */
#endif /* (defined(FASTMORPH)) */
    RwUInt8 transType;              /**< RwUInt8 flags, specifying the type of transform to use
                                     *   (ortho/persp, fog/not, etc - see \ref RxSkyTransTypeFlags) */
    RwUInt8 primType;               /**< RwUInt8 code for the primitive type that will
                                     *   be submitted by VU1 to the GS (see GS manual ~p113) */
    RwUInt8 matModulate;            /**< RwUInt8 specifying whether or not to modulate
                                     *   the object material colours (0 means FALSE) */

    /* Following change per mesh */
    RwUInt8 vu1CodeIndex;           /**< RwUInt8 index into VU code array, */
                                    /*   specifying the transform to use */
    const RpMesh *mesh;             /**< A pointer to the source \ref RpMesh */
    RwResEntry **cacheEntryRef;     /**< A pointer to a pointer to a \ref RwResEntry
                                     *   holding the instance data for the mesh */
    RxInstanceFlags meshInstance;   /**< Optionally set by the MeshReInstanceTest CB, overrides
                                     *   objInstance in saying whether to instance the mesh and if
                                     *   so whether to do in-place, congruent or full reinstancing
                                     *   (and if in-place which clusters to reinstance) */
    RwUInt32 meshIdentifier;        /**< Per-mesh data that gets
                                     *   written into the PS2ResHeader such that state changes
                                     *   since creation of the instance data can be detected by
                                     *   object-specific code. */ 
    RwSurfaceProperties *surfProps; /**< A pointer to the current material surface properties. If
                                     *   left NULL, default {1, 1, 1} surface properties will be used. */
    RwTexture *texture;             /**< A pointer to a RwTexture for the current mesh */
    RwRGBA matCol;                  /**< RwRGBA material color value. Initialised by default to
                                     *   {255, 255, 255, 255} */
};

typedef struct rwPS2AllPrimTypeLUT rwPS2AllPrimTypeLUT;
struct rwPS2AllPrimTypeLUT
{
    RwUInt8 vertToIndRatio[rwPRIMTYPEOR];               /**< Internal Use */
    RwUInt8 vertToIndOffset[rwPRIMTYPEOR];              /**< Internal Use */
};


typedef struct rwPS2AllClusterQuickInfo rwPS2AllClusterQuickInfo;
struct rwPS2AllClusterQuickInfo
{
    u_long128           *data;                          /**< Internal Use */
    RwUInt32             stride;                        /**< Internal Use */
};


/**
 * \ingroup rpworldp2sky2
 * \ref RxPipelineNodePS2AllCallBackType
 * PS2All.csl callback types (see \ref RxPipelineNodePS2AllSetCallBack
 * and \ref RxPipelineNodePS2AllMatSetCallBack), in order of execution within
 * the node.
 */
enum RxPipelineNodePS2AllCallBackType
{
    rxPS2ALLCALLBACKNACALLBACK          = 0,
    rxPS2ALLCALLBACKOBJECTSETUP         = 1, /**< Performs per-object setup
                                              *   (see \ref RxPipelineNodePS2AllObjectSetupCallBack) */
    rxPS2ALLCALLBACKOBJECTFINALIZE      = 2, /**< Performs per-object post-render tasks
                                              *   (see \ref RxPipelineNodePS2AllObjectFinalizeCallBack) */

    rxPS2ALLCALLBACKFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum RxPipelineNodePS2AllCallBackType RxPipelineNodePS2AllCallBackType;

typedef RwBool (*RxPipelineNodePS2AllObjectSetupCallBack)
    (RxPS2AllPipeData *ps2AllPipeData,
     RwMatrix **transform,
     RxWorldApplyLightFunc lightingFunc);

typedef RwBool (*RxPipelineNodePS2AllObjectFinalizeCallBack)
    (RxPS2AllPipeData *ps2AllPipeData);

typedef struct rxNodePS2AllPvtData rxNodePS2AllPvtData;
struct rxNodePS2AllPvtData
{
    rwPS2AllPrimTypeLUT              primLUT;           /**< Internal Use */

    /* Callbacks */
    RxPipelineNodePS2AllObjectSetupCallBack objectSetupCB; /**< Internal Use */
    RxPipelineNodePS2AllObjectFinalizeCallBack objectFinalizeCB; /**< Internal Use */

    /* ObjAllInOne sub-section */
    RxPipeline *groupPipe;                              /**< Internal Use */
    
};

typedef struct rwPS2AllResEntryHeader rwPS2AllResEntryHeader;
struct rwPS2AllResEntryHeader
{
    RwInt32 refCnt;                                     /**< Internal Use */
    RwInt32 clrCnt;                                     /**< Internal Use */

    u_long128 *data;                                    /**< Internal Use */

    RwUInt32 numVerts;                                  /**< Internal Use */

    RwUInt32 objIdentifier;                             /**< Internal Use */
    RwUInt32 meshIdentifier;                            /**< Internal Use */

    int batchSize;                                      /**< Internal Use */
    int numBatches;                                     /**< Internal Use */
    int batchesPerTag;                                  /**< Internal Use */

#if (defined(FASTMORPH))
    int morphStart;                                     /**< Internal Use */
    int morphFinish;                                    /**< Internal Use */
    int morphNum;                                       /**< Internal Use */
#endif /* (defined(FASTMORPH)) */

    rwPS2AllClusterQuickInfo clquickinfo[CL_MAXCL + FMADD]; /**< Internal Use */
    rwPS2AllFieldRec fieldRec[CL_MAXCL + FMADD];        /**< Internal Use */


};

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

extern RxNodeDefinition *RxNodeDefinitionGetPS2All(void);


/* Post-unlock API functions (these may be called more than
 * once, to change pipe behaviour between pipe executions) */

extern RxPipelineNode *
RxPipelineNodePS2AllSetCallBack(RxPipelineNode *self,
                                RxPipelineNodePS2AllCallBackType type,
                                void *func);
extern RxPipelineNode *
RxPipelineNodePS2AllGroupMeshes(RxPipelineNode *node, RxPipeline *pipe);


#ifdef    __cplusplus
}
#endif /* __cplusplus */



/*--- Automatically derived from: pipe/p2/sky2/ps2allsector.h ---*/

typedef struct rpWorldSectorPS2AllLightData rpWorldSectorPS2AllLightData;
struct rpWorldSectorPS2AllLightData
{
    RwSurfaceProperties  *surface;                      /**< Internal Use */
    RxWorldApplyLightFunc lightFunc;                    /**< Internal Use */
};

#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)) */
#define RPWORLDSECTORMAKEOBJID(meshHeader)           \
    (((RwUInt16)((meshHeader)->serialNum)) |    \
     (((RwUInt8)(rwObjectGetFlags((RpWorld *)RWSRCGLOBAL(curWorld)) & WORLDRENDERTYPEMASK)) << 16))

#define RPWORLDSECTOROBJIDGETSERIALNUM(objID) ((RwUInt16)(objID))
#define RPWORLDSECTOROBJIDGETFLAGS(objID)     ((RwUInt8)((objID) >> 16))

/* TRUE if the pointer points to an RpWorldSector, FALSE if an RpAtomic */
#define RPWORLDSECTORVERIFY(_object) (*(RwUInt8 *)(_object) == (RwUInt8)-1)


/* Used as RpWorldSectorPS2AllGetMeshHeaderMeshCache (function in debug) */
#define RpWorldSectorPS2AllGetMeshHeaderMeshCacheMacro(_sector, _ps2AllPipeData)                        \
MACRO_START                                                                                             \
{                                                                                                       \
    RxPS2AllPipeData *_p2apd = (_ps2AllPipeData);                                                       \
    RpWorldSector *_sctr = (_sector);                                                                   \
                                                                                                        \
    PS2ALLMACROASSERT(NULL != _p2apd);                                                                  \
    PS2ALLMACROASSERT(NULL != _sctr);                                                                   \
                                                                                                        \
    _p2apd->meshHeader = _sctr->mesh;                                                                   \
    PS2ALLMACROASSERT(NULL != _p2apd->meshHeader);                                                      \
                                                                                                        \
    /* Get the RwMeshCache from the sector */                                                           \
    _p2apd->meshCache = rpWorldSectorGetMeshCache(_sctr, _p2apd->meshHeader->numMeshes);                \
    PS2ALLMACROASSERT(NULL != _p2apd->meshCache);                                                       \
}                                                                                                       \
MACRO_STOP

/* Used as RpPS2AllWorldSectorGatherObjMetrics (function in debug) */
#if (defined(RWMETRICS))
#define RpWorldSectorPS2AllGatherObjMetricsMacro(_sector)                                               \
MACRO_START                                                                                             \
{                                                                                                       \
    RpWorldSector *_sctr = (_sector);                                                                   \
                                                                                                        \
    /* Update our metrics statistics */                                                                 \
    RWSRCGLOBAL(metrics)->numVertices  += RpWorldSectorGetNumVertices(_sctr);                           \
    RWSRCGLOBAL(metrics)->numTriangles += RpWorldSectorGetNumPolygons(_sctr);                           \
}                                                                                                       \
MACRO_STOP
#else /* (defined(RWMETRICS)) */
#define RpWorldSectorPS2AllGatherObjMetricsMacro(_sector) /* No op */
#endif /* (defined(RWMETRICS)) */

/* Used as RpWorldSectorPS2AllObjInstanceTest (function in debug) */
#define RpWorldSectorPS2AllObjInstanceTestMacro(_ps2AllPipeData)                                        \
MACRO_START                                                                                             \
{                                                                                                       \
    RxPS2AllPipeData *_p2apd = (_ps2AllPipeData);                                                       \
    RwResEntry *_rsnt;                                                                                  \
                                                                                                        \
    /* The per-mesh identifier will be identical for all meshes in an object. Regardless, we    */      \
    /* allow per-material reinstance tests to override/replace the per-object ones done here    */      \
                                                                                                        \
    /* Make a new object identifier */                                                                  \
    _p2apd->objIdentifier = RPWORLDSECTORMAKEOBJID(_p2apd->meshHeader);                                 \
                                                                                                        \
    /* Remove DONTINSTANCE so meshes are free to do their tests */                                      \
    /* (and we don't skip instancing if (resEntry == NULL)) */                                          \
    _p2apd->objInstance = (RxInstanceFlags)                                                             \
        (_p2apd->objInstance & ~rxINSTANCEDONTINSTANCE);                                                \
                                                                                                        \
    /* The same object identifier goes into every mesh's resEntry, so just grab the first one */        \
    _rsnt = *rwMeshCacheGetEntryRef(_p2apd->meshCache, 0);                                              \
    if (NULL != _rsnt)                                                                                  \
    {                                                                                                   \
        /* Test our new identifier against the old one to see how much reinstancing needs doing */      \
        rwPS2AllResEntryHeader *ps2AllResHeader =                                                       \
            RWPS2ALLRESENTRYHEADERFROMRESENTRY(_rsnt);                                                  \
                                                                                                        \
        if (_p2apd->objIdentifier != ps2AllResHeader->objIdentifier)                                    \
        {                                                                                               \
            if (RPWORLDSECTOROBJIDGETFLAGS(_p2apd->objIdentifier) !=                                    \
                RPWORLDSECTOROBJIDGETFLAGS(ps2AllResHeader->objIdentifier))                             \
            {                                                                                           \
                /* Changing object flags causes a full reinstance */                                    \
                _p2apd->objInstance = (RxInstanceFlags)                                                 \
                    (_p2apd->objInstance | rxINSTANCEFULLINSTANCE);                                     \
            }                                                                                           \
            else                                                                                        \
            {                                                                                           \
                /* Only a congruent reinstance for other changes (serialNum atm) */                     \
                _p2apd->objInstance = (RxInstanceFlags)                                                 \
                    (_p2apd->objInstance | rxINSTANCECONGRUENTINSTANCE);                                \
                REDEBUGPrintf(("objIdentifier change caused congruent reinstancing: (%x)\n",            \
                               _p2apd->objIdentifier));                                                 \
            }                                                                                           \
        }                                                                                               \
        /* Currently in-place instancing won't occur because we don't expect editing of sector data */  \
    }                                                                                                   \
    else                                                                                                \
    {                                                                                                   \
        /* Reinstancing will always occur if (resEntry == NULL) */                                      \
    }                                                                                                   \
}                                                                                                       \
MACRO_STOP

/* Used as RpWorldSectorPS2AllTransformSetup (function in debug) */
#define RpWorldSectorPS2AllTransformSetupMacro(_transform)                                              \
MACRO_START                                                                                             \
{                                                                                                       \
    RwMatrix **_tnfm = (_transform);                                                                    \
                                                                                                        \
    /* We just cache the camera matrix */                                                               \
   *_tnfm = &(((RwCamera *)RWSRCGLOBAL(curCamera))->viewMatrix);                                        \
    PS2ALLMACROASSERT(RWMATRIXALIGNMENT(*_tnfm));                                                       \
}                                                                                                       \
MACRO_STOP

/* Used as RpWorldSectorPS2AllFrustumTest (function in debug) */
#define RpWorldSectorPS2AllFrustumTestMacro(_sector, _inFrustum)                                        \
MACRO_START                                                                                             \
{                                                                                                       \
    RpWorldSector       *_sctr = (_sector);                                                             \
    RwFrustumTestResult *_infm = (_inFrustum);                                                          \
                                                                                                        \
    RwFrustumPlane      *_frustPlane;                                                                   \
    RwUInt32             _numPlanes;                                                                    \
                                                                                                        \
    /* Assume innocent until proven guilty */                                                           \
   *_infm = rwSPHEREINSIDE;                                                                             \
                                                                                                        \
    _frustPlane = CAMERAEXTFROMCAMERA(RWSRCGLOBAL(curCamera))->largeFrustumPlanes;                      \
                                                                                                        \
    _numPlanes = 6;                                                                                     \
    while (_numPlanes--)                                                                                \
    {                                                                                                   \
        RwV3d  vCorner;                                                                                 \
        RwReal dot;                                                                                     \
                                                                                                        \
        /* Check against plane */                                                                       \
        vCorner.x = ((RwV3d *)&_sctr->boundingBox)[1 - _frustPlane->closestX].x;                        \
        vCorner.y = ((RwV3d *)&_sctr->boundingBox)[1 - _frustPlane->closestY].y;                        \
        vCorner.z = ((RwV3d *)&_sctr->boundingBox)[1 - _frustPlane->closestZ].z;                        \
        dot = RwV3dDotProduct(&vCorner, &_frustPlane->plane.normal);                                    \
        dot -= _frustPlane->plane.distance;                                                             \
                                                                                                        \
        /* We only need to detect a boundary case, we should never be wholly outside here. */           \
        if (dot > 0)                                                                                    \
        {                                                                                               \
            /* Its outside the plane */                                                                 \
           *_infm = rwSPHEREBOUNDARY;                                                                   \
            break;                                                                                      \
        }                                                                                               \
        _frustPlane++;                                                                                  \
    }                                                                                                   \
}                                                                                                       \
MACRO_STOP

/* Used as RpWorldSectorPS2AllMatModulateSetup (function in debug) */
#define RpWorldSectorPS2AllMatModulateSetupMacro(_ps2AllPipeData)                                       \
MACRO_START                                                                                             \
{                                                                                                       \
    PS2ALLMACROASSERT(NULL != RWSRCGLOBAL(curWorld));                                                   \
    (_ps2AllPipeData)->matModulate =                                                                    \
        (RpWorldGetFlags((RpWorld *) RWSRCGLOBAL(curWorld)) &                                           \
         rpWORLDMODULATEMATERIALCOLOR) ? TRUE : FALSE;                                                  \
}                                                                                                       \
MACRO_STOP

/* Used as RpWorldSectorPS2AllLightingSetup (function in debug) */
#define RpWorldSectorPS2AllLightingSetupMacro(_ps2AllPipeData, _lightingFunc)                           \
MACRO_START                                                                                             \
{                                                                                                       \
    RxPS2AllPipeData *_p2apd = (_ps2AllPipeData);                                                       \
    RxWorldApplyLightFunc _ltfn = (_lightingFunc);                                                      \
    RpWorldSector *_sctr = (RpWorldSector *)_p2apd->sourceObject;                                       \
    RpWorld *_wrld = (RpWorld *)RWSRCGLOBAL(curWorld);                                                  \
                                                                                                        \
    PS2ALLMACROASSERT(NULL != _ltfn);                                                                   \
    PS2ALLMACROASSERT(NULL != _sctr);                                                                   \
    /* If we are rendering atomic sectors we must have a world! */                                      \
    PS2ALLMACROASSERT(NULL != _wrld);                                                                   \
                                                                                                        \
    if(rwObjectTestFlags(_wrld, rpWORLDLIGHT))                                                          \
    {                                                                                                   \
        rpWorldSectorPS2AllLightData lightingData;                                                      \
                                                                                                        \
        /* Ideally I'd like to use the code in baworld.c but */                                         \
        /* the function _rpWorldSectorLight isn't exposed */                                            \
        lightingData.surface = &(_wrld->surfaceProps);                                                  \
        lightingData.lightFunc = _ltfn;                                                                 \
                                                                                                        \
        rpWorldForAllGlobalLights(RpWorldSectorPS2AllDoApplyLight, &lightingData);                      \
        rpWorldSectorForAllLocalLights(_sctr, RpWorldSectorPS2AllDoApplyLight, &lightingData);          \
    }                                                                                                   \
}                                                                                                       \
MACRO_STOP

/* Used as RpWorldSectorPS2AllResEntryAlloc (function in debug) */
#define RpWorldSectorPS2AllResEntryAllocMacro(_ps2AllPipeData, _repEntry, _size, _destroyCallBack)      \
MACRO_START                                                                                             \
{                                                                                                       \
    RwResEntry **_rsny = (_repEntry);                                                                   \
   *_rsny = RwResourcesAllocateResEntry(                                                                \
        (_ps2AllPipeData)->sourceObject, _rsny, _size, _destroyCallBack);                               \
}                                                                                                       \
MACRO_STOP



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

/* Default RW callbacks */
extern RwBool RpWorldSectorPS2AllObjectSetupCallBack(
    RxPS2AllPipeData *ps2AllPipeData,
    RwMatrix **transform,
    RxWorldApplyLightFunc lightingFunc);

/* Standard instance func for sectors */
extern RwBool RpWorldSectorPS2AllInstance(RxPS2AllPipeData *ps2AllPipeData);

/* Callbacks used by the standard lighting func */
extern RpLight *RpWorldSectorPS2AllDoApplyLight(RpLight *light, void *pData);

/* Callback components, for use in user callbacks */
/* ObjectSetupCB */
extern void RpWorldSectorPS2AllGetMeshHeaderMeshCacheFunc(
    RpWorldSector *sector,
    RxPS2AllPipeData *ps2AllPipeData);
extern void RpWorldSectorPS2AllGatherObjMetricsFunc(
    RpWorldSector *sector);
extern void RpWorldSectorPS2AllObjInstanceTestFunc(
    RxPS2AllPipeData *ps2AllPipeData);
extern void RpWorldSectorPS2AllTransformSetupFunc(
    RwMatrix **transform);
extern void RpWorldSectorPS2AllFrustumTestFunc(
    RpWorldSector *sector,
    RwFrustumTestResult *inFrustum);
extern void RpWorldSectorPS2AllMatModulateSetupFunc(
    RxPS2AllPipeData *ps2AllPipeData);
extern void RpWorldSectorPS2AllLightingSetupFunc(
    RxPS2AllPipeData *ps2AllPipeData,
    RxWorldApplyLightFunc lightingFunc);
extern void RpWorldSectorPS2AllResEntryAllocFunc(
    RxPS2AllPipeData *ps2AllPipeData,
    RwResEntry **repEntry,
    RwUInt32 size,
    RwResEntryDestroyNotify destroyCallBack);

#if (defined(RWDEBUG))
#define RpWorldSectorPS2AllGetMeshHeaderMeshCache   RpWorldSectorPS2AllGetMeshHeaderMeshCacheFunc
#define RpWorldSectorPS2AllGatherObjMetrics         RpWorldSectorPS2AllGatherObjMetricsFunc
#define RpWorldSectorPS2AllObjInstanceTest          RpWorldSectorPS2AllObjInstanceTestFunc
#define RpWorldSectorPS2AllTransformSetup           RpWorldSectorPS2AllTransformSetupFunc
#define RpWorldSectorPS2AllFrustumTest              RpWorldSectorPS2AllFrustumTestFunc
#define RpWorldSectorPS2AllMatModulateSetup         RpWorldSectorPS2AllMatModulateSetupFunc
#define RpWorldSectorPS2AllLightingSetup            RpWorldSectorPS2AllLightingSetupFunc
#define RpWorldSectorPS2AllResEntryAlloc            RpWorldSectorPS2AllResEntryAllocFunc
#else /* (defined(RWDEBUG)) */
#define RpWorldSectorPS2AllGetMeshHeaderMeshCache   RpWorldSectorPS2AllGetMeshHeaderMeshCacheMacro
#define RpWorldSectorPS2AllGatherObjMetrics         RpWorldSectorPS2AllGatherObjMetricsMacro
#define RpWorldSectorPS2AllObjInstanceTest          RpWorldSectorPS2AllObjInstanceTestMacro
#define RpWorldSectorPS2AllTransformSetup           RpWorldSectorPS2AllTransformSetupMacro
#define RpWorldSectorPS2AllFrustumTest              RpWorldSectorPS2AllFrustumTestMacro
#define RpWorldSectorPS2AllMatModulateSetup         RpWorldSectorPS2AllMatModulateSetupMacro
#define RpWorldSectorPS2AllLightingSetup            RpWorldSectorPS2AllLightingSetupMacro
#define RpWorldSectorPS2AllResEntryAlloc            RpWorldSectorPS2AllResEntryAllocMacro
#endif /* (defined(RWDEBUG)) */

#ifdef    __cplusplus
}
#endif /* __cplusplus */


/*--- Automatically derived from: pipe/p2/sky2/ps2allatomic.h ---*/

typedef struct rpAtomicPS2AllLightData rpAtomicPS2AllLightData;
struct rpAtomicPS2AllLightData
{
    RwSurfaceProperties  *surface;                      /**< Internal Use */
    RwMatrix              invMat;                       /**< Internal Use */
    RwReal                invScale;                     /**< Internal Use */
    RxWorldApplyLightFunc lightFunc;                    /**< Internal Use */
};

#define RPATOMICPS2ALLMAKEOBJID(meshHeader, geom)                           \
    (((RwUInt16)((meshHeader)->serialNum)) |                                \
     (((RwUInt8)(rwObjectGetFlags(geom) & ATOMICRENDERTYPEMASK)) << 16) |   \
     (((RwUInt8)((geom)->numMorphTargets)) << 24))
#define RPATOMICPS2ALLOBJIDGETSERIALNUM(_objID)         ((RwUInt16)(_objID))
#define RPATOMICPS2ALLOBJIDGETFLAGS(_objID)             ((RwUInt8)((_objID) >> 16))
#define RPATOMICPS2ALLOBJIDGETNUMMORPHTARGETS(_objID)   ((RwUInt8)((_objID) >> 24))

#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 RpAtomicGetMeshHeaderMeshCache (function in debug) */
#define RpAtomicPS2AllGetMeshHeaderMeshCacheMacro(_atomic, _ps2AllPipeData)                             \
MACRO_START                                                                                             \
{                                                                                                       \
    RxPS2AllPipeData *_p2apd = (_ps2AllPipeData);                                                       \
    RpAtomic   *_atmc = (_atomic);                                                                      \
    RpGeometry *_gmty = RpAtomicGetGeometry(_atmc);                                                     \
                                                                                                        \
    _p2apd->meshHeader = _gmty->mesh;                                                                   \
    PS2ALLMACROASSERT(NULL != _p2apd->meshHeader);                                                      \
                                                                                                        \
    if (RpGeometryGetNumMorphTargets(_gmty) != 1)                                                       \
    {                                                                                                   \
        _p2apd->meshCache =                                                                             \
            rpAtomicGetMeshCache(_atmc, _gmty->mesh->numMeshes);                                        \
    }                                                                                                   \
    else                                                                                                \
    {                                                                                                   \
        _p2apd->meshCache =                                                                             \
            rpGeometryGetMeshCache(_gmty, _gmty->mesh->numMeshes);                                      \
    }                                                                                                   \
    PS2ALLMACROASSERT(NULL != _p2apd->meshCache);                                                       \
}                                                                                                       \
MACRO_STOP

/* Used as RpPS2AllAtomicGatherObjMetrics (function in debug) */
#if (defined(RWMETRICS))
#define RpAtomicPS2AllGatherObjMetricsMacro(_atomic)                                                    \
MACRO_START                                                                                             \
{                                                                                                       \
    RpGeometry *_gmty = RpAtomicGetGeometry(_atomic);                                                   \
                                                                                                        \
    /* Update our metrics statistics */                                                                 \
    RWSRCGLOBAL(metrics)->numVertices  += RpGeometryGetNumVertices(_gmty);                              \
    RWSRCGLOBAL(metrics)->numTriangles += RpGeometryGetNumTriangles(_gmty);                             \
}                                                                                                       \
MACRO_STOP
#else  /* (defined(RWMETRICS)) */
#define RpAtomicPS2AllGatherObjMetricsMacro(_atomic) /* No op */
#endif /* (defined(RWMETRICS)) */

/* Used as RpAtomicPS2AllMorphSetup (function in debug) */
#if (defined(FASTMORPH))
#define RpAtomicPS2AllMorphSetupMacro(_atomic, _ps2AllPipeData)                                         \
MACRO_START                                                                                             \
{                                                                                                       \
    RxPS2AllPipeData *_p2apd = (_ps2AllPipeData);                                                       \
    RpAtomic   *_atmc = (_atomic);                                                                      \
    RpGeometry *_gmty = RpAtomicGetGeometry(_atmc);                                                     \
                                                                                                        \
    _p2apd->numMorphTargets = _gmty->numMorphTargets;                                                   \
    /* Set up morph scale where appropriate */                                                          \
    if (_p2apd->numMorphTargets > 1)                                                                    \
    {                                                                                                   \
        RpInterpolator *_itpltr;                                                                        \
                                                                                                        \
        _itpltr = &(_atmc->interpolator);                                                               \
        PS2ALLMACROASSERT(NULL != _itpltr);                                                             \
                                                                                                        \
        /* Upload morph 'scale' value in the extra float */                                             \
        _p2apd->spExtra = _itpltr->recipTime*                                                           \
                          _itpltr->position;                                                            \
    }                                                                                                   \
}                                                                                                       \
MACRO_STOP
#else  /* (defined(FASTMORPH)) */
#define RpAtomicPS2AllMorphSetupMacro(_atomic, _ps2AllPipeData) /* No op */
#endif /* (defined(FASTMORPH)) */

/* Used as RpAtomicObjInstanceTest (function in debug) */

/* Can't nest # directives in macros, so have to have predicate some
 * separated sub-sections for RpAtomicPS2AllObjInstanceTestMacro */
#if (defined(FASTMORPH))
#define _AtomicObjInstTestMorph()                                                                       \
     ||                                                                                                 \
     (RPATOMICPS2ALLOBJIDGETNUMMORPHTARGETS(_p2apd->objIdentifier) !=                                   \
      RPATOMICPS2ALLOBJIDGETNUMMORPHTARGETS(ps2AllResHeader->objIdentifier))
#define _AtomicObjInstTestInterp()                                                                      \
MACRO_START                                                                                             \
{                                                                                                       \
     /* Rules are a bit different here. We check to see if the morph */                                 \
     /* start/end have changed, and only then reinstance */                                             \
     if ((ps2AllResHeader->morphFinish != interpolator->endMorphTarget) ||                              \
         (ps2AllResHeader->morphStart  != interpolator->startMorphTarget) )                             \
     {                                                                                                  \
         _p2apd->objInstance = (RxInstanceFlags)                                                        \
             (_p2apd->objInstance | rxINSTANCECONGRUENTINSTANCE);                                       \
         REDEBUGPrintf(("interpolator forced disconnect of resEntry\n"));                               \
         REDEBUGPrintf(("start: %d, end: %d\n",                                                         \
                       interpolator->startMorphTarget,                                                  \
                       interpolator->endMorphTarget));                                                  \
     }                                                                                                  \
}                                                                                                       \
MACRO_STOP
#else /* (defined(FASTMORPH)) */
#define _AtomicObjInstTestMorph() /* No op */
#define _AtomicObjInstTestInterp()                                                                      \
MACRO_START                                                                                             \
{                                                                                                       \
    /* NB: we only OR the value here so if polygons changed */                                          \
    /* above the FULL reinstance isn't cancelled! */                                                    \
    _p2apd->objInstance = (RxInstanceFlags)                                                             \
        ( _p2apd->objInstance | rxINSTANCECONGRUENTINSTANCE);                                           \
    /* Flag reset once per atomic, not per mesh. */                                                     \
    /* (otherwise only the first mesh is animated!) */                                                  \
    REDEBUGPrintf(("interpolator forced rebuild\n"));                                                   \
}                                                                                                       \
MACRO_STOP
#endif /* (defined(FASTMORPH)) */

#define RpAtomicPS2AllObjInstanceTestMacro(_atomic, _ps2AllPipeData)                                    \
MACRO_START                                                                                             \
{                                                                                                       \
    RxPS2AllPipeData *_p2apd = (_ps2AllPipeData);                                                       \
    RpAtomic   *_atmc = (_atomic);                                                                      \
    RpGeometry *_gmty = RpAtomicGetGeometry(_atmc);                                                     \
                                                                                                        \
    if ( !(_gmty->instanceFlags & rpGEOMETRYPERSISTENT) )                                               \
    {                                                                                                   \
        RwResEntry *resEntry;                                                                           \
                                                                                                        \
        /* The per-mesh identifier will be identical for all meshes in an object. Regardless, we    */  \
        /* allow per-material reinstance tests to override/replace the per-object ones done here    */  \
                                                                                                        \
        /* Make a new object identifier */                                                              \
        _p2apd->objIdentifier = RPATOMICPS2ALLMAKEOBJID(_p2apd->meshHeader, _gmty);                     \
                                                                                                        \
        /* Remove DONTINSTANCE so (given we're not using persistent */                                  \
        /* instance data) meshes are free to do their tests */                                          \
        /* (and we don't skip instancing if (resEntry == NULL)) */                                      \
        _p2apd->objInstance = (RxInstanceFlags)                                                         \
             (_p2apd->objInstance & ~rxINSTANCEDONTINSTANCE);                                           \
                                                                                                        \
        /* The same object identifier goes into every */                                                \
        /* mesh's resEntry, so just grab the first one */                                               \
        resEntry = *rwMeshCacheGetEntryRef(_p2apd->meshCache, 0);                                       \
        if (NULL != resEntry)                                                                           \
        {                                                                                               \
            /* Test our new identifier against the old one */                                           \
            /* to see how much reinstancing needs doing. */                                             \
            rwPS2AllResEntryHeader *ps2AllResHeader =                                                   \
                RWPS2ALLRESENTRYHEADERFROMRESENTRY(resEntry);                                           \
            RpInterpolator *interpolator = &(_atmc->interpolator);                                      \
                                                                                                        \
            /* This is important, else the instance CB can't tell atomics from sectors */               \
            PS2ALLMACROASSERT(0 != RPATOMICPS2ALLOBJIDGETNUMMORPHTARGETS(_p2apd->objIdentifier));       \
            if (_p2apd->objIdentifier != ps2AllResHeader->objIdentifier)                                \
            {                                                                                           \
                if ( (RPATOMICPS2ALLOBJIDGETFLAGS(_p2apd->objIdentifier) !=                             \
                      RPATOMICPS2ALLOBJIDGETFLAGS(ps2AllResHeader->objIdentifier))                      \
                     /* This is FASTMORPH-predicated, see above */                                      \
                     _AtomicObjInstTestMorph() )                                                        \
                {                                                                                       \
                    /* Changing object flags or morphtarget number causes a full reinstance */          \
                    _p2apd->objInstance = (RxInstanceFlags)                                             \
                        (_p2apd->objInstance | rxINSTANCEFULLINSTANCE);                                 \
                }                                                                                       \
                else                                                                                    \
                {                                                                                       \
                    /* Only a congruent reinstance for other changes (serialNum atm) */                 \
                    _p2apd->objInstance = (RxInstanceFlags)                                             \
                        (_p2apd->objInstance | rxINSTANCECONGRUENTINSTANCE);                            \
                    REDEBUGPrintf(("objIdentifier change caused congruent reinstancing: (%x)\n",        \
                                   _p2apd->objIdentifier));                                             \
                }                                                                                       \
            }                                                                                           \
                                                                                                        \
            if (0 != _gmty->lockedSinceLastInst)                                                        \
            {                                                                                           \
                /* Something's changed.... what needs to be reinstanced? */                             \
                if (_gmty->lockedSinceLastInst & rpGEOMETRYLOCKPOLYGONS)                                \
                {                                                                                       \
                    /* Polygons changed... implies numverts changed */                                  \
                    _p2apd->objInstance = (RxInstanceFlags)                                             \
                        (_p2apd->objInstance | rxINSTANCEFULLINSTANCE);                                 \
                }                                                                                       \
                else                                                                                    \
                {                                                                                       \
                    /* We allow in-place instancing again. Quick conversion from */                     \
                    /* RpGeometryLockMode to RxInstanceFlags, with ASSERT safety-net */                 \
                    _p2apd->objInstance = (RxInstanceFlags)                                             \
                        (_p2apd->objInstance | rxINSTANCEINPLACEINSTANCE);                              \
                    _p2apd->objInstance = (RxInstanceFlags)                                             \
                        (_p2apd->objInstance | (_gmty->lockedSinceLastInst << 3));                      \
                    PS2ALLMACROASSERT((rpGEOMETRYLOCKVERTICES   << 3) == rxINSTANCEXYZ);                \
                    PS2ALLMACROASSERT((rpGEOMETRYLOCKNORMALS    << 3) == rxINSTANCENORMAL);             \
                    PS2ALLMACROASSERT((rpGEOMETRYLOCKTEXCOORDS  << 3) == rxINSTANCEUV);                 \
                    PS2ALLMACROASSERT((rpGEOMETRYLOCKTEXCOORDS2 << 3) == rxINSTANCEUV2);                \
                    PS2ALLMACROASSERT((rpGEOMETRYLOCKPRELIGHT   << 3) == rxINSTANCERGBA);               \
                }                                                                                       \
            }                                                                                           \
                                                                                                        \
            REDEBUGPrintf(("atomic _p2apd->objInstance %x\n", (RwUInt32)_p2apd->objInstance));          \
                                                                                                        \
            if (interpolator->flags & (RwInt32)rpINTERPOLATORDIRTYINSTANCE)                             \
            {                                                                                           \
                /* This is FASTMORPH-predicated, see above */                                           \
                _AtomicObjInstTestInterp();                                                             \
            }                                                                                           \
        }                                                                                               \
        else                                                                                            \
        {                                                                                               \
            /* Reinstancing will always occur if (resEntry == NULL) */                                  \
        }                                                                                               \
    }                                                                                                   \
    else                                                                                                \
    {                                                                                                   \
        /* Make sure this "persistent instance data" malarky's not just a bluff. */                     \
        PS2ALLMACROASSERT((RwResEntry *)NULL !=                                                         \
                          *rwMeshCacheGetEntryRef(_p2apd->meshCache, 0));                               \
    }                                                                                                   \
}                                                                                                       \
MACRO_STOP

/* Used as RpAtomicPS2AllTransformSetup (function in debug) */
#define RpAtomicPS2AllTransformSetupMacro(_atomic, _transform)                                          \
MACRO_START                                                                                             \
{                                                                                                       \
    RpAtomic  *_atmc = (_atomic);                                                                       \
    RwMatrix **_tnfm = (_transform);                                                                    \
                                                                                                        \
    RwMatrix * const _mpLocalToWorld =                                                                  \
        RwFrameGetLTM((RwFrame *)rwObjectGetParent(_atmc));                                             \
    RwMatrix * const _viewMatrix =                                                                      \
        &(((RwCamera *)RWSRCGLOBAL(curCamera))->viewMatrix);                                            \
                                                                                                        \
    PS2ALLMACROASSERT(RWMATRIXALIGNMENT(_mpLocalToWorld));                                              \
    PS2ALLMACROASSERT(RWMATRIXALIGNMENT(_viewMatrix));                                                  \
                                                                                                        \
    RwMatrixMultiply(*_tnfm, _mpLocalToWorld, _viewMatrix);                                             \
}                                                                                                       \
MACRO_STOP

/* Used as RpAtomicPS2AllFrustumTest (function in debug) */
#define RpAtomicPS2AllFrustumTestMacro(_atomic, _inFrustum)                                             \
MACRO_START                                                                                             \
{                                                                                                       \
    RpAtomic  *_atmc = (_atomic);                                                                       \
    RwFrustumTestResult *_infm = _inFrustum;                                                            \
                                                                                                        \
    RwFrustumPlane     *_frustPlane;                                                                    \
    const RwSphere     *_sphere;                                                                        \
    RwUInt32           _numPlanes;                                                                      \
                                                                                                        \
    /* Assume innocent until proven guilty */                                                           \
   *_infm = rwSPHEREINSIDE;                                                                             \
                                                                                                        \
    _sphere = RpAtomicGetWorldBoundingSphere(_atmc);                                                    \
    PS2ALLMACROASSERT(_sphere);                                                                         \
                                                                                                        \
    _frustPlane = CAMERAEXTFROMCAMERA(RWSRCGLOBAL(curCamera))                                           \
                      ->largeFrustumPlanes;                                                             \
    _numPlanes = 6;                                                                                     \
    while (_numPlanes--)                                                                                \
    {                                                                                                   \
        RwReal dot;                                                                                     \
        dot = RwV3dDotProduct(&_sphere->center,                                                         \
                              &_frustPlane->plane.normal);                                              \
        dot -= _frustPlane->plane.distance;                                                             \
                                                                                                        \
        /* We only need to detect boundary case, we */                                                  \
        /* should never get a totally outside. */                                                       \
        if (dot > -_sphere->radius)                                                                     \
        {                                                                                               \
           *_infm = rwSPHEREBOUNDARY;                                                                   \
            break;                                                                                      \
        }                                                                                               \
        _frustPlane++;                                                                                  \
    }                                                                                                   \
}                                                                                                       \
MACRO_STOP

/* Used as RpAtomicPS2AllPrimTypeTransTypeSetup (function in debug) */
#define RpAtomicPS2AllPrimTypeTransTypeSetupMacro(_ps2AllPipeData, _inFrustum)                          \
MACRO_START                                                                                             \
{                                                                                                       \
    RxPS2AllPipeData *_p2apd  = (_ps2AllPipeData);                                                      \
    RwFrustumTestResult _infm = (_inFrustum);                                                           \
                                                                                                        \
    /* Select ps2AllPipeData->primType based on mesh type (meshHeader->flags) and clipping */           \
    /* (inFrustum).[in-VU fans/polylines not supported] and choose transType, as in */                  \
    /* RxSkyTransTypeFlags: [FOG], [PERSP/ISO], CLIP, STRIP/LIST, TRI/LINE, [CULL] */                   \
    /* The [] bracketed ones are from the global state variable skyTransType */                         \
                                                                                                        \
    if ((_p2apd->meshHeader->flags & rpMESHHEADERTRISTRIP) == rpMESHHEADERTRISTRIP)                     \
    {                                                                                                   \
        /* GS manual p113/114 - triStrip */                                                             \
        _p2apd->primType = 4;                                                                           \
        if (_infm == rwSPHEREINSIDE)                                                                    \
        {                                                                                               \
            /* We don't need to clip  :-) */                                                            \
            _p2apd->transType =                                                                         \
                skyTransType /*| rxSKYTRANSTYPECLIP | rxSKYTRANSTYPELIST | rxSKYTRANSTYPELINE*/;        \
        }                                                                                               \
        else                                                                                            \
        {                                                                                               \
            /* We need to clip  :-( */                                                                  \
            _p2apd->transType =                                                                         \
                skyTransType | rxSKYTRANSTYPECLIP /*| rxSKYTRANSTYPELIST | rxSKYTRANSTYPELINE*/;        \
            /* The true TS clipper fixes up the primCode itself on VU1 */                               \
            /* The culling clipper still submits strips */                                              \
        }                                                                                               \
    }                                                                                                   \
    else if (((_p2apd->meshHeader->flags & rpMESHHEADERTRIFAN  ) == rpMESHHEADERTRIFAN) ||              \
             ((_p2apd->meshHeader->flags & rpMESHHEADERPRIMMASK) == 0) /* trilist */      )             \
    {                                                                                                   \
        /* TriFans instance into triLists. GS manual p113/114 - triList */                              \
        _p2apd->primType = 3;                                                                           \
        if (_infm == rwSPHEREINSIDE)                                                                    \
        {                                                                                               \
            _p2apd->transType =                                                                         \
                skyTransType /*| rxSKYTRANSTYPECLIP */| rxSKYTRANSTYPELIST /*| rxSKYTRANSTYPELINE*/;    \
        }                                                                                               \
        else                                                                                            \
        {                                                                                               \
            _p2apd->transType =                                                                         \
                skyTransType | rxSKYTRANSTYPECLIP | rxSKYTRANSTYPELIST /*| rxSKYTRANSTYPELINE*/;        \
        }                                                                                               \
    }                                                                                                   \
    else if ((_p2apd->meshHeader->flags & rpMESHHEADERPOINTLIST) == rpMESHHEADERPOINTLIST)              \
    {                                                                                                   \
        /* We can't guess what primitive type you'll submit, so we choose something arbitrarily */      \
        if (_infm == rwSPHEREINSIDE)                                                                    \
        {                                                                                               \
            /* Assume tri strip */                                                                      \
            _p2apd->transType =                                                                         \
                skyTransType /*| rxSKYTRANSTYPECLIP | rxSKYTRANSTYPELIST | rxSKYTRANSTYPELINE*/;        \
        }                                                                                               \
        else                                                                                            \
        {                                                                                               \
            /* Assume ADC-culled tri strips */                                                          \
            _p2apd->transType =                                                                         \
                skyTransType | rxSKYTRANSTYPECLIP /*| rxSKYTRANSTYPELIST | rxSKYTRANSTYPELINE*/;        \
        }                                                                                               \
        /* Tri strip (possibly ADC-culled) */                                                           \
        _p2apd->primType = 4;                                                                           \
    }                                                                                                   \
    else /* (((_p2apd->meshHeader->flags & rpMESHHEADERLINELIST) == rpMESHHEADERLINELIST) ||  */        \
         /*  ((_p2apd->meshHeader->flags & rpMESHHEADERPOLYLINE) == rpMESHHEADERPOLYLINE)   ) */        \
    {                                                                                                   \
        /* PolyLines instance into LineLists. GS manual p113/114 - lineList (lineStrip is 2) */         \
        _p2apd->primType = 1;                                                                           \
                                                                                                        \
        /* For now the line transform always culls and never fogs */                                    \
        if (_infm == rwSPHEREINSIDE)                                                                    \
        {                                                                                               \
            _p2apd->transType =                                                                         \
                skyTransType /*| rxSKYTRANSTYPECLIP */| rxSKYTRANSTYPELIST | rxSKYTRANSTYPELINE;        \
        }                                                                                               \
        else                                                                                            \
        {                                                                                               \
            _p2apd->transType =                                                                         \
                skyTransType | rxSKYTRANSTYPECLIP | rxSKYTRANSTYPELIST | rxSKYTRANSTYPELINE;            \
        }                                                                                               \
    }                                                                                                   \
}                                                                                                       \
MACRO_STOP

/* Used as RpAtomicPS2AllMatModulateSetup (function in debug) */
#define RpAtomicPS2AllMatModulateSetupMacro(_atomic, _ps2AllPipeData)                                   \
    ((_ps2AllPipeData)->matModulate =                                                                   \
        (RpGeometryGetFlags(RpAtomicGetGeometry(_atomic)) &                                             \
         rpGEOMETRYMODULATEMATERIALCOLOR) ? TRUE : FALSE )

/* Used as RpAtomicPS2AllLightingSetup (function in debug) */
#define RpAtomicPS2AllLightingSetupMacro(_ps2AllPipeData, _lightingFunc)                                \
MACRO_START                                                                                             \
{                                                                                                       \
    RxPS2AllPipeData *_p2apd = (_ps2AllPipeData);                                                       \
    RxWorldApplyLightFunc _ltfn = (_lightingFunc);                                                      \
    RpAtomic *_atmc;                                                                                    \
                                                                                                        \
    PS2ALLMACROASSERT(NULL != _p2apd);                                                                  \
    PS2ALLMACROASSERT(NULL != _ltfn);                                                                   \
                                                                                                        \
    _atmc = (RpAtomic *)_p2apd->sourceObject;                                                           \
    PS2ALLMACROASSERT(NULL != _atmc);                                                                   \
    PS2ALLMACROASSERT(NULL != _atmc->geometry);                                                         \
                                                                                                        \
    if (rwObjectTestFlags((_atmc->geometry), rpGEOMETRYLIGHT))                                          \
    {                                                                                                   \
        RwLLLink *cur, *end;                                                                            \
        RwSurfaceProperties *surface;                                                                   \
        RpMeshHeader *meshHeader;                                                                       \
        rpAtomicPS2AllLightData lightingData;                                                           \
        RwMatrix *frameMat;                                                                             \
        RpWorld  *world;                                                                                \
                                                                                                        \
        PS2ALLMACROASSERT(RWMATRIXALIGNMENT(&lightingData.invMat));                                     \
                                                                                                        \
        /* Increase lightFrame - used to ensure that each light is applied only */                      \
        /* once (if an atomic and light both overlap two sectors, you can see how */                    \
        /* the light might be applied twice if we didn't have a check). */                              \
        RWSRCGLOBAL(lightFrame)++;                                                                      \
                                                                                                        \
        world = (RpWorld *) RWSRCGLOBAL(curWorld);                                                      \
        PS2ALLMACROASSERT(NULL != world);                                                               \
                                                                                                        \
        frameMat = RwFrameGetLTM((RwFrame *)rwObjectGetParent(_atmc));                                  \
        PS2ALLMACROASSERT(RWMATRIXALIGNMENT(frameMat));                                                 \
                                                                                                        \
        /* Setup the lighting data block */                                                             \
        lightingData.lightFunc = _ltfn;                                                                 \
        RwMatrixInvert(&lightingData.invMat, frameMat);                                                 \
                                                                                                        \
        if ((rwMatrixGetFlags(frameMat) & rwMATRIXTYPEMASK) == rwMATRIXTYPEORTHONORMAL)                 \
        {                                                                                               \
            lightingData.invScale = (RwReal) 1.0;                                                       \
        }                                                                                               \
        else                                                                                            \
        {                                                                                               \
            lightingData.invScale = RwV3dDotProduct(&lightingData.invMat.at, &lightingData.invMat.at);  \
                                                                                                        \
            rwSqrtMacro(lightingData.invScale, lightingData.invScale);                                  \
        }                                                                                               \
                                                                                                        \
        /*lightingData.surface = &atomic->geometry->surfaceProps;*/                                     \
        /* temporary hack to get the surface properties from the first mesh */                          \
        meshHeader = _atmc->geometry->mesh;                                                             \
        PS2ALLMACROASSERT(NULL != meshHeader);                                                          \
        surface = &((RpMesh*)(((RwUInt8*)(meshHeader + 1)) +                                            \
                              meshHeader->firstMeshOffset))->material->surfaceProps;                    \
        lightingData.surface = surface;                                                                 \
                                                                                                        \
        /* Directional light it */                                                                      \
        rpWorldForAllGlobalLights(RpAtomicPS2AllDoApplyLight, &lightingData);                           \
                                                                                                        \
        /* For all sectors that this atomic lies in, apply all lights within */                         \
        cur = rwLinkListGetFirstLLLink(&_atmc->llWorldSectorsInAtomic);                                 \
        end = rwLinkListGetTerminator(&_atmc->llWorldSectorsInAtomic);                                  \
        while (cur != end)                                                                              \
        {                                                                                               \
            RpTie *tpTie = rwLLLinkGetData(cur, RpTie, lWorldSectorInAtomic);                           \
                                                                                                        \
            /* Now apply all the lights (but this time we do the frame thing) */                        \
            rpWorldSectorForAllLocalLights(                                                             \
                tpTie->worldSector, RpAtomicPS2AllDoApplyLightFrame, &lightingData);                    \
                                                                                                        \
            /* Next one */                                                                              \
            cur = rwLLLinkGetNext(cur);                                                                 \
        }                                                                                               \
    }                                                                                                   \
}                                                                                                       \
MACRO_STOP

/* Used as RpAtomicPS2AllFinalize (function in debug) */
#define RpAtomicPS2AllFinalizeMacro(_atomic)                                                            \
MACRO_START                                                                                             \
{                                                                                                       \
    /* Some flags are cleared once per atomic not per mesh, */                                          \
    /* given that meshes are instanced/reinstanced separately */                                        \
    RpAtomic *_atmc = (_atomic);                                                                        \
    RpGeometry *_gmty = RpAtomicGetGeometry(_atmc);                                                     \
    RpInterpolator *_iplr = RpAtomicGetInterpolator(_atmc);                                             \
                                                                                                        \
    PS2ALLMACROASSERT(NULL != _gmty);                                                                   \
    PS2ALLMACROASSERT(NULL != _iplr);                                                                   \
                                                                                                        \
    _gmty->lockedSinceLastInst = 0;                                                                     \
    _iplr->flags &= ~rpINTERPOLATORDIRTYINSTANCE;                                                       \
}                                                                                                       \
MACRO_STOP

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


/* Can't nest # directives in macros, so have to have predicate some
 * separated sub-sections for RpAtomicPS2AllResEntryAllocMacro */
#if (defined(FASTMORPH))
#define _AtomicResAllocMorph()                                                                          \
    if (_p2apd->fastMorphing)                                                                           \
    {                                                                                                   \
        /* FastMorphing atomic */                                                                       \
       *_rsny = RwResourcesAllocateResEntry(_p2apd->sourceObject, _rsny, _cyze, _dycb);                 \
    }                                                                                                   \
    else
#else /* (defined(FASTMORPH)) */
#define _AtomicResAllocMorph() /* No op */
#endif /* (defined(FASTMORPH)) */

/* Used as RpAtomicPS2AllResEntryAlloc (function in debug) */
#define RpAtomicPS2AllResEntryAllocMacro(_ps2AllPipeData, _repEntry, _size, _destroyCallBack)           \
MACRO_START                                                                                             \
{                                                                                                       \
    RxPS2AllPipeData *_p2apd  = (_ps2AllPipeData);                                                      \
    RwResEntry **_rsny = (_repEntry);                                                                   \
    RwResEntryDestroyNotify _dycb = (_destroyCallBack);                                                 \
    RwUInt32 _cyze = (_size);                                                                           \
                                                                                                        \
    _AtomicResAllocMorph()                                                                              \
    {                                                                                                   \
        RpGeometry *_gmty;                                                                              \
                                                                                                        \
        _gmty = RpAtomicGetGeometry((RpAtomic *)(_p2apd->sourceObject));                                \
        PS2ALLMACROASSERT(NULL != _gmty);                                                               \
                                                                                                        \
        if (_gmty->instanceFlags & rpGEOMETRYINSTANCE)                                                  \
        {                                                                                               \
            /* Persistent geometry */                                                                   \
           *_rsny = _rwResourcesAllocateResEntry(_gmty, _rsny, _cyze, rwMEMORYPOOLDEFAULT, _dycb);      \
        }                                                                                               \
        else                                                                                            \
        {                                                                                               \
            /* Non-fastmorphing, non-persistent atomic */                                               \
           *_rsny = RwResourcesAllocateResEntry(_gmty, _rsny, _cyze, _dycb);                            \
        }                                                                                               \
    }                                                                                                   \
}                                                                                                       \
MACRO_STOP



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

/* Default RW callbacks */
extern RwBool RpAtomicPS2AllObjectSetupCallBack(
    RxPS2AllPipeData *ps2AllPipeData,
    RwMatrix **transform,
    RxWorldApplyLightFunc lightingFunc);
/* Shared between atomics and sectors (so materials may be shared) */
extern RwBool RpMeshPS2AllMeshInstanceTestCallBack(
    RxPS2AllPipeData *ps2AllPipeData);
/* Shared between atomics and sectors (so materials may be shared) */
extern RwResEntry *RpMeshPS2AllResEntryAllocCallBack(
    RxPS2AllPipeData *ps2AllPipeData,
    RwResEntry **repEntry,
    RwUInt32 size,
    RwResEntryDestroyNotify destroyCallBack);
/* Shared between atomics and sectors (so materials may be shared) */
extern RwBool RpMeshPS2AllInstanceCallBack(
    RxPS2AllPipeData *ps2AllPipeData,
    void **clusters,
    RwUInt32 numClusters);
/* Shared between atomics and sectors (so materials may be shared) */
extern RwBool RpMeshPS2AllBridgeCallBack(
    RxPS2AllPipeData *ps2AllPipeData);
/* Shared between atomics and sectors (so materials may be shared) */
extern RwBool RpMeshPS2AllPostMeshCallBack(
    RxPS2AllPipeData *ps2AllPipeData);
extern RwBool RpAtomicPS2AllObjectFinalizeCallBack(
    RxPS2AllPipeData *ps2AllPipeData);

/* Standard instance func for atomics */
RwBool RpAtomicPS2AllInstance(RxPS2AllPipeData *ps2AllPipeData);

/* Callbacks used by the standard lighting func */
extern RpLight *RpAtomicPS2AllDoApplyLight(RpLight *light, void *pData);
extern RpLight *RpAtomicPS2AllDoApplyLightFrame(RpLight *light, void *pData);

/* Callback components, for use in user callbacks */
/* ObjectSetupCB */
extern void RpAtomicPS2AllGetMeshHeaderMeshCacheFunc(
    RpAtomic *atomic,
    RxPS2AllPipeData *ps2AllPipeData);
extern void RpAtomicPS2AllGatherObjMetricsFunc(
    RpAtomic *atomic);
extern void RpAtomicPS2AllMorphSetupFunc(
    RpAtomic *atomic,
    RxPS2AllPipeData *ps2AllPipeData);
extern void RpAtomicPS2AllObjInstanceTestFunc(
    RpAtomic *atomic,
    RxPS2AllPipeData *ps2AllPipeData);
extern void RpAtomicPS2AllTransformSetupFunc(
    RpAtomic *atomic,
    RwMatrix **transform);
extern void RpAtomicPS2AllFrustumTestFunc(
    RpAtomic *atomic,
    RwFrustumTestResult *inFrustum);
extern void RpAtomicPS2AllPrimTypeTransTypeSetupFunc(
    RxPS2AllPipeData *ps2AllPipeData,
    RwFrustumTestResult inFrustum);
extern void RpAtomicPS2AllMatModulateSetupFunc(
    RpAtomic *atomic,
    RxPS2AllPipeData *ps2AllPipeData);
extern void RpAtomicPS2AllLightingSetupFunc(
    RxPS2AllPipeData *ps2AllPipeData,
    RxWorldApplyLightFunc lightingFunc);
/* ObjectFinalizeCB */
extern void RpAtomicPS2AllFinalizeFunc(
    RpAtomic *atomic);
/* ResEntryAllocCB */
extern void RpAtomicPS2AllResEntryAllocFunc(
    RxPS2AllPipeData *ps2AllPipeData,
    RwResEntry **repEntry,
    RwUInt32 size,
    RwResEntryDestroyNotify destroyCallBack);
/* PostMeshCB */
extern void RpMeshPS2AllGatherMeshMetricsFunc(
    RxPS2AllPipeData *ps2AllPipeData);

#if (defined(RWDEBUG))
#define RpAtomicPS2AllGetMeshHeaderMeshCache    RpAtomicPS2AllGetMeshHeaderMeshCacheFunc
#define RpAtomicPS2AllGatherObjMetrics          RpAtomicPS2AllGatherObjMetricsFunc
#define RpAtomicPS2AllMorphSetup                RpAtomicPS2AllMorphSetupFunc
#define RpAtomicPS2AllObjInstanceTest           RpAtomicPS2AllObjInstanceTestFunc
#define RpAtomicPS2AllTransformSetup            RpAtomicPS2AllTransformSetupFunc
#define RpAtomicPS2AllFrustumTest               RpAtomicPS2AllFrustumTestFunc
#define RpAtomicPS2AllPrimTypeTransTypeSetup    RpAtomicPS2AllPrimTypeTransTypeSetupFunc
#define RpAtomicPS2AllMatModulateSetup          RpAtomicPS2AllMatModulateSetupFunc
#define RpAtomicPS2AllLightingSetup             RpAtomicPS2AllLightingSetupFunc
#define RpAtomicPS2AllFinalize                  RpAtomicPS2AllFinalizeFunc
#define RpAtomicPS2AllResEntryAlloc             RpAtomicPS2AllResEntryAllocFunc
#define RpMeshPS2AllGatherMeshMetrics           RpMeshPS2AllGatherMeshMetricsFunc
#else /* (defined(RWDEBUG)) */
#define RpAtomicPS2AllGetMeshHeaderMeshCache    RpAtomicPS2AllGetMeshHeaderMeshCacheMacro
#define RpAtomicPS2AllGatherObjMetrics          RpAtomicPS2AllGatherObjMetricsMacro
#define RpAtomicPS2AllMorphSetup                RpAtomicPS2AllMorphSetupMacro
#define RpAtomicPS2AllObjInstanceTest           RpAtomicPS2AllObjInstanceTestMacro
#define RpAtomicPS2AllTransformSetup            RpAtomicPS2AllTransformSetupMacro
#define RpAtomicPS2AllFrustumTest               RpAtomicPS2AllFrustumTestMacro
#define RpAtomicPS2AllPrimTypeTransTypeSetup    RpAtomicPS2AllPrimTypeTransTypeSetupMacro
#define RpAtomicPS2AllMatModulateSetup          RpAtomicPS2AllMatModulateSetupMacro
#define RpAtomicPS2AllLightingSetup             RpAtomicPS2AllLightingSetupMacro
#define RpAtomicPS2AllFinalize                  RpAtomicPS2AllFinalizeMacro
#define RpAtomicPS2AllResEntryAlloc             RpAtomicPS2AllResEntryAllocMacro
#define RpMeshPS2AllGatherMeshMetrics           RpMeshPS2AllGatherMeshMetricsMacro
#endif /* (defined(RWDEBUG)) */

#ifdef    __cplusplus
}
#endif /* __cplusplus */


/*--- Automatically derived from: pipe/p2/sky2/ps2allim3d.h ---*/

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 */
};

#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) */
#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) */
#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) */
#define RwIm3DPS2AllMeshEndMacro(_stash, _ps2AllPipeData)                                               \
    ((_stash)->objVerts = gIm3DData.tempObjVerts)



#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);

/* 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 *_stch,
    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 */


/*--- Automatically derived from: pipe/p2/sky2/matbridge.h ---*/
#if (defined(RWASSERT))
#define PS2ALLMACROASSERT(args) RWASSERT(args)
#else /* (!defined(RWASSERT)) */
#define PS2ALLMACROASSERT(args) /* No op */
#endif /* (!defined(RWASSERT)) */

/* Used as RpMeshPS2AllAsyncTextureUpload (function in debug) */
#define RpMeshPS2AllAsyncTextureUploadMacro(_ps2AllPipeData)                                            \
MACRO_START                                                                                             \
{                                                                                                       \
    RxPS2AllPipeData *_p2apd = (_ps2AllPipeData);                                                       \
                                                                                                        \
    if (NULL != _p2apd->texture)                                                                        \
    {                                                                                                   \
        PS2ALLMACROASSERT(NULL != _p2apd->texture->raster);                                             \
        RpSkyTexCacheAccessSpeculate(_p2apd->texture->raster);                                          \
    }                                                                                                   \
}                                                                                                       \
MACRO_STOP

#if (!defined(__MWERKS__))
#define _rxPS2AllTexFilterASM(_filtering)                                                   \
MACRO_START                                                                                 \
{                                                                                           \
    /* We try to force CW to work by using a temp var */                                    \
    long tmp = 0;                                                                           \
                                                                                            \
/* *INDENT-OFF* */                                                                          \
    asm __volatile__ (                                                                      \
        ".set noreorder        ;                                                            \
        .set noat              ;                                                            \
                                                                                            \
        ori $at, $0, 0x6       ;                                                            \
        beql $at, %2, nps2mb0  ;                                                            \
        ori %0, %1, 0x160      ;                                                            \
                                                                                            \
        ori $at, $0, 0x5       ;                                                            \
        beql $at, %2, nps2mb0  ;                                                            \
        ori %0, %1, 0xc0       ;                                                            \
                                                                                            \
        ori $at, $0, 0x4       ;                                                            \
        beql $at, %2, nps2mb0  ;                                                            \
        ori %0, %1, 0x120      ;                                                            \
                                                                                            \
        ori $at, $0, 0x3       ;                                                            \
        beql $at, %2, nps2mb0  ;                                                            \
        ori %0, %1, 0x80       ;                                                            \
                                                                                            \
        ori $at, $0, 0x2       ;                                                            \
        beql $at, %2, nps2mb0  ;                                                            \
        ori %0, %1, 0x60       ;                                                            \
                                                                                            \
        ori %0,%1,0x0          ;                                                            \
                                                                                            \
        nps2mb0: nop           ;                                                            \
                                                                                            \
        .set reorder           ;                                                            \
        .set at                                                                             \
      " : "=r" (tmp)                                                                        \
      : "r" (skyTex1_1 & ~0x1e0l),                                                          \
      "r" (_filtering));                                                                    \
                                                                                            \
    skyTex1_1 = tmp;                                                                        \
}                                                                                           \
MACRO_STOP
#endif /* (!defined(__MWERKS__)) */

/* Used as (function in debug) */
#define RpMeshPS2AllSyncTextureUploadMacro(_ps2AllPipeData)                                             \
MACRO_START                                                                                             \
{                                                                                                       \
    RxPS2AllPipeData *_p2apd = (_ps2AllPipeData);                                                       \
    RwTexture *_nwtx;                                                                                   \
    RwRaster  *_nwrs = (RwRaster *)NULL;                                                                \
                                                                                                        \
    /* Get appropriate setup done even if (NULL == texture) */                                          \
    _nwtx = _p2apd->texture;                                                                            \
    if (NULL != _nwtx) _nwrs = _nwtx->raster;                                                           \
                                                                                                        \
    if (_nwrs != skyTextureRaster)                                                                      \
    {                                                                                                   \
        /* Raster to texture with */                                                                    \
        skyTextureRaster = _nwrs;                                                                       \
                                                                                                        \
        skyAlphaTex = FALSE;                                                                            \
        if (NULL != skyTextureRaster)                                                                   \
        {                                                                                               \
            const RwUInt32 cFormat = skyTextureRaster->cFormat & (rwRASTERFORMATPIXELFORMATMASK >> 8);  \
                                                                                                        \
            /* If an alpha format texture - enable alpha blending */                                    \
            skyAlphaTex |= ((rwRASTERFORMAT1555 >> 8) == cFormat) |                                     \
                           ((rwRASTERFORMAT8888 >> 8) == cFormat);                                      \
                                                                                                        \
            skyPrim_State |= 0x10;                                                                      \
                                                                                                        \
            /* Do what it takes to get the raster selected */                                           \
            RpSkyTexCacheAccessRaster(skyTextureRaster, FALSE);                                         \
        }                                                                                               \
        else                                                                                            \
        {                                                                                               \
            skyPrim_State &= ~0x10L;                                                                    \
        }                                                                                               \
                                                                                                        \
        if (skyVertexAlpha | skyAlphaTex)                                                               \
        {                                                                                               \
            skyPrim_State |= 0x40;                                                                      \
        }                                                                                               \
        else                                                                                            \
        {                                                                                               \
            skyPrim_State &= ~0x40L;                                                                    \
        }                                                                                               \
                                                                                                        \
        /* Finally iff skyAlphaTex we turn on Alpha test */                                             \
        if (skyAlphaTex)                                                                                \
        {                                                                                               \
            skyTest_1 |= 1;                                                                             \
        }                                                                                               \
        else                                                                                            \
        {                                                                                               \
            skyTest_1 &= ~1L;                                                                           \
        }                                                                                               \
                                                                                                        \
        if (NULL != _nwtx)                                                                              \
        {                                                                                               \
            /* Old CodeWarrior version from before inline asm worked                */                  \
            /* Switch statements hurt                                               */                  \
            /*    if (_p2apd->texture->filtering == rwFILTERLINEARMIPNEAREST)       */                  \
            /*        skyTex1_1 = (skyTex1_1 & ~0x1e0l) | 0xc0;                     */                  \
            /*    else if (_p2apd->texture->filtering == rwFILTERLINEAR)            */                  \
            /*        skyTex1_1 = (skyTex1_1 & ~0x1e0l) | 0x60;                     */                  \
            /*    else if (_p2apd->texture->filtering == rwFILTERLINEARMIPLINEAR)   */                  \
            /*        skyTex1_1 = (skyTex1_1 & ~0x1e0l) | 0x160;                    */                  \
            /*    else if (_p2apd->texture->filtering == rwFILTERMIPNEAREST)        */                  \
            /*        skyTex1_1 = (skyTex1_1 & ~0x1e0l) | 0x80;                     */                  \
            /*    else if (_p2apd->texture->filtering == rwFILTERMIPLINEAR)         */                  \
            /*        skyTex1_1 = (skyTex1_1 & ~0x1e0l) | 0x120;                    */                  \
            /*    else /*must be rwFILTERNEAREST/                                   */                  \
            /*        skyTex1_1 = skyTex1_1 & ~0x1e0l;                              */                  \
                                                                                                        \
            /* A more efficient texture command production than a switch statement,     */              \
            /* which uses a jump table pulled into the d-cache from the text segment.   */              \
            /* ASSUMES THESE ENUM VALUES AREN'T GOING ANYWHERE  :-)                     */              \
            _rxPS2AllTexFilterASM(_nwtx->filtering);                                                    \
                                                                                                        \
            /* Clamp, wrap, mirror or border. We now have two addressing modes, */                      \
            /* one for U and one for V directions. If the app has never set the */                      \
            /* V direction, then default both U and V to the setting from the   */                      \
            /* U direction, which will have been set.                           */                      \
            skyClamp_1 = 0; /* default to repeat in U and V */                                          \
            if (RwTextureGetAddressingU(_nwtx) == rwTEXTUREADDRESSCLAMP) skyClamp_1 |= 1;               \
            if (RwTextureGetAddressingV(_nwtx) == rwTEXTUREADDRESSCLAMP) skyClamp_1 |= 4;               \
        }                                                                                               \
    }                                                                                                   \
}                                                                                                       \
MACRO_STOP

/* Used as RpMeshPS2AllStartVIFUploads (function in debug) */
#define RpMeshPS2AllStartVIFUploadsMacro(_createDMATag, _numQW)                                         \
MACRO_START                                                                                             \
{                                                                                                       \
    RwUInt32 _nmQW = (_numQW);                                                                          \
                                                                                                        \
    /* Open a VIF packet, with TTE set and numQW QWs. */                                                \
    sweFinaliseOpenLocalPkt(                                                                            \
        SWE_PKT_VU1 | SWE_PKT_CIRCALLOC | SWE_PKT_DMA_MODE_CHAIN_TTE | SWE_LPS_NOFIXUP, -_nmQW);        \
    PS2ALLMACROASSERT(NULL != sweLocalPacket);                                                          \
                                                                                                        \
    /* Make a standard DMA tag, no embedded VIFTag, no chain, no ref, numQW QWs */                      \
    if (FALSE != (_createDMATag))                                                                       \
    {                                                                                                   \
        RwUInt64  tmp;                                                                                  \
        u_long128 ltmp = 0;                                                                             \
                                                                                                        \
        tmp = (1L << 28) | (_nmQW);                                                                     \
        MAKE128(ltmp, 0L, tmp);                                                                         \
        SWEADDCONTFAST(ltmp);                                                                           \
    }                                                                                                   \
}                                                                                                       \
MACRO_STOP

/* Used as RpMeshPS2AllGIFTagUpload (function in debug) */
#define rpMESHPS2ALLGIFTAGNUMQW 2
#define RpMeshPS2AllGIFTagUploadMacro(_ps2AllPipeData)                                                  \
MACRO_START                                                                                             \
{                                                                                                       \
    u_long128 __ltmp = 0;                                                                               \
    RwUInt64  __tmp1;                                                                                   \
                                                                                                        \
    /* A VIFTag to transfer a GIFTag to VU1 memory */                                                   \
    __tmp1 = (((0x6CL << 24) | /* VIF unpack 4-32 */                                                    \
               (0x01L << 16) | /* Transfer 1 QW */                                                      \
             /* vuSDgifTag = 0x03FA, Destination address in VU1 memory (in QWs) */                      \
               (vuSDgifTag)   ) << 32) |                                                                \
             ((1L << 24) | (4 << 8) | (4)); /* How to unpack, length 4W, stride 4W */                   \
    MAKE128(__ltmp, __tmp1, 0L);                                                                        \
    SWEADDCONTFAST(__ltmp);                                                                             \
                                                                                                        \
    /* Mask out old primType in the GIFTag */                                                           \
    ((RwUInt32 *)&gifTagPrim128)[1] &= ~(                   0x7F8  << (47 - 32));                       \
    /* Now set the new primType */                                                                      \
    ((RwUInt32 *)&gifTagPrim128)[1] |=   ((skyPrim_State) & 0x7FF) << (47 - 32);                        \
    /* GIF tag for 1 primitive using packed mode */                                                     \
    SWEADDCONTFAST(gifTagPrim128);                                                                      \
}                                                                                                       \
MACRO_STOP

#if (!defined(__MWERKS__))
#define _rxPS2AllMatColASM(_matCol, _colScale)                                                          \
MACRO_START                                                                                             \
{                                                                                                       \
    u_long128 __ltmp = 0;                                                                               \
    float     __floattmp1 = 0.0f;                                                                       \
    float     __floattmp2 = 0.0f;                                                                       \
    long      __longtmp = 0;                                                                            \
                                                                                                        \
    /* *INDENT-OFF* */                                                                                  \
    asm ("mul.s %1, %7, %9 ;                                                                            \
          mul.s %2, %5, %8 ;                                                                            \
                                                                                                        \
          mfc1 %0, %1      ;                                                                            \
          mfc1 %3, %2      ;                                                                            \
                                                                                                        \
          pexew %0, %0     ;                                                                            \
          pexew %3, %3     ;                                                                            \
                                                                                                        \
          mul.s %1, %6, %8 ;                                                                            \
          mul.s %2, %4, %8 ;                                                                            \
                                                                                                        \
          mfc1 %0, %1      ;                                                                            \
          mfc1 %3, %2      ;                                                                            \
                                                                                                        \
          ppacw %0, %0, %3                                                                              \
                                                                                                        \
            " : "=r" (__ltmp),                                                                          \
         "=f&" (__floattmp1),                                                                           \
         "=f&" (__floattmp2),                                                                           \
         "=r"  (__longtmp):                                                                             \
         "f"   ((RwReal)((_matCol)->red)),                                                              \
         "f"   ((RwReal)((_matCol)->green)),                                                            \
         "f"   ((RwReal)((_matCol)->blue)),                                                             \
         "f"   ((RwReal)((_matCol)->alpha)),                                                            \
         "f"   (_colScale),                                                                             \
         "f"   (128.1f/(255.0f*255.0f)) );                                                              \
    SWEADDCONTFAST(__ltmp);                                                                             \
}                                                                                                       \
MACRO_STOP
#endif /* (!defined(__MWERKS__)) */

/* Used as RpMeshPS2AllMatColUpload (function in debug) */
#define rpMESHPS2ALLMATCOLNUMQW 2
#define RpMeshPS2AllMatColUploadMacro(_ps2AllPipeData)                                                  \
MACRO_START                                                                                             \
{                                                                                                       \
    RxPS2AllPipeData *_p2apd  = (_ps2AllPipeData);                                                      \
                                                                                                        \
    u_long128 __ltmp = 0;                                                                               \
    RwUInt64  __tmp1;                                                                                   \
    float     __colScale;                                                                               \
                                                                                                        \
    /* This gets used in texture state setup  */                                                        \
    skyVertexAlpha = (_p2apd->matCol.alpha != 255);                                                     \
                                                                                                        \
    /* A VIFTag to transfer colScale to VU1 memory */                                                   \
    __tmp1 = (((0x6CL << 24) | /* VIF unpack 4-32 */                                                    \
               (0x01L << 16) | /* Transfer 1 QW */                                                      \
             /* vuSDcolScale = 0x03FB, Destination address in VU1 memory (in QWs) */                    \
               (vuSDcolScale) ) << 32) |                                                                \
             ((1L << 24) | (4 << 8) | (4)); /* How to unpack, length 4W, stride 4W */                   \
    MAKE128(__ltmp, __tmp1, 0L);                                                                        \
    SWEADDCONTFAST(__ltmp);                                                                             \
                                                                                                        \
    /* Old metrowerks version (before inline asm worked)                */                              \
    /*  if (!(skyPrim_State & 0x10))                                    */                              \
    /*  {                                                               */                              \
    /*      colScale = 255.0f;                                          */                              \
    /*  }                                                               */                              \
    /*  ((RwReal *) & ltmp)[0] = (colScale / (255.0f*255.0f)) *         */                              \
    /*                           (RwReal)_p2apd->matCol.red;            */                              \
    /*  ((RwReal *) & ltmp)[1] = (colScale / (255.0f*255.0f)) *         */                              \
    /*                           (RwReal)_p2apd->matCol.green;          */                              \
    /*  ((RwReal *) & ltmp)[2] = (colScale / (255.0f*255.0f)) *         */                              \
    /*                           (RwReal)_p2apd->matCol.blue;           */                              \
    /*  ((RwReal *) & ltmp)[3] = (alphaScale / (255.0f*255.0f)) *       */                              \
    /*                           (RwReal)_p2apd->matCol.alpha;          */                              \
                                                                                                        \
    if (skyPrim_State & 0x10)                                                                           \
    {                                                                                                   \
        /* [We have a sneaking suspicion that 128.0f should be 128.1f] */                               \
        __colScale = 128.1f/(255.0f*255.0f);                                                            \
    }                                                                                                   \
    else                                                                                                \
    {                                                                                                   \
        __colScale = 1.0f/255.0f;                                                                       \
    }                                                                                                   \
    _rxPS2AllMatColASM(&(_p2apd->matCol), __colScale);                                                  \
}                                                                                                       \
MACRO_STOP

#if (!defined(__MWERKS__))
#define _rxPS2AllSurfPropsASM(_surfProps, _extra)                                                       \
MACRO_START                                                                                             \
{                                                                                                       \
    u_long128 __ltmp = 0;                                                                               \
    float     __floattmp1 = 0.0f;                                                                       \
    float     __floattmp2 = 0.0f;                                                                       \
    long      __longtmp = 0;                                                                            \
                                                                                                        \
    /* *INDENT-OFF* */                                                                                  \
    asm ("mul.s %2, %5, %7 ;                                                                            \
                                                                                                        \
          mfc1 %0, %8      ;                                                                            \
          mfc1 %3, %2      ;                                                                            \
                                                                                                        \
          pexew %0, %0     ;                                                                            \
          pexew %3, %3     ;                                                                            \
                                                                                                        \
          mul.s %1, %6, %7 ;                                                                            \
          mul.s %2, %4, %7 ;                                                                            \
                                                                                                        \
          mfc1 %0, %1      ;                                                                            \
          mfc1 %3, %2      ;                                                                            \
                                                                                                        \
          ppacw %0, %0, %3                                                                              \
                                                                                                        \
            " : "=r" (__ltmp),                                                                          \
         "=f&" (__floattmp1),                                                                           \
         "=f&" (__floattmp2),                                                                           \
         "=r"  (__longtmp):                                                                             \
         "f"   ((RwReal)((_surfProps)->ambient)),                                                       \
         "f"   ((RwReal)((_surfProps)->specular)),                                                      \
         "f"   ((RwReal)((_surfProps)->diffuse)),                                                       \
         "f"   (255.00001f),                                                                            \
        /* Extra value - e.g 'scale' for the FASTMORPH plugin */                                        \
         "f"   (_extra) );                                                                              \
                                                                                                        \
    SWEADDCONTFAST(__ltmp);                                                                             \
}                                                                                                       \
MACRO_STOP
#endif /* (!defined(__MWERKS__)) */

/* Used as RpMeshPS2AllSurfPropsUpload (function in debug) */
#define rpMESHPS2ALLSURFPROPSNUMQW 2
#define RpMeshPS2AllSurfPropsUploadMacro(_ps2AllPipeData)                                               \
MACRO_START                                                                                             \
{                                                                                                       \
    RxPS2AllPipeData *_p2apd  = (_ps2AllPipeData);                                                      \
                                                                                                        \
    u_long128 __ltmp = 0;                                                                               \
    RwUInt64  __tmp1;                                                                                   \
                                                                                                        \
    /* A VIFTag to transfer (surfProps+extra) to VU1 memory */                                          \
    __tmp1 = (((0x6CL << 24) | /* VIF unpack 4-32 */                                                    \
               (0x01L << 16) | /* Transfer 1 QW */                                                      \
             /* vuSDsurfProps = 0x03FC, Destination address in VU1 memory (in QWs) */                   \
               (vuSDsurfProps) ) << 32) |                                                               \
             ((1L << 24) | (4 << 8) | (4)); /* How to unpack, length 4W, stride 4W */                   \
    MAKE128(__ltmp, __tmp1, 0L);                                                                        \
    SWEADDCONTFAST(__ltmp);                                                                             \
                                                                                                        \
    /* Old metrowerks version (before inline asm worked)                                    */          \
    /* ((RwReal *) & ltmp)[0] = 255.00001f * (RwReal) ps2AllPipeData->surfProps->ambient;   */          \
    /* ((RwReal *) & ltmp)[1] = 255.00001f * (RwReal) ps2AllPipeData->surfProps->specular;  */          \
    /* ((RwReal *) & ltmp)[2] = 255.00001f * (RwReal) ps2AllPipeData->surfProps->diffuse;   */          \
    /* ((RwReal *) & ltmp)[3] = 255.00001f * (RwReal) ps2AllPipeData->spExtra;              */          \
                                                                                                        \
    /* Surface prop */                                                                                  \
    _rxPS2AllSurfPropsASM(_p2apd->surfProps, _p2apd->spExtra);                                          \
}                                                                                                       \
MACRO_STOP


/* Can't nest # directives in macros, so have to have predicate some
 * separated sub-sections for RpMeshPS2AllClipInfoUploadMacro */
#if (defined(VUCONTINUE))
/*TODO[6]: THE DIFFERENCE BETWEEN VUCONTINUE AND non-VUCONTINUE VERSIONS NEEDS DOCUMENTING */
#define RpPS2AllClipTmp1Setup(_tempone) \
    (_tempone = (1L << 32) | skyUserSwitch1)
#else /* (defined(VUCONTINUE)) */
#define RpPS2AllClipTmp1Setup(_tempone) \
    (_tempone = (((RwUInt64)skyUserSwitch2) << 32) | skyUserSwitch1)
#endif /* (defined(VUCONTINUE)) */

/* Used as RpMeshPS2AllClipInfoUpload (function in debug) */
#define rpMESHPS2ALLCLIPINFONUMQW 4
#define RpMeshPS2AllClipInfoUploadMacro(_ps2AllPipeData)                                                \
MACRO_START                                                                                             \
{                                                                                                       \
    RxPS2AllPipeData *_p2apd  = (_ps2AllPipeData);                                                      \
                                                                                                        \
    u_long128 __ltmp = 0;                                                                               \
    RwUInt64  __tmp1;                                                                                   \
    RwUInt32  __skySwitchFlag;                                                                          \
                                                                                                        \
    __skySwitchFlag = _p2apd->transType & (rxSKYTRANSTYPEFOG|rxSKYTRANSTYPECLIP|rxSKYTRANSTYPELIST);    \
                                                                                                        \
    /* A VIFTag to transfer the Clip Vectors and SwitchQW to VU1 memory */                              \
    __tmp1 = (((0x6CL << 24) | /* VIF unpack 4-32 */                                                    \
               (0x03L << 16) | /* Transfer 3 QWs */                                                     \
             /* vuSDClipvec1 = 0x03FD, Destination address in VU1 memory (in QWs) */                    \
             /* [vuSDClipvec2 and vuSDVUSwitch follow directly] */                                      \
               (vuSDClipvec1)   ) << 32) |                                                              \
             ((1L << 24) | (4 << 8) | (4)); /* How to unpack, length 4W, stride 4W */                   \
    MAKE128(__ltmp, __tmp1, 0L);                                                                        \
    SWEADDCONTFAST(__ltmp);                                                                             \
                                                                                                        \
    if((skyTSClipperMode && (!(__skySwitchFlag & 4))) ||                                                \
       (skyTLClipperMode &&   (__skySwitchFlag & 4) )    )                                              \
    {                                                                                                   \
        /* True clipping */                                                                             \
        __skySwitchFlag |= 8;                                                                           \
    }                                                                                                   \
                                                                                                        \
    /* Upload camera clipping info */                                                                   \
    if (__skySwitchFlag & 8)                                                                            \
    {                                                                                                   \
        /* Clipping. Use small frustum */                                                               \
        SWEADDCONTFAST(skyCClipVect1);                                                                  \
        SWEADDCONTFAST(skyCClipVect2);                                                                  \
    }                                                                                                   \
    else                                                                                                \
    {                                                                                                   \
        /* Culling. Use large frustum */                                                                \
        SWEADDCONTFAST(skyClipVect1);                                                                   \
        SWEADDCONTFAST(skyClipVect2);                                                                   \
    }                                                                                                   \
                                                                                                        \
    /* Back/front-face culling flag */                                                                  \
    skyUserSwitch1 = 0;                                                                                 \
    if (gSkyCullState == rwCULLMODECULLFRONT)                                                           \
    {                                                                                                   \
        skyUserSwitch1 = 0x20;                                                                          \
    }                                                                                                   \
                                                                                                        \
    /* Combine skyUserSwitch1 and skyUserSwitch2 (skyUserSwitch2 ignored  */                            \
    /* if VUCONTINUE is defined) and upload with __skySwitchFlag */                                     \
    RpPS2AllClipTmp1Setup(__tmp1);                                                                      \
    MAKE128(__ltmp, __tmp1, __skySwitchFlag);                                                           \
    SWEADDCONTFAST(__ltmp);                                                                             \
}                                                                                                       \
MACRO_STOP


/* Can't nest # directives in macros, so have to have predicate some
 * separated sub-sections for RpMeshPS2AllTextureStateUploadMacro */
#if (defined(LESSEOPS))
#define RpPS2AllTexStateEOP (0L << 15)
#else /* (defined(LESSEOPS)) */
#define RpPS2AllTexStateEOP (1L << 15)
#endif /* (defined(LESSEOPS)) */

/* Used as (function in debug) */
#define rpMESHPS2ALLTEXTURESTATENUMQW 5
#define RpMeshPS2AllTextureStateUploadMacro(_ps2AllPipeData)                                            \
MACRO_START                                                                                             \
{                                                                                                       \
    RxPS2AllPipeData *_p2apd = (_ps2AllPipeData);                                                       \
                                                                                                        \
    RwUInt64  __tmp, __tmp1;                                                                            \
    u_long128 __ltmp = 0;                                                                               \
                                                                                                        \
    if (NULL != _p2apd->texture)                                                                        \
    {                                                                                                   \
        /* VIF tag sending 4 QWs thru VIF direct to the GS */                                           \
        __tmp1 = ((0x50L << 24) | 4L) << 32;                                                            \
        MAKE128(__ltmp, __tmp1, 0L);                                                                    \
        SWEADDCONTFAST(__ltmp);                                                                         \
                                                                                                        \
        __tmp = /* NLOOP */ 3L |                                                                        \
                /* EOP   */ RpPS2AllTexStateEOP |                                                       \
                /* PRE   */ (0L << 46) |                                                                \
                /* FLG   */ (0L << 58) |                                                                \
                /* NREG  */ (1L << 60);                                                                 \
        /* '(64 - 64)' is because we're writing to bit 64 of a 128-bit QW, but we're using */           \
        /* a 64-bit variable to do so... helps keep track of which bit we're writing to. */             \
        __tmp1 = /* A+D */ (0xEL << (64 - 64));                                                         \
        MAKE128(__ltmp, __tmp1, __tmp);                                                                 \
        SWEADDCONTGIFFAST(__ltmp, 1);                                                                   \
                                                                                                        \
        __tmp = skyTest_1;                                                                              \
        __tmp1 = (GS_TEST_1 << (64 - 64));                                                              \
        MAKE128(__ltmp, __tmp1, __tmp);                                                                 \
        SWEADDCONTFAST(__ltmp);                                                                         \
                                                                                                        \
        __tmp = skyTex1_1;                                                                              \
        __tmp1 = (GS_TEX1_1 << (64 - 64));                                                              \
        MAKE128(__ltmp, __tmp1, __tmp);                                                                 \
        SWEADDCONTFAST(__ltmp);                                                                         \
                                                                                                        \
        __tmp = skyClamp_1;                                                                             \
        __tmp1 = (GS_CLAMP_1 << (64 - 64));                                                             \
        MAKE128(__ltmp, __tmp1, __tmp);                                                                 \
        SWEADDCONTFAST(__ltmp);                                                                         \
    }                                                                                                   \
    else                                                                                                \
    {                                                                                                   \
        /* This is inlined from _rwSkySetRenderState(rwRENDERSTATETEXTURERASTER, NULL) */               \
        /* Other bits are done in RpMeshPS2AllSyncTextureUploadMacro */                                 \
                                                                                                        \
        /* Since skyVertexAlpha may be TRUE, we may need to turn on Alpha test */                       \
        if (skyTest_1 & 1)                                                                              \
        {                                                                                               \
            /* Need to transfer 5 QW in total, add 2 NOPs */                                            \
            SWEADDCONTFAST(__ltmp);                                                                     \
            SWEADDCONTFAST(__ltmp);                                                                     \
                                                                                                        \
            skyTest_1 &= ~1L;                                                                           \
                                                                                                        \
            /* VIF tag sending 2 QWs thru VIF direct to the GS */                                       \
            __tmp1 = ((0x50L << 24) | 2L) << 32;                                                        \
            MAKE128(__ltmp, __tmp1, 0L);                                                                \
            SWEADDCONTFAST(__ltmp);                                                                     \
                                                                                                        \
            __tmp = /* NLOOP */ 1L |                                                                    \
                  /* EOP   */ RpPS2AllTexStateEOP |                                                     \
                  /* PRE   */ (0L << 46) |                                                              \
                  /* FLG   */ (0L << 58) |                                                              \
                  /* NREG  */ (1L << 60);                                                               \
            __tmp1 = /* A+D */ (0xEL << (64 - 64));                                                     \
            MAKE128(__ltmp, __tmp1, __tmp);                                                             \
            SWEADDCONTGIFFAST(__ltmp, 1);                                                               \
                                                                                                        \
            __tmp = skyTest_1;                                                                          \
            __tmp1 = (GS_TEST_1 << (64 - 64));                                                          \
            MAKE128(__ltmp, __tmp1, __tmp);                                                             \
            SWEADDCONTFAST(__ltmp);                                                                     \
        }                                                                                               \
        else                                                                                            \
        {                                                                                               \
            /* Need to transfer 5 QW in total, add 5 NOPs (NULL raster is rare) */                      \
            SWEADDCONTFAST(__ltmp);                                                                     \
            SWEADDCONTFAST(__ltmp);                                                                     \
            SWEADDCONTFAST(__ltmp);                                                                     \
            SWEADDCONTFAST(__ltmp);                                                                     \
            SWEADDCONTFAST(__ltmp);                                                                     \
        }                                                                                               \
    }                                                                                                   \
}                                                                                                       \
MACRO_STOP

/* Used as RpMeshPS2AllVU1CodeIndexSetup (function in debug) */
#define RpMeshPS2AllVU1CodeIndexSetupMacro(_ps2AllPipeData)                                             \
MACRO_START                                                                                             \
{                                                                                                       \
    RxPS2AllPipeData *_p2apd = (_ps2AllPipeData);                                                       \
                                                                                                        \
    _p2apd->vu1CodeIndex = ((rxSKYTRANSTYPELINE & _p2apd->transType) >> 2) |                            \
                           ((rxSKYTRANSTYPEISO  & _p2apd->transType) >> 2) |                            \
                           ((rxSKYTRANSTYPECULL & _p2apd->transType) >> 5);                             \
}                                                                                                       \
MACRO_STOP


/* Can't nest # directives in macros, so have to have predicate some
 * separated sub-sections for RpMeshPS2AllVU1CodeUploadMacro */
#if (defined(VUCONTINUE))
#define RpMeshNewVU1CodeCont()                                                                          \
MACRO_START                                                                                             \
{                                                                                                       \
    RwUInt64  __tmp, __tmp1;                                                                            \
    u_long128 __ltmp = 0;                                                                               \
                                                                                                        \
    /* This DMA tag transfers no QWs, but TTE's enabled so it gets transferred  */                      \
    /* (along with the embedded VIF tag below).                                 */                      \
    /* NOTE: we do this as late as poss. so as much transfer (in parallel with VU1  */                  \
    /* code execution) as poss. before the flush, at the cost of this extra DMA tag */                  \
    __tmp  = 1L << 28;                                                                                  \
    /* This VIF tag does a flush (waits for VU code execution to complete) */                           \
    __tmp1 = 0x15L << 24;                                                                               \
    MAKE128(__ltmp, __tmp1, __tmp);                                                                     \
    SWEADDCONTFAST(__ltmp);                                                                             \
}                                                                                                       \
MACRO_STOP
#else /* (defined(VUCONTINUE)) */
#define RpMeshNewVU1CodeCont()                                                                          \
MACRO_START                                                                                             \
{ /* No op */ }                                                                                         \
MACRO_STOP
#endif /* (defined(VUCONTINUE)) */

/* Used as RpMeshPS2AllVU1CodeUpload (function in debug) */
#define RpMeshPS2AllVU1CodeUploadMacro(_ps2AllPipeData)                                                 \
MACRO_START                                                                                             \
{                                                                                                       \
    RxPS2AllPipeData *_p2apd  = (_ps2AllPipeData);                                                      \
    const void *_kohd;                                                                                  \
                                                                                                        \
    /* Assumes the VU1CodeArray is always set up (if nothing else, to     */                            \
    /* skyVU1Transforms in PS2AllPipelineNodeInit) and contains no NULLs. */                            \
    PS2ALLMACROASSERT(NULL != _p2apd->matPvtData->vu1CodeArray);                                        \
    _kohd = _p2apd->matPvtData->vu1CodeArray[_p2apd->vu1CodeIndex];                                     \
    PS2ALLMACROASSERT(NULL != _kohd);                                                                   \
    /* The DMA tag (optionally) created by RpMeshPS2AllStartVIFUploadsMacro finishes */                 \
    /* transferring just before us so we're free to either add a new DMA tag or not. */                 \
    if (skyUploadedCode != _kohd)                                                                       \
    {                                                                                                   \
        RwUInt64  tmp;                                                                                  \
        u_long128 ltmp = 0;                                                                             \
                                                                                                        \
        /* This DMA tag calls the code upload chunk (has its own DMA transfer tag) */                   \
        tmp  = (5L << 28) | (RwUInt64) ((RwUInt32) _kohd) << 32;                                        \
        MAKE128(ltmp, 0L, tmp);                                                                         \
        SWEADDCONTFAST(ltmp);                                                                           \
        skyUploadedCode = _kohd;                                                                        \
                                                                                                        \
        /* Do VUCONTINUE stuff */                                                                       \
        RpMeshNewVU1CodeCont();                                                                         \
    }                                                                                                   \
}                                                                                                       \
MACRO_STOP


/* Used as RpMeshPS2AllEndVIFUploads (function in debug) */
#define RpMeshPS2AllEndVIFUploadsMacro(_ps2AllPipeData)                                                 \
MACRO_START                                                                                             \
{                                                                                                       \
    RxPS2AllPipeData       *_p2apd  = (_ps2AllPipeData);                                                \
    rwPS2AllResEntryHeader *_p2rh;                                                                      \
                                                                                                        \
    RwUInt64            __tmp, __tmp1;                                                                  \
    u_long128           __ltmp = 0;                                                                     \
                                                                                                        \
    _p2rh = RWPS2ALLRESENTRYHEADERFROMRESENTRY(*(_p2apd->cacheEntryRef));                               \
                                                                                                        \
    /* This DMA tag calls the geometry chain which (has its own DMA tags and) returns here when done */ \
    __tmp  = (((RwUInt64)(RwUInt32)(_p2rh->data)) << 32) | (5L << 28);                                  \
    /* This sets up the VIF offset (i.e which batch the geom chain will transfer into) */               \
    __tmp1 = (3L << 24) | 0 |                                                                           \
             (((2L << 24) | _p2apd->matPvtData->vifOffset) << 32); /* Reset vifOffset */                \
    MAKE128(__ltmp, __tmp1, __tmp);                                                                     \
    SWEADDCONTFAST(__ltmp);                                                                             \
                                                                                                        \
    /* This DMA tag terminates the DMA transfer chain - it may be overwritten if the    */              \
    /* packet is extended later (that's what SWE_LPS_CONT does below). We also set an   */              \
    /* interrupt bit just to flag this as a valid end-of-chain tag as a debug check.    */              \
    __tmp = (0xFL << 28);                                                                               \
    MAKE128(__ltmp, 0L, __tmp);                                                                         \
    SWEADDCONTFAST(__ltmp);                                                                             \
                                                                                                        \
    /* Add a "CONT" packet to allow DMA packets to be continued after VU code upload.   */              \
    /* Without this statement, the DMA packet stream has to be stopped and restarted    */              \
    /* which introduces a large DMA management overhead.                                */              \
    sweFinaliseOpenLocalPkt(SWE_LPS_CONT, 0);                                                           \
                                                                                                        \
    /* Reference count stuff (used when objects are destroyed)  */                                      \
    /* clrCnt improves efficiency by allowing many reference    */                                      \
    /* increments in one packet to be performed in one go       */                                      \
    DI();                                                                                               \
    _p2rh->refCnt += 1;                                                                                 \
    EI();                                                                                               \
    _p2rh->clrCnt += 1;                                                                                 \
    if (_p2rh->clrCnt == 1)                                                                             \
    {                                                                                                   \
        _sweProcrastinatedAddURef((RwUInt32 *)&(_p2rh->refCnt));                                        \
    }                                                                                                   \
}                                                                                                       \
MACRO_STOP


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

/* Callback components, for use in the BridgeCB */
extern void RpMeshPS2AllAsyncTextureUploadFunc(
    RxPS2AllPipeData *ps2AllPipeData);
extern void RpMeshPS2AllSyncTextureUploadFunc(
    RxPS2AllPipeData *ps2AllPipeData);
extern void RpMeshPS2AllStartVIFUploadsFunc(
    RwBool createDMATag,
    RwUInt32 numQW);
extern void RpMeshPS2AllGIFTagUploadFunc(
    RxPS2AllPipeData *ps2AllPipeData);
extern void RpMeshPS2AllMatColUploadFunc(
    RxPS2AllPipeData *ps2AllPipeData);
extern void RpMeshPS2AllSurfPropsUploadFunc(
    RxPS2AllPipeData *ps2AllPipeData);
extern void RpMeshPS2AllClipInfoUploadFunc(
    RxPS2AllPipeData *ps2AllPipeData);
extern void RpMeshPS2AllTextureStateUploadFunc(
    RxPS2AllPipeData *ps2AllPipeData);
extern void RpMeshPS2AllVU1CodeIndexSetupFunc(
    RxPS2AllPipeData *ps2AllPipeData);
extern void RpMeshPS2AllVU1CodeUploadFunc(
    RxPS2AllPipeData *ps2AllPipeData);
extern void RpMeshPS2AllEndVIFUploadsFunc(
    RxPS2AllPipeData *ps2AllPipeData);

#if (defined(RWDEBUG))
#define RpMeshPS2AllAsyncTextureUpload          RpMeshPS2AllAsyncTextureUploadFunc
#define RpMeshPS2AllSyncTextureUpload           RpMeshPS2AllSyncTextureUploadFunc
#define RpMeshPS2AllStartVIFUploads             RpMeshPS2AllStartVIFUploadsFunc
#define RpMeshPS2AllGIFTagUpload                RpMeshPS2AllGIFTagUploadFunc
#define RpMeshPS2AllMatColUpload                RpMeshPS2AllMatColUploadFunc
#define RpMeshPS2AllSurfPropsUpload             RpMeshPS2AllSurfPropsUploadFunc
#define RpMeshPS2AllClipInfoUpload              RpMeshPS2AllClipInfoUploadFunc
#define RpMeshPS2AllTextureStateUpload          RpMeshPS2AllTextureStateUploadFunc
#define RpMeshPS2AllVU1CodeIndexSetup           RpMeshPS2AllVU1CodeIndexSetupFunc
#define RpMeshPS2AllVU1CodeUpload               RpMeshPS2AllVU1CodeUploadFunc
#define RpMeshPS2AllEndVIFUploads               RpMeshPS2AllEndVIFUploadsFunc
#else /* (defined(RWDEBUG)) */
#define RpMeshPS2AllAsyncTextureUpload          RpMeshPS2AllAsyncTextureUploadMacro
#define RpMeshPS2AllSyncTextureUpload           RpMeshPS2AllSyncTextureUploadMacro
#define RpMeshPS2AllStartVIFUploads             RpMeshPS2AllStartVIFUploadsMacro
#define RpMeshPS2AllGIFTagUpload                RpMeshPS2AllGIFTagUploadMacro
#define RpMeshPS2AllMatColUpload                RpMeshPS2AllMatColUploadMacro
#define RpMeshPS2AllSurfPropsUpload             RpMeshPS2AllSurfPropsUploadMacro
#define RpMeshPS2AllClipInfoUpload              RpMeshPS2AllClipInfoUploadMacro
#define RpMeshPS2AllTextureStateUpload          RpMeshPS2AllTextureStateUploadMacro
#define RpMeshPS2AllVU1CodeIndexSetup           RpMeshPS2AllVU1CodeIndexSetupMacro
#define RpMeshPS2AllVU1CodeUpload               RpMeshPS2AllVU1CodeUploadMacro
#define RpMeshPS2AllEndVIFUploads               RpMeshPS2AllEndVIFUploadsMacro
#endif /* (defined(RWDEBUG)) */

#if (defined(__MWERKS__))
extern void _rxPS2AllTexFilterASM(RwTextureFilterMode filtering);
extern void _rxPS2AllMatColASM(RwRGBA *matCol, float colScale);
extern void _rxPS2AllSurfPropsASM(RwSurfaceProperties *surfProps, RwReal extra);
#endif /* (defined(__MWERKS__)) */

#ifdef    __cplusplus
}
#endif /* __cplusplus */


/*--- Automatically derived from: pipe/p2/sky2/matinstance.h ---*/

/* Instancing support structs */

struct _rwPS2AllNormalLUTs
{
    /* mask[] masks the index into the indices array
     * in UNindexed mode and masks the addition of
     * vert in INdexed mode - vice versa for mask2 */
    RwUInt8 counterGen;                                 /**< Internal Use */
    RwUInt8 startIndOffset;                             /**< Internal Use */
    RwUInt8 shiftMask[1];                               /**< Internal Use */
    RwUInt8 shiftMask2[1];                              /**< Internal Use */
    RwUInt8 vertInc[1];                                 /**< Internal Use */
};

struct _rwPS2AllTriFanLUTs
{
    /* mask[] masks the index into the indices array
     * in UNindexed mode and masks the addition of
     * vert in INdexed mode - vice versa for mask2 */
    RwUInt8 counterGen;                                 /**< Internal Use */
    RwUInt8 startIndOffset;                             /**< Internal Use */
    RwUInt8 shiftMask[3];                               /**< Internal Use */
    RwUInt8 shiftMask2[3];                              /**< Internal Use */
    RwUInt8 vertInc[3];                                 /**< Internal Use */
};

struct _rwPS2AllPolyLineLUTs
{
    /* mask[] masks the index into the indices array
     * in UNindexed mode and masks the addition of
     * vert in INdexed mode - vice versa for mask2 */
    RwUInt8 counterGen;                                 /**< Internal Use */
    RwUInt8 startIndOffset;                             /**< Internal Use */
    RwUInt8 shiftMask[2];                               /**< Internal Use */
    RwUInt8 shiftMask2[2];                              /**< Internal Use */
    RwUInt8 vertInc[2];                                 /**< Internal Use */
};

typedef struct rwPS2AllIndexLUTs rwPS2AllIndexLUTs;
struct rwPS2AllIndexLUTs
{
    RxVertexIndex         fakeIndices[1];               /**< Internal Use */
    struct _rwPS2AllNormalLUTs    normal;               /**< Internal Use */
    struct _rwPS2AllTriFanLUTs    triFan;               /**< Internal Use */
    struct _rwPS2AllPolyLineLUTs  polyLine;             /**< Internal Use */
};

#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)) */

/* Instancing support defines:
 *
 * Allows one piece of code to instance from any of the
 * six primitive types, indexed or unindexed. Uses a struct
 * of small values (e.g bytes as 4x2-bit LUTs) and redundant
 * cheap calcs to remove predication or code duplication */

#define INDEXDECLARE()                                                      \
    RwUInt32       cntGen, indOffset = 0, startIndOffset, modCnt = 0;       \
    RwUInt32       vertRatio, vertLeadup;                                   \
    const RwUInt8  *shiftMask, *shiftMask2, *vertInc, *swap;                \
    const RxVertexIndex *indexArray

/* N.B Trailing semicolon deliberately omitted from INDEXDECLARE */

#define INDEXSETUP(_flags, _indices)                                          \
MACRO_START                                                                   \
{                                                                             \
    static const rwPS2AllIndexLUTs IndexLUT =                                 \
    {                                                                         \
        {0},                                         /* Fake index 'array' */ \
        {0, 0, {~0},         { 0},       {1}},       /* Normal (default) */   \
        {9, 1, {~0, ~0, ~0}, {~0, 0, 0}, {0, 1, 0}}, /* TriFan */             \
        {1, 0, {~0, ~0},     { 0, 0},    {1, 0}}     /* PolyLine */           \
    };                                                                        \
                                                                              \
    if (_flags & rpMESHHEADERTRIFAN)                                          \
    {                                                                         \
        cntGen         = IndexLUT.triFan.counterGen;                          \
        startIndOffset = IndexLUT.triFan.startIndOffset;                      \
        shiftMask      = &(IndexLUT.triFan.shiftMask[0]);                     \
        shiftMask2     = &(IndexLUT.triFan.shiftMask2[0]);                    \
        vertInc        = &(IndexLUT.triFan.vertInc[0]);                       \
        vertRatio      = 3;                                                   \
        vertLeadup     = 2;                                                   \
    }                                                                         \
    else if (_flags & rpMESHHEADERPOLYLINE)                                   \
    {                                                                         \
        cntGen         = IndexLUT.polyLine.counterGen;                        \
        startIndOffset = IndexLUT.polyLine.startIndOffset;                    \
        shiftMask      = &(IndexLUT.polyLine.shiftMask[0]);                   \
        shiftMask2     = &(IndexLUT.polyLine.shiftMask2[0]);                  \
        vertInc        = &(IndexLUT.polyLine.vertInc[0]);                     \
        vertRatio      = 2;                                                   \
        vertLeadup     = 1;                                                   \
    }                                                                         \
    else                                                                      \
    {                                                                         \
        cntGen         = IndexLUT.normal.counterGen;                          \
        startIndOffset = IndexLUT.normal.startIndOffset;                      \
        shiftMask      = &(IndexLUT.normal.shiftMask[0]);                     \
        shiftMask2     = &(IndexLUT.normal.shiftMask2[0]);                    \
        vertInc        = &(IndexLUT.normal.vertInc[0]);                       \
        vertRatio      = 1;                                                   \
        vertLeadup     = 0;                                                   \
    }                                                                         \
    PS2ALLMACROASSERT(sizeof(RwImVertexIndex) == sizeof(RxVertexIndex));      \
    if (! ((_flags) & rpMESHHEADERUNINDEXED) )                                \
    {                                                                         \
        /* The roles of mask and mask2 swap */                                \
        /* between INdexed and UNindexed */                                   \
        swap       = shiftMask;                                               \
        shiftMask  = shiftMask2;                                              \
        shiftMask2 = swap;                                                    \
        PS2ALLMACROASSERT(_indices != NULL);                                  \
        indexArray = (_indices);                                              \
    }                                                                         \
    else                                                                      \
    {                                                                         \
        indexArray = &(IndexLUT.fakeIndices[0]);                              \
    }                                                                         \
}                                                                             \
MACRO_STOP                                                                    \

/* To be called before each instancing loop */
#define INDEXRESET() (modCnt = 0, indOffset = startIndOffset)

/* Gets the current index */
#define INDEXGET()                                                          \
    ( (indOffset << shiftMask2[modCnt]) + indexArray[indOffset << shiftMask[modCnt]] )

/* Increment after each vertex */
#define INDEXINC()                          \
    ( indOffset += vertInc[modCnt],         \
      modCnt = 3&(cntGen >> (modCnt << 1))) \

/* Reversal only affects tristrips and their counter is
 * constant at zero, so it's simple */
#define STRIPREVERSE(_reverse)   ( indOffset -= (_reverse) )

/* Used as RpMeshPS2AllTestNumVerts (function in debug) */
#define RpMeshPS2AllTestNumVertsMacro(_ps2AllPipeData)                                                  \
MACRO_START                                                                                             \
{                                                                                                       \
    RxPS2AllPipeData *_p2apd  = (_ps2AllPipeData);                                                      \
    rwPS2AllResEntryHeader *_rshd;                                                                      \
    RwUInt32 _nvrt;                                                                                     \
                                                                                                        \
    PS2ALLMACROASSERT(NULL != _p2apd->cacheEntryRef);                                                   \
    PS2ALLMACROASSERT(NULL != *(_p2apd->cacheEntryRef));                                                \
    _rshd = RWPS2ALLRESENTRYHEADERFROMRESENTRY(*(_p2apd->cacheEntryRef));                               \
                                                                                                        \
    RPMESHPS2ALLCALCNUMVERTS(_p2apd, &_nvrt);                                                           \
    if (_nvrt != _rshd->numVerts)                                                                       \
    {                                                                                                   \
        /* NumVerts changing changes the size of the resEntry */                                        \
        _p2apd->meshInstance = (RxInstanceFlags)                                                        \
             (_p2apd->meshInstance | rxINSTANCEFULLINSTANCE);                                           \
        REDEBUGPrintf(("numVerts change caused full reinstance: %d\n", _nvrt));                         \
    }                                                                                                   \
}                                                                                                       \
MACRO_STOP

#define RPMESHPS2ALLMAKEMESHID(_meshHeader)             ((RwUInt32)(_meshHeader)->flags)
#define RPMESHPS2ALLMESHIDGETFLAGS(_meshID)             ((RwUInt32)(_meshID))

/* Used as RpMeshPS2AllTestMeshID (function in debug) */
#define RpMeshPS2AllTestMeshIDMacro(_ps2AllPipeData)                                                    \
MACRO_START                                                                                             \
{                                                                                                       \
    RxPS2AllPipeData *_p2apd  = (_ps2AllPipeData);                                                      \
    rwPS2AllResEntryHeader *_rshd;                                                                      \
                                                                                                        \
    PS2ALLMACROASSERT(NULL != _p2apd->cacheEntryRef);                                                   \
    PS2ALLMACROASSERT(NULL != *(_p2apd->cacheEntryRef));                                                \
    _rshd = RWPS2ALLRESENTRYHEADERFROMRESENTRY(*(_p2apd->cacheEntryRef));                               \
                                                                                                        \
    _p2apd->meshIdentifier = RPMESHPS2ALLMAKEMESHID(_p2apd->meshHeader);                                \
    if (_p2apd->meshIdentifier != _rshd->meshIdentifier)                                                \
    {                                                                                                   \
        /* This (meshHeader flags changing) causes a full reinstance of this mesh */                    \
        _p2apd->meshInstance = (RxInstanceFlags)                                                        \
            (_p2apd->meshInstance | rxINSTANCEFULLINSTANCE);                                            \
        REDEBUGPrintf(("meshIdentifier change caused full reinstance: (%x)\n",                          \
                       _p2apd->meshIdentifier));                                                        \
    }                                                                                                   \
}                                                                                                       \
MACRO_STOP


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

/* Callback components, for use in the MeshInstanceTestCB */
extern void RpMeshPS2AllTestNumVertsFunc(
    RxPS2AllPipeData *ps2AllPipeData);
extern void RpMeshPS2AllTestMeshIDFunc(
    RxPS2AllPipeData *ps2AllPipeData);
#if (defined(RWDEBUG))
#define RpMeshPS2AllTestNumVerts                RpMeshPS2AllTestNumVertsFunc
#define RpMeshPS2AllTestMeshID                  RpMeshPS2AllTestMeshIDFunc
#else /* (defined(RWDEBUG)) */
#define RpMeshPS2AllTestNumVerts                RpMeshPS2AllTestNumVertsMacro
#define RpMeshPS2AllTestMeshID                  RpMeshPS2AllTestMeshIDMacro
#endif /* (defined(RWDEBUG)) */


#ifdef    __cplusplus
}
#endif /* __cplusplus */



/*--- Automatically derived from: pipe/p2/sky2/objallinone.h ---*/

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


#ifdef    __cplusplus
}
#endif /* __cplusplus */



/*--- Automatically derived from: pipe/p2/sky2/nodeps2matinstance.h ---*/

/* LEGACY-SUPPORT macro (old name was non-standard) */
#define RxPipelineNodePS2MatInstanceNodeSetVUBufferSizes(_self,      \
                                      _stride, _TSCount, _TLCount)   \
    (RxPipelineNodePS2MatInstanceSetVUBufferSizes(_self, _stride,    \
                                                 _TSCount, _TLCount))

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

extern RxNodeDefinition *
RxNodeDefinitionGetPS2MatInstance(void);

/* instance node's "construction time customisation" api;
   following call is available between time node
   is add()ed to pipeline and time pipeline is unlock()ed */

extern RxPipelineNode *
RxPipelineNodePS2MatInstanceGenerateCluster(RxPipelineNode * self,
                                            RxClusterDefinition * cluster2generate,
                                            RwUInt32 type);


#define RxPipelineNodePS2MatInstanceSetVUBufferSizes(_self,                     \
                                                     _strideOfInputCluster,     \
                                                     _vuTSVertexMaxCount,       \
                                                     _vuTLTriMaxCount)          \
        RxPS2MatInstanceSetVUBufferSizes(_self,                                 \
                                         _strideOfInputCluster,                 \
                                         _vuTSVertexMaxCount,                   \
                                         _vuTLTriMaxCount)  

extern RxPipelineNode *
RxPipelineNodePS2MatInstanceSetVUBufferSizes(RxPipelineNode * self,
                                             RwInt32 strideOfInputCluster,
                                             RwInt32 vuTSVertexMaxCount,
                                             RwInt32 vuTLTriMaxCount);

#define RxPipelineNodePS2MatInstanceSetPointListVUBufferSize(_self,                     \
                                                             _strideOfInputCluster,     \
                                                             _vuPLVertexMaxCount)       \
        RxPS2MatInstanceSetPointListVUBufferSize(_self,                                 \
                                                 _strideOfInputCluster,                 \
                                                 _vuPLVertexMaxCount)

extern RxPipelineNode *
RxPipelineNodePS2MatInstanceSetPointListVUBufferSize(RxPipelineNode * self, 
                                                     RwInt32 strideOfInputCluster,
                                                     RwInt32 vuPLVertexMaxCount);


#ifdef    __cplusplus
}
#endif                          /* __cplusplus */


/*--- Automatically derived from: pipe/p2/sky2/nodeps2matbridge.h ---*/

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

extern RxNodeDefinition *
RxNodeDefinitionGetPS2MatBridge(void);

/* These are for use after RxPipelineUnlock() */

extern RxPipelineNode *
RxPipelineNodePS2MatBridgeSetVU1CodeArray(RxPipelineNode * self,
                                          void **VU1CodeArray);

extern const void **
RxPipelineNodePS2MatBridgeGetVU1CodeArray(RxPipelineNode *self);

extern RxPipelineNode *
RxPipelineNodePS2MatBridgeSetVIFOffset(RxPipelineNode * self,
                                       int vifOffset);

extern RxPipelineNode *
RxPipelineNodePS2MatBridgeNoTexture(RxPipelineNode * self,
                                    RwBool noTexture);

/* LEGACY-SUPPORT macros for old API func names */

#define RxNodePS2MatBridgeGetVU1CodeArray \
        RxPipelineNodePS2MatBridgeGetVU1CodeArray

#define RxNodePS2MatBridgeSetVU1CodeArray \
        RxPipelineNodePS2MatBridgeSetVU1CodeArray

#define RxNodePS2MatBridgeSetVIFOffset \
        RxPipelineNodePS2MatBridgeSetVIFOffset

#define RxNodePS2MatBridgeNoTexture \
        RxPipelineNodePS2MatBridgeNoTexture

#define RxBridgeNodeSetVIFOffset(_self, _vifOffset)       \
        RxPipelineNodePS2MatBridgeSetVIFOffset(_self, _vifOffset)

#define RxBridgeNodeSetVU1CodeArray(_self, _VU1CodeArray) \
        RxPipelineNodePS2MatBridgeSetVU1CodeArray(_self, _VU1CodeArray)

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */


/*--- Automatically derived from: pipe/p2/sky2/nodeps2manager.h ---*/

/**
 * \ingroup rpworldp2sky2
 * \ref RxPipelineNodePS2ManagerInstanceCallBack is the callback to be called,
 * for the owning PS2Manager pipeline node, after standard instancing
 * has occurred. Within this callback, code may instance data for user
 * clusters and setup other DMA data (such as a second texture to upload
 * for use in environment mapping).
 *
 * This callback will receive pointers to cluster data for all clusters
 * (requested through \ref RxPipelineNodePS2ManagerGenerateCluster) which
 * have CL_ATTRIB_READ or CL_ATTRIB_WRITE attributes. This is guaranteed
 * to include, in addition to user-generated clusters, the \ref RxPS2Mesh
 * cluster (placed first in the array) and the \ref RxPS2DMASessionRecord
 * cluster (placed second in the array). Even if there are no other
 * user-generated clusters with CL_ATTRIB_READ or CL_ATTRIB_WRITE
 * attributes, the callback is still called.
 *
 * If the callback returns FALSE then the current mesh will not be
 * rendered. The rest of the object's meshes will be processed as normal.
 *
 * \param  clusterData   An array of pointers to the data of
 * clusters with CL_ATTRIB_READ or CL_ATTRIB_WRITE attributes.
 * \param  numClusters   A count of the number of pointers
 * in the clusterData array. This value is guaranteed to be at least two.
 *
 * \return TRUE to continue rendering, FALSE to skip rendering this mesh.
 *
 * \see RxPipelineNodePS2ManagerSetInstanceCallBack
 * \see RxPipelineNodePS2ManagerSetPostObjectCallBack
 * \see RxPipelineNodePS2ManagerGenerateCluster
 */
typedef RwBool (*RxPipelineNodePS2ManagerInstanceCallBack) (void **clusterData,
                                                            RwUInt32 numClusters);

/* LEGACY-SUPPORT define for old typedef name */
#define RxNodePS2ManagerInstanceCallBack RxPipelineNodePS2ManagerInstanceCallBack


/**
 * \ingroup rpworldp2sky2
 * \ref RxPipelineNodePS2ManagerPostObjectCallBack is the callback to be
 * called, for the owning PS2Manager pipeline node, after all meshes in an
 * object have been processed (remember that PS2Manager is used in object
 * pipelines, not material pipelines), such that cleanup may be performed
 * at the end of the object's pipeline execution (without having to
 * interfere with the object's render callback).
 *
 * This callback will receive a pointer to the data of the
 * \ref RxPS2DMASessionRecord cluster.
 *
 * The callback should return FALSE to indicate an error.
 *
 * \param  dmaSesRec   a pointer to the data of the
 * \ref RxPS2DMASessionRecord cluster
 *
 * \return TRUE on success, FALSE otherwise
 *
 * \see RxPipelineNodePS2ManagerSetInstanceCallBack
 * \see RxPipelineNodePS2ManagerSetPostObjectCallBack
 * \see RxPipelineNodePS2ManagerGenerateCluster
 */
typedef RwBool (*RxPipelineNodePS2ManagerPostObjectCallBack) (RxPS2DMASessionRecord *dmaSesRec);

/* LEGACY-SUPPORT define for old typedef name */
#define RxNodePS2ManagerPostObjectCallBack RxPipelineNodePS2ManagerPostObjectCallBack


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

extern RxNodeDefinition *RxNodeDefinitionGetPS2Manager(RwInt32 objType);

extern void
RxPipelineNodePS2ManagerSetLighting(RxPipelineNode *self,
                                    RxWorldLightingCallBack newLightingFunc);
extern RxPipelineNode *
RxPipelineNodePS2ManagerSetVUBufferSizes(RxPipelineNode *self,
                                         RwInt32 strideOfInputCluster,
                                         RwInt32 vuTSVertexMaxCount,
                                         RwInt32 vuTLTriMaxCount);
extern RxPipelineNode *
RxPipelineNodePS2ManagerSetPointListVUBufferSize(RxPipelineNode *self,
                                                 RwInt32 strideOfInputCluster,
                                                 RwInt32 vuPLVertexMaxCount);


extern RxPipelineNode *
RxPipelineNodePS2ManagerGenerateCluster(RxPipelineNode      *self,
                                        RxClusterDefinition *cluster2generate,
                                        RwUInt32             type);

extern RwInt32
RxPipelineNodePS2ManagerGetVUBatchSize(RxPipelineNode *self,
                                       RpMeshHeaderFlags flags);

extern RxPipelineNode *
RxPipelineNodePS2ManagerSetVU1CodeArray(RxPipelineNode *self,
                                        void **VU1CodeArray);

extern const void **
RxPipelineNodePS2ManagerGetVU1CodeArray(RxPipelineNode *self);

extern RxPipelineNode *
RxPipelineNodePS2ManagerSetVIFOffset(RxPipelineNode *self,
                                     int vifOffset);

extern RxPipelineNode *
RxPipelineNodePS2ManagerNoTexture(RxPipelineNode * self,
                                  RwBool noTexture);

/* Allow instancing of user data, and misc other DMA setup, to
 * occur within PS2Manager after the (embedded) matInstance stage */
extern RxPipelineNode *
RxPipelineNodePS2ManagerSetInstanceCallBack(
    RxPipelineNode *node,
    RxPipelineNodePS2ManagerInstanceCallBack callBack);

/* Allow post-object cleanup without interfering with the render callback */
extern RxPipelineNode *
RxPipelineNodePS2ManagerSetPostObjectCallBack(
    RxPipelineNode *self,
    RxPipelineNodePS2ManagerPostObjectCallBack callBack);

#ifdef    __cplusplus
}
#endif /* __cplusplus */


/*--- Automatically derived from: pipe/p2/bapipew.h ---*/

#if (!defined(RXPIPELINE))
#define RXPIPELINE
#endif /* (!defined(RXPIPELINE)) */

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

extern RxPipeline    *RpWorldGetGenericSectorInstancePipeline(void);
extern RxPipeline    *RpWorldSetDefaultSectorInstancePipeline(RxPipeline *pipeline);
extern RxPipeline    *RpWorldGetDefaultSectorInstancePipeline(void);
extern RpWorld       *RpWorldSetSectorInstancePipeline(RpWorld *world,        RxPipeline  *pipeline);
extern RpWorld       *RpWorldGetSectorInstancePipeline(RpWorld *world,        RxPipeline **pipeline);
extern RpWorldSector *RpWorldSectorSetInstancePipeline(RpWorldSector *sector, RxPipeline  *pipeline);
extern RpWorldSector *RpWorldSectorGetInstancePipeline(RpWorldSector *sector, RxPipeline **pipeline);

extern RxPipeline    *RpAtomicGetGenericInstancePipeline(void);
extern RxPipeline    *RpAtomicGetDefaultInstancePipeline(void);
extern RxPipeline    *RpAtomicSetDefaultInstancePipeline(RxPipeline *pipeline);
extern RpAtomic      *RpAtomicSetInstancePipeline(RpAtomic *atomic, RxPipeline  *pipeline);
extern const RpAtomic      *RpAtomicGetInstancePipeline(const RpAtomic * const atomic, 
                                                  RxPipeline **pipeline);

extern RxPipeline    *RpMaterialGetGenericRenderPipeline(void);
extern RxPipeline    *RpMaterialSetDefaultRenderPipeline(RxPipeline *pipeline);
extern RxPipeline    *RpMaterialGetDefaultRenderPipeline(void);
extern RpMaterial    *RpMaterialSetRenderPipeline(RpMaterial *material, RxPipeline  *pipeline);
extern RpMaterial    *RpMaterialGetRenderPipeline(RpMaterial *material, RxPipeline **pipeline);

extern const RpGeometry *RpGeometryIsCorrectlySorted(const RpGeometry * geometry,
                                                     RwBool * result);
extern RpGeometry  *RpGeometrySortByMaterial(const RpGeometry * geometry,
                                             RpGeometrySortByMaterialCallBack  callback);

#ifdef    __cplusplus
}
#endif /* __cplusplus */


/*--- Automatically derived from: ./baworobj.h ---*/
/****************************************************************************
 Global types
 */

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

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

/* Adding and removing cameras to/from the world */
extern RpWorld *RpWorldRemoveCamera(RpWorld *world, RwCamera *camera);
extern RpWorld *RpWorldAddCamera(RpWorld *world, RwCamera *camera);
extern RpWorld *RwCameraGetWorld(const RwCamera *camera);

/* Adding and removing atomics to/from the world */
extern RpWorld *RpWorldRemoveAtomic(RpWorld *world, RpAtomic *atomic);
extern RpWorld *RpWorldAddAtomic(RpWorld *world, RpAtomic *atomic);
extern RpWorld *RpAtomicGetWorld(const RpAtomic *atomic);

/* Adding and removing clumps to/from the world */
extern RpWorld *RpWorldAddClump(RpWorld *world, RpClump *clump);
extern RpWorld *RpWorldRemoveClump(RpWorld *world, RpClump *clump);
extern RpWorld *RpClumpGetWorld(const RpClump *clump);

/* Adding and removing lights to/from the world */
extern RpWorld *RpWorldAddLight(RpWorld *world, RpLight *light);
extern RpWorld *RpWorldRemoveLight(RpWorld *world, RpLight *light);
extern RpWorld *RpLightGetWorld(const RpLight *light);

/* Finding whats in the view frustum */
extern RwCamera *RwCameraForAllClumpsInFrustum(RwCamera *camera, void *data);
extern RwCamera *RwCameraForAllClumpsNotInFrustum(RwCamera *camera,
                                                    RwInt32 numClumps, void *data);
extern RwCamera *RwCameraForAllSectorsInFrustum(RwCamera *camera,
                                                RpWorldSectorCallBack callBack,
                                                void *pData);

/* Enumeration involving the world sectors */
extern RpLight *RpLightForAllWorldSectors(RpLight *light,
                                          RpWorldSectorCallBack callback,
                                          void *data);
extern RpAtomic *RpAtomicForAllWorldSectors(RpAtomic *atomic,
                                            RpWorldSectorCallBack callback,
                                            void *data);
extern RpWorldSector *RpWorldSectorForAllAtomics(RpWorldSector *sector,
                                                 RpAtomicCallBack callback,
                                                 void *data);
extern RpWorldSector *RpWorldSectorForAllCollisionAtomics(RpWorldSector *sector,
                                                 RpAtomicCallBack callback,
                                                 void *data);
extern RpWorldSector *RpWorldSectorForAllLights(RpWorldSector *sector,
                                                RpLightCallBack callback,
                                                void *data);

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */


/*--- Automatically derived from: ./babinwor.h ---*/
/****************************************************************************
 Global types
 */

/* Binary Representation
 *
 */
typedef struct RpWorldChunkInfoSector RpWorldSectorChunkInfo;
typedef struct RpWorldChunkInfoSector _rpWorldSector;

struct RpWorldChunkInfoSector
{
    RwInt32 matListWindowBase;
    RwInt32 numPolygons;
    RwInt32 numVertices;
    RwV3d inf;
    RwV3d sup;
    RwBool collSectorPresent;
    RwBool unused;
};

typedef struct RpPlaneSectorChunkInfo RpPlaneSectorChunkInfo;
typedef struct RpPlaneSectorChunkInfo _rpPlaneSector;

struct RpPlaneSectorChunkInfo
{
    RwInt32 type;
    RwReal value;    
    RwBool leftIsWorldSector;
    RwBool rightIsWorldSector;
    RwReal leftValue;
    RwReal rightValue;
};

typedef struct RpWorldChunkInfo RpWorldChunkInfo;
typedef struct RpWorldChunkInfo _rpWorld;

struct RpWorldChunkInfo
{
    RwBool rootIsWorldSector;

    RwV3d invWorldOrigin;

    RwSurfaceProperties surfaceProps;

    RwInt32 numPolygons;
    RwInt32 numVertices;
    RwInt32 numPlaneSectors;
    RwInt32 numWorldSectors;
    RwInt32 colSectorSize;    

    RwInt32 flags;  /* Flags about the world */
};

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

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

/* Binary format */
extern RwUInt32 RpWorldStreamGetSize(const RpWorld *world);
extern RpWorld *RpWorldStreamRead(RwStream *stream);
extern const RpWorld *RpWorldStreamWrite(const RpWorld *world,
                                         RwStream *stream);
extern RpWorldSectorChunkInfo *
RpWorldSectorChunkInfoRead(RwStream *stream,
                           RpWorldSectorChunkInfo *worldSectorChunkInfo,
                           RwInt32 *bytesRead);
extern RpPlaneSectorChunkInfo *
RpPlaneSectorChunkInfoRead(RwStream *stream,
                           RpPlaneSectorChunkInfo *planeSectorChunkInfo,
                           RwInt32 *bytesRead);
extern RpWorldChunkInfo *
RpWorldChunkInfoRead(RwStream *stream,
                     RpWorldChunkInfo *worldChunkInfo,
                     RwInt32 *bytesRead);

#ifdef    __cplusplus
}
#endif                          /* __cplusplus */

#endif /* RPWORLD_H */
