/* Instancing support structs */ #if (!defined(DOXYGEN)) 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 */ }; typedef struct rwPS2AllIndexLUTs rwPS2AllIndexLUTs; struct rwPS2AllIndexLUTs { RxVertexIndex fakeIndices[1]; /**< Internal Use */ struct _rwPS2AllNormalLUTs normal; /**< Internal Use */ struct _rwPS2AllTriFanLUTs triFan; /**< Internal Use */ }; #endif /* (!defined(DOXYGEN)) */ /* 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, stripReverse; \ 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 */ \ }; \ \ 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 \ { \ 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; \ } \ if ((_flags) & rpMESHHEADERTRISTRIP) \ { \ stripReverse = 2; \ } \ else if ((_flags) & rpMESHHEADERPOLYLINE) \ { \ stripReverse = 1; \ } \ else \ { \ stripReverse = 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))) \ /* Decrement the vertex counter before each batch */ #define VERTCOUNTERDEC(_vrtCnt, _j) ( (_vrtCnt) -= (_j - stripReverse) ) /* Reversal only affects tristrips and their * counter is constant at zero, so it's simple */ #define STRIPREVERSE() ( indOffset -= stripReverse ) /* 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 #if (defined(__cplusplus)) extern "C" { #endif /* (defined(__cplusplus)) */ /* Callback components, for use in the MeshInstanceTestCB */ extern void RpMeshPS2AllTestNumVertsFunc( RxPS2AllPipeData *ps2AllPipeData); extern void RpMeshPS2AllTestMeshIDFunc( RxPS2AllPipeData *ps2AllPipeData); #if (defined(__cplusplus)) } #endif /* (defined(__cplusplus)) */ #if (defined(RWDEBUG)) #define RpMeshPS2AllTestNumVerts RpMeshPS2AllTestNumVertsFunc #define RpMeshPS2AllTestMeshID RpMeshPS2AllTestMeshIDFunc #else /* (defined(RWDEBUG)) */ #define RpMeshPS2AllTestNumVerts RpMeshPS2AllTestNumVertsMacro #define RpMeshPS2AllTestMeshID RpMeshPS2AllTestMeshIDMacro #endif /* (defined(RWDEBUG)) */