typedef struct rpAtomicPS2AllLightData rpAtomicPS2AllLightData; #if (!defined(DOXYGEN)) struct rpAtomicPS2AllLightData { RwSurfaceProperties *surface; /**< Internal Use */ RwMatrix invMat; /**< Internal Use */ RwReal invScale; /**< Internal Use */ RwReal recipInvScale; /**< Internal Use */ }; #endif /* (!defined(DOXYGEN)) */ #define RPATOMICPS2ALLMAKEOBJID(meshHeader, geom) \ (((RwUInt16)((meshHeader)->serialNum)) | \ (((RwUInt8)(RpGeometryGetFlags(geom) & ATOMICRENDERTYPEMASK)) << 16) | \ (((RwUInt8)((geom)->numMorphTargets)) << 24)) #define RPATOMICPS2ALLOBJIDGETSERIALNUM(_objID) ((RwUInt16)(_objID)) #define RPATOMICPS2ALLOBJIDGETFLAGS(_objID) ((RwUInt8)((_objID) >> 16)) #define RPATOMICPS2ALLOBJIDGETNUMMORPHTARGETS(_objID) ((RwUInt8)((_objID) >> 24)) /* Used as RpAtomicGetMeshHeaderMeshCache (function in debug) */ #define RpAtomicPS2AllGetMeshHeaderMeshCacheMacro(_atomic, _ps2AllPipeData) \ MACRO_START \ { \ RxPS2AllPipeData *_p2apd = (_ps2AllPipeData); \ RpAtomic *_atmc = (_atomic); \ RpGeometry *_gmty = RpAtomicGetGeometry(_atmc); \ \ PS2ALLMACROASSERT(NULL != _p2apd); \ PS2ALLMACROASSERT(!RPWORLDSECTORVERIFY(_p2apd->sourceObject)); \ PS2ALLMACROASSERT(NULL != _atmc); \ PS2ALLMACROASSERT(_atmc == (RpAtomic *)(_p2apd->sourceObject)); \ PS2ALLMACROASSERT(NULL != _gmty); \ \ _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 \ { \ RpAtomic *_atmc = (_atomic); \ RpGeometry *_gmty; \ \ PS2ALLMACROASSERT(NULL != _atmc); \ PS2ALLMACROASSERT(!RPWORLDSECTORVERIFY(_atmc)); \ _gmty = RpAtomicGetGeometry(_atmc); \ PS2ALLMACROASSERT(NULL != _gmty); \ \ /* 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); \ \ PS2ALLMACROASSERT(NULL != _p2apd); \ PS2ALLMACROASSERT(!RPWORLDSECTORVERIFY(_p2apd->sourceObject)); \ PS2ALLMACROASSERT(_atmc == (RpAtomic *)(_p2apd->sourceObject)); \ \ _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); \ \ PS2ALLMACROASSERT(NULL != _p2apd); \ PS2ALLMACROASSERT(!RPWORLDSECTORVERIFY(_p2apd->sourceObject)); \ PS2ALLMACROASSERT(NULL != _atmc); \ PS2ALLMACROASSERT(_atmc == (RpAtomic *)(_p2apd->sourceObject)); \ \ if ( !(rpGEOMETRYNATIVE & RpGeometryGetFlags(_gmty)) ) \ { \ 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((rpGEOMETRYLOCKPRELIGHT << 3) == rxINSTANCERGBA); \ PS2ALLMACROASSERT((rpGEOMETRYLOCKTEXCOORDS << 3) == rxINSTANCEUV); \ PS2ALLMACROASSERT((rpGEOMETRYLOCKTEXCOORDS1 << 3) == rxINSTANCEUV1); \ PS2ALLMACROASSERT((rpGEOMETRYLOCKTEXCOORDS2 << 3) == rxINSTANCEUV2); \ PS2ALLMACROASSERT((rpGEOMETRYLOCKTEXCOORDS3 << 3) == rxINSTANCEUV3); \ PS2ALLMACROASSERT((rpGEOMETRYLOCKTEXCOORDS4 << 3) == rxINSTANCEUV4); \ PS2ALLMACROASSERT((rpGEOMETRYLOCKTEXCOORDS5 << 3) == rxINSTANCEUV5); \ PS2ALLMACROASSERT((rpGEOMETRYLOCKTEXCOORDS6 << 3) == rxINSTANCEUV6); \ PS2ALLMACROASSERT((rpGEOMETRYLOCKTEXCOORDS7 << 3) == rxINSTANCEUV7); \ PS2ALLMACROASSERT((rpGEOMETRYLOCKTEXCOORDS8 << 3) == rxINSTANCEUV8); \ } \ } \ \ 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 RpAtomicPS2AllClear (function in debug) */ #define RpAtomicPS2AllClearMacro(_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; \ RpInterpolator *_iplr; \ \ PS2ALLMACROASSERT(NULL != _atmc); \ PS2ALLMACROASSERT(!RPWORLDSECTORVERIFY(_atmc)); \ _gmty = RpAtomicGetGeometry(_atmc); \ PS2ALLMACROASSERT(NULL != _gmty); \ _iplr = RpAtomicGetInterpolator(_atmc); \ PS2ALLMACROASSERT(NULL != _iplr); \ \ PS2ALLMACROASSERT(NULL != _gmty); \ PS2ALLMACROASSERT(NULL != _iplr); \ \ _gmty->lockedSinceLastInst = 0; \ _iplr->flags &= ~rpINTERPOLATORDIRTYINSTANCE; \ } \ MACRO_STOP /* Used as RpAtomicPS2AllTransformSetup (function in debug) */ #define RpAtomicPS2AllTransformSetupMacro(_atomic, _transform) \ MACRO_START \ { \ RpAtomic *_atmc = (_atomic); \ RwMatrix **_tnfm = (_transform); \ \ RwMatrix * const _viewMatrix = \ &(((RwCamera *)RWSRCGLOBAL(curCamera))->viewMatrix); \ RwMatrix * _mpLocalToWorld; \ \ PS2ALLMACROASSERT(NULL != _atmc); \ PS2ALLMACROASSERT(!RPWORLDSECTORVERIFY(_atmc)); \ _mpLocalToWorld = RwFrameGetLTM((RwFrame *)rwObjectGetParent(_atmc)); \ PS2ALLMACROASSERT(NULL != _mpLocalToWorld); \ PS2ALLMACROASSERT(NULL != _tnfm); \ \ 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; \ \ PS2ALLMACROASSERT(NULL != _atmc); \ PS2ALLMACROASSERT(!RPWORLDSECTORVERIFY(_atmc)); \ PS2ALLMACROASSERT(NULL != _infm); \ \ /* 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 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 */ \ \ PS2ALLMACROASSERT(NULL != _p2apd); \ \ if ((_p2apd->meshHeader->flags & rpMESHHEADERTRISTRIP) == rpMESHHEADERTRISTRIP) \ { \ /* GS manual p113/114 - triStrip */ \ _p2apd->primType = 4; \ _p2apd->transType = skyTransType /*| rxSKYTRANSTYPELIST | rxSKYTRANSTYPELINE*/; \ } \ else if (((_p2apd->meshHeader->flags & rpMESHHEADERPRIMMASK) == 0) /* trilist */ || \ ((_p2apd->meshHeader->flags & rpMESHHEADERTRIFAN ) == rpMESHHEADERTRIFAN) ) \ { \ /* TriFans instance into triLists. GS manual p113/114 - triList */ \ _p2apd->primType = 3; \ _p2apd->transType = skyTransType | rxSKYTRANSTYPELIST /*| rxSKYTRANSTYPELINE*/; \ } \ else if ((_p2apd->meshHeader->flags & rpMESHHEADERPOINTLIST) == rpMESHHEADERPOINTLIST) \ { \ /* We can't guess what primitive type you'll submit, so we choose tri-strip arbitrarily */ \ _p2apd->primType = 4; \ _p2apd->transType = skyTransType /*| rxSKYTRANSTYPELIST | rxSKYTRANSTYPELINE*/; \ } \ else if ((_p2apd->meshHeader->flags & rpMESHHEADERPOLYLINE) == rpMESHHEADERPOLYLINE) \ { \ /* PolyLines remain as PolyLines with the G3 pipes! Woohoo! GS manual p113/114 - lineStrip */ \ _p2apd->primType = 2; \ _p2apd->transType = skyTransType /*| rxSKYTRANSTYPESTRIP*/ | rxSKYTRANSTYPELINE; \ } \ else /* ((_p2apd->meshHeader->flags & rpMESHHEADERLINELIST) == rpMESHHEADERLINELIST) */ \ { \ /* GS manual p113/114 - lineList */ \ _p2apd->primType = 1; \ _p2apd->transType = skyTransType | rxSKYTRANSTYPELIST | rxSKYTRANSTYPELINE; \ } \ if (_infm != rwSPHEREINSIDE) \ { \ /* We need to clip :-( */ \ _p2apd->transType |= rxSKYTRANSTYPECLIP; \ /* NOTE: The tri-strip true-clipper now submits strips to the GS */ \ /* through the power of degenerates! (and ADC, I think) */ \ } \ } \ 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) \ MACRO_START \ { \ RxPS2AllPipeData *_p2apd = (_ps2AllPipeData); \ RpAtomic *_atmc; \ RpGeometry *_gmty; \ \ PS2ALLMACROASSERT(NULL != _p2apd); \ _atmc = (RpAtomic *)_p2apd->sourceObject; \ PS2ALLMACROASSERT(NULL != _atmc); \ PS2ALLMACROASSERT(!RPWORLDSECTORVERIFY(_atmc)); \ _gmty = RpAtomicGetGeometry(_atmc); \ PS2ALLMACROASSERT(NULL != _gmty); \ \ if (rpGEOMETRYLIGHT & RpGeometryGetFlags(_gmty)) \ { \ 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 */ \ RwMatrixInvert(&lightingData.invMat, frameMat); \ \ if ((rwMatrixGetFlags(frameMat) & rwMATRIXTYPEMASK) == rwMATRIXTYPEORTHONORMAL) \ { \ lightingData.invScale = 1.0f; \ lightingData.recipInvScale = 1.0f; \ } \ else \ { \ RwReal temp; \ temp = RwV3dDotProduct(&lightingData.invMat.at, &lightingData.invMat.at); \ rwSqrtInvSqrtMacro(&(lightingData.invScale), &(lightingData.recipInvScale), temp); \ } \ \ /*lightingData.surface = &atomic->geometry->surfaceProps;*/ \ /* temporary hack to get the surface properties from the first mesh */ \ meshHeader = _gmty->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); \ RwLLLink *curLight, *endLight; \ \ /* Lights in the sector */ \ curLight = rwLinkListGetFirstLLLink(&tpTie->worldSector->lightsInWorldSector); \ endLight = rwLinkListGetTerminator(&tpTie->worldSector->lightsInWorldSector); \ \ while (curLight != endLight) \ { \ RpLightTie *lightTie; \ \ lightTie = rwLLLinkGetData(curLight, RpLightTie, lightInWorldSector); \ \ /* NB lightTie may actually be a dummyTie from a enclosing ForAll */ \ \ /* Check to see if the light has already been applied and is set to */ \ /* light atomics */ \ \ if (lightTie->light && \ (lightTie->light->lightFrame != RWSRCGLOBAL(lightFrame)) && \ (rwObjectTestFlags(lightTie->light, rpLIGHTLIGHTATOMICS))) \ { \ const RwMatrix *matrixLight; \ const RwV3d *pos; \ const RwSphere *sphere; \ RwV3d distanceVector; \ RwReal distanceSquare; \ RwReal distanceCollision; \ \ /* don't light this atomic with the same light again! */ \ lightTie->light->lightFrame = RWSRCGLOBAL(lightFrame); \ \ /* Does the light intersect the atomics bounding sphere */ \ matrixLight = RwFrameGetLTM(RpLightGetFrame(lightTie->light)); \ \ pos = &(matrixLight->pos); \ \ sphere = RpAtomicGetWorldBoundingSphere(_atmc); \ \ RwV3dSub(&distanceVector, &(sphere->center), pos); \ \ distanceSquare = RwV3dDotProduct(&distanceVector, &distanceVector); \ \ distanceCollision = (sphere->radius + RpLightGetRadius(lightTie->light)); \ \ if (distanceSquare < (distanceCollision * distanceCollision)) \ { \ _rpAtomicPS2AllDoApplyLight(lightTie->light, &lightingData); \ } \ } \ \ /* Next */ \ curLight = rwLLLinkGetNext(curLight); \ } \ \ /* Next one */ \ cur = rwLLLinkGetNext(cur); \ } \ } \ } \ MACRO_STOP /* Used as RpAtomicPS2AllLightingPersist (function in debug) */ #define RpAtomicPS2AllLightingPersistMacro(_inverse, _invScale, _recipInvScale) \ MACRO_START \ { \ RwMatrix *_invs = (_inverse); \ RwReal _insl = _invScale; \ RwReal _rnsl = _recipInvScale; \ \ /* Make sure they're not doing lighting *and* calling this! */ \ PS2ALLMACROASSERT(0 == _rwSkyLightQWordsWritten); \ \ /* This being a macro, this'll boil away to an unconditional single clause */ \ if (NULL != _invs) \ { \ /* We're letting lights persist and updating the inverse lighting matrix */ \ *_rwSkyLightFillPos++ = _invs->right.x; \ *_rwSkyLightFillPos++ = _invs->right.y; \ *_rwSkyLightFillPos++ = _invs->right.z; \ *_rwSkyLightFillPos++ = _insl; \ *_rwSkyLightFillPos++ = _invs->up.x; \ *_rwSkyLightFillPos++ = _invs->up.y; \ *_rwSkyLightFillPos++ = _invs->up.z; \ *_rwSkyLightFillPos++ = _insl; \ *_rwSkyLightFillPos++ = _invs->at.x; \ *_rwSkyLightFillPos++ = _invs->at.y; \ *_rwSkyLightFillPos++ = _invs->at.z; \ *_rwSkyLightFillPos++ = _insl; \ *_rwSkyLightFillPos++ = _invs->pos.x; \ *_rwSkyLightFillPos++ = _invs->pos.y; \ *_rwSkyLightFillPos++ = _invs->pos.z; \ *_rwSkyLightFillPos++ = _rnsl; \ _rwSkyLightQWordsWritten = (RwUInt32)(-5); \ } \ else \ { \ /* We're letting both lights and the inverse lighting matrix persist */ \ _rwSkyLightQWordsWritten = (RwUInt32)(-1); \ } \ } \ MACRO_STOP /* Used as RpMeshPS2AllGatherMeshMetrics (function in debug) */ #if (defined(RWMETRICS)) #define RpMeshPS2AllGatherMeshMetricsMacro(_ps2AllPipeData) \ MACRO_START \ { \ RxPS2AllPipeData *_p2apd = (_ps2AllPipeData); \ \ PS2ALLMACROASSERT(NULL != _p2apd); \ \ /* 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); \ \ PS2ALLMACROASSERT(NULL != _p2apd); \ PS2ALLMACROASSERT(!RPWORLDSECTORVERIFY(_p2apd->sourceObject)); \ PS2ALLMACROASSERT(NULL != _rsny); \ \ _AtomicResAllocMorph() \ { \ RpGeometry *_gmty; \ \ _gmty = RpAtomicGetGeometry((RpAtomic *)(_p2apd->sourceObject)); \ PS2ALLMACROASSERT(NULL != _gmty); \ \ if ((rpGEOMETRYNATIVEINSTANCE & RpGeometryGetFlags(_gmty))) \ { \ /* Allocate the memory */ \ *_rsny = (RwResEntry *)RwMalloc(sizeof(RwResEntry) + _cyze); \ PS2ALLMACROASSERT(NULL != (*_rsny)); \ \ /* We have an entry */ \ (*_rsny)->link.next = (RwLLLink *)NULL; \ (*_rsny)->link.prev = (RwLLLink *)NULL; \ (*_rsny)->owner = (void *)_gmty; \ (*_rsny)->size = _cyze; \ (*_rsny)->ownerRef = _rsny; \ (*_rsny)->destroyNotify = _dycb; \ } \ else \ { \ /* Non-fastmorphing, non-persistent atomic */ \ *_rsny = RwResourcesAllocateResEntry(_gmty, _rsny, _cyze, _dycb); \ } \ } \ } \ MACRO_STOP #if (defined(__cplusplus)) extern "C" { #endif /* (defined(__cplusplus)) */ /* Default RW callbacks */ extern RwBool RpAtomicPS2AllObjectSetupCallBack( RxPS2AllPipeData *ps2AllPipeData, RwMatrix **transform); /* 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); /* Standard instance func for atomics */ extern 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 RpAtomicPS2AllClearFunc( RpAtomic *atomic); 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); extern void RpAtomicPS2AllLightingPersistFunc( RwMatrix *inverse, RwReal invScale, RwReal recipInvScale); /* ResEntryAllocCB */ extern void RpAtomicPS2AllResEntryAllocFunc( RxPS2AllPipeData *ps2AllPipeData, RwResEntry **repEntry, RwUInt32 size, RwResEntryDestroyNotify destroyCallBack); /* PostMeshCB */ extern void RpMeshPS2AllGatherMeshMetricsFunc( RxPS2AllPipeData *ps2AllPipeData); #if (defined(__cplusplus)) } #endif /* (defined(__cplusplus)) */ #if (defined(RWDEBUG)) #define RpAtomicPS2AllGetMeshHeaderMeshCache RpAtomicPS2AllGetMeshHeaderMeshCacheFunc #define RpAtomicPS2AllGatherObjMetrics RpAtomicPS2AllGatherObjMetricsFunc #define RpAtomicPS2AllMorphSetup RpAtomicPS2AllMorphSetupFunc #define RpAtomicPS2AllObjInstanceTest RpAtomicPS2AllObjInstanceTestFunc #define RpAtomicPS2AllClear RpAtomicPS2AllClearFunc #define RpAtomicPS2AllTransformSetup RpAtomicPS2AllTransformSetupFunc #define RpAtomicPS2AllFrustumTest RpAtomicPS2AllFrustumTestFunc #define RpAtomicPS2AllPrimTypeTransTypeSetup RpAtomicPS2AllPrimTypeTransTypeSetupFunc #define RpAtomicPS2AllMatModulateSetup RpAtomicPS2AllMatModulateSetupFunc #define RpAtomicPS2AllLightingSetup RpAtomicPS2AllLightingSetupFunc #define RpAtomicPS2AllLightingPersist RpAtomicPS2AllLightingPersistFunc #define RpAtomicPS2AllResEntryAlloc RpAtomicPS2AllResEntryAllocFunc #define RpMeshPS2AllGatherMeshMetrics RpMeshPS2AllGatherMeshMetricsFunc #else /* (defined(RWDEBUG)) */ #define RpAtomicPS2AllGetMeshHeaderMeshCache RpAtomicPS2AllGetMeshHeaderMeshCacheMacro #define RpAtomicPS2AllGatherObjMetrics RpAtomicPS2AllGatherObjMetricsMacro #define RpAtomicPS2AllMorphSetup RpAtomicPS2AllMorphSetupMacro #define RpAtomicPS2AllObjInstanceTest RpAtomicPS2AllObjInstanceTestMacro #define RpAtomicPS2AllClear RpAtomicPS2AllClearMacro #define RpAtomicPS2AllTransformSetup RpAtomicPS2AllTransformSetupMacro #define RpAtomicPS2AllFrustumTest RpAtomicPS2AllFrustumTestMacro #define RpAtomicPS2AllPrimTypeTransTypeSetup RpAtomicPS2AllPrimTypeTransTypeSetupMacro #define RpAtomicPS2AllMatModulateSetup RpAtomicPS2AllMatModulateSetupMacro #define RpAtomicPS2AllLightingSetup RpAtomicPS2AllLightingSetupMacro #define RpAtomicPS2AllLightingPersist RpAtomicPS2AllLightingPersistMacro #define RpAtomicPS2AllResEntryAlloc RpAtomicPS2AllResEntryAllocMacro #define RpMeshPS2AllGatherMeshMetrics RpMeshPS2AllGatherMeshMetricsMacro #endif /* (defined(RWDEBUG)) */