summaryrefslogtreecommitdiffstats
path: root/src/rw
diff options
context:
space:
mode:
Diffstat (limited to 'src/rw')
-rw-r--r--src/rw/NodeName.cpp2
-rw-r--r--src/rw/RwHelper.cpp42
-rw-r--r--src/rw/RwHelper.h10
-rw-r--r--src/rw/RwMatFX.cpp113
-rw-r--r--src/rw/RwPS2AlphaTest.cpp247
-rw-r--r--src/rw/VisibilityPlugins.cpp4
-rw-r--r--src/rw/VisibilityPlugins.h6
7 files changed, 400 insertions, 24 deletions
diff --git a/src/rw/NodeName.cpp b/src/rw/NodeName.cpp
index d62884f7..ad4acffb 100644
--- a/src/rw/NodeName.cpp
+++ b/src/rw/NodeName.cpp
@@ -51,7 +51,7 @@ RwInt32
NodeNameStreamGetSize(const void *object, RwInt32 offsetInObject, RwInt32 sizeInObject)
{
// game checks for null pointer on node name extension but that really happen
- return rwstrlen(NODENAMEEXT(object));
+ return (RwInt32)rwstrlen(NODENAMEEXT(object));
}
bool
diff --git a/src/rw/RwHelper.cpp b/src/rw/RwHelper.cpp
index cd2a1bf6..f568532a 100644
--- a/src/rw/RwHelper.cpp
+++ b/src/rw/RwHelper.cpp
@@ -11,7 +11,11 @@
RtCharset *debugCharset;
#endif
-bool gPS2alphaTest = 1;
+#ifdef PS2_ALPHA_TEST
+bool gPS2alphaTest = true;
+#else
+bool gPS2alphaTest = false;
+#endif
#ifndef FINAL
static bool charsetOpen;
@@ -202,7 +206,7 @@ isSkinnedCb(RpAtomic *atomic, void *data)
RpAtomic **pAtomic = (RpAtomic**)data;
if(*pAtomic)
return nil; // already found one
- if(RpSkinGeometryGetSkin(atomic->geometry))
+ if(RpSkinGeometryGetSkin(RpAtomicGetGeometry(atomic)))
*pAtomic = atomic; // we could just return nil here directly...
return atomic;
}
@@ -611,3 +615,37 @@ CameraCreate(RwInt32 width, RwInt32 height, RwBool zBuffer)
WRAPPER void _TexturePoolsInitialise() { EAXJMP(0x598B10); }
WRAPPER void _TexturePoolsShutdown() { EAXJMP(0x598B30); }
#endif
+
+#if defined(FIX_BUGS) && defined(GTA_PC)
+RwUInt32 saved_alphafunc, saved_alpharef;
+
+void
+SetAlphaTest(RwUInt32 alpharef)
+{
+#ifdef LIBRW
+ saved_alphafunc = rw::GetRenderState(rw::ALPHATESTFUNC);
+ saved_alpharef = rw::GetRenderState(rw::ALPHATESTREF);
+
+ rw::SetRenderState(rw::ALPHATESTFUNC, rw::ALPHAGREATEREQUAL);
+ rw::SetRenderState(rw::ALPHATESTREF, 0);
+#else
+ RwD3D8GetRenderState(D3DRS_ALPHAFUNC, &saved_alphafunc);
+ RwD3D8GetRenderState(D3DRS_ALPHAREF, &saved_alpharef);
+
+ RwD3D8SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
+ RwD3D8SetRenderState(D3DRS_ALPHAREF, alpharef);
+#endif
+}
+
+void
+RestoreAlphaTest()
+{
+#ifdef LIBRW
+ rw::SetRenderState(rw::ALPHATESTFUNC, saved_alphafunc);
+ rw::SetRenderState(rw::ALPHATESTREF, saved_alpharef);
+#else
+ RwD3D8SetRenderState(D3DRS_ALPHAFUNC, saved_alphafunc);
+ RwD3D8SetRenderState(D3DRS_ALPHAREF, saved_alpharef);
+#endif
+}
+#endif \ No newline at end of file
diff --git a/src/rw/RwHelper.h b/src/rw/RwHelper.h
index a751ee39..eceaee07 100644
--- a/src/rw/RwHelper.h
+++ b/src/rw/RwHelper.h
@@ -52,4 +52,12 @@ RwCamera *CameraCreate(RwInt32 width,
void _TexturePoolsInitialise();
-void _TexturePoolsShutdown(); \ No newline at end of file
+void _TexturePoolsShutdown();
+
+#if defined(FIX_BUGS) && defined (GTA_PC)
+void SetAlphaTest(RwUInt32 alpharef);
+void RestoreAlphaTest();
+#else
+#define SetAlphaTest(a) (0)
+#define RestoreAlphaTest() (0)
+#endif \ No newline at end of file
diff --git a/src/rw/RwMatFX.cpp b/src/rw/RwMatFX.cpp
index 1e64c560..c8384b0f 100644
--- a/src/rw/RwMatFX.cpp
+++ b/src/rw/RwMatFX.cpp
@@ -2,9 +2,7 @@
#define WITHD3D
#include "common.h"
-#ifdef RWLIBS
-#include "patcher.h"
-#endif
+#include "rpmatfx.h"
struct MatFXNothing { int pad[5]; int effect; };
@@ -47,16 +45,16 @@ struct MatFX
int effects;
};
-#ifdef RWLIBS
extern "C" {
extern int MatFXMaterialDataOffset;
extern int MatFXAtomicDataOffset;
+
void _rpMatFXD3D8AtomicMatFXEnvRender(RxD3D8InstanceData* inst, int flags, int sel, RwTexture* texture, RwTexture* envMap);
+ void _rpMatFXD3D8AtomicMatFXRenderBlack(RxD3D8InstanceData *inst);
+ void _rpMatFXD3D8AtomicMatFXBumpMapRender(RxD3D8InstanceData *inst, int flags, RwTexture *texture, RwTexture *bumpMap, RwTexture *envMap);
+ void _rpMatFXD3D8AtomicMatFXDualPassRender(RxD3D8InstanceData *inst, int flags, RwTexture *texture, RwTexture *dualTexture);
}
-#else
-int &MatFXMaterialDataOffset = *(int*)0x66188C;
-int &MatFXAtomicDataOffset = *(int*)0x66189C;
-#endif
+
#ifdef PS2_MATFX
@@ -218,12 +216,97 @@ _rpMatFXD3D8AtomicMatFXEnvRender_ps2(RxD3D8InstanceData *inst, int flags, int se
RwD3D8SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
}
-#ifdef RWLIBS
-STARTPATCHES
- InjectHook((uintptr)&_rpMatFXD3D8AtomicMatFXEnvRender, _rpMatFXD3D8AtomicMatFXEnvRender_ps2, PATCH_JUMP);
-ENDPATCHES
-#endif
+void
+_rwD3D8EnableClippingIfNeeded(void *object, RwUInt8 type)
+{
+ int clip;
+ if (type == rpATOMIC)
+ clip = !RwD3D8CameraIsSphereFullyInsideFrustum(RwCameraGetCurrentCameraMacro(), RpAtomicGetWorldBoundingSphere((RpAtomic *)object));
+ else
+ clip = !RwD3D8CameraIsBBoxFullyInsideFrustum(RwCameraGetCurrentCameraMacro(), &((RpWorldSector *)object)->tightBoundingBox);
+ RwD3D8SetRenderState(D3DRS_CLIPPING, clip);
+}
-#endif
+void
+_rwD3D8AtomicMatFXRenderCallback(RwResEntry *repEntry, void *object, RwUInt8 type, RwUInt32 flags)
+{
+ RwBool lighting;
+ RwBool forceBlack;
+ RxD3D8ResEntryHeader *header;
+ RxD3D8InstanceData *inst;
+ RwInt32 i;
+
+ if (flags & rpGEOMETRYPRELIT) {
+ RwD3D8SetRenderState(D3DRS_COLORVERTEX, 1);
+ RwD3D8SetRenderState(D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_COLOR1);
+ } else {
+ RwD3D8SetRenderState(D3DRS_COLORVERTEX, 0);
+ RwD3D8SetRenderState(D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_MATERIAL);
+ }
+
+ _rwD3D8EnableClippingIfNeeded(object, type);
+
+ RwD3D8GetRenderState(D3DRS_LIGHTING, &lighting);
+ if (lighting || flags & rpGEOMETRYPRELIT) {
+ forceBlack = FALSE;
+ } else {
+ forceBlack = TRUE;
+ RwD3D8SetTexture(nil, 0);
+ RwD3D8SetRenderState(D3DRS_TEXTUREFACTOR, D3DCOLOR_RGBA(0, 0, 0, 255));
+ RwD3D8SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG2);
+ RwD3D8SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TFACTOR);
+ }
+
+ header = (RxD3D8ResEntryHeader *)(repEntry + 1);
+ inst = (RxD3D8InstanceData *)(header + 1);
+ for (i = 0; i < header->numMeshes; i++) {
+ if (forceBlack)
+ _rpMatFXD3D8AtomicMatFXRenderBlack(inst);
+ else {
+ if (lighting)
+ RwD3D8SetSurfaceProperties(&inst->material->color, &inst->material->surfaceProps, flags & rpGEOMETRYMODULATEMATERIALCOLOR);
+ MatFX *matfx = *RWPLUGINOFFSET(MatFX *, inst->material, MatFXMaterialDataOffset);
+ int effect = matfx ? matfx->effects : rpMATFXEFFECTNULL;
+ switch (effect) {
+ case rpMATFXEFFECTNULL:
+ default:
+ _rpMatFXD3D8AtomicMatFXDefaultRender(inst, flags, inst->material->texture);
+ break;
+ case rpMATFXEFFECTBUMPMAP:
+ _rpMatFXD3D8AtomicMatFXBumpMapRender(inst, flags, inst->material->texture, matfx->fx[0].b.bumpedTex, nil);
+ break;
+ case rpMATFXEFFECTENVMAP:
+ {
+ // TODO: matfx switch in the settings
+ //_rpMatFXD3D8AtomicMatFXEnvRender(inst, flags, 0, inst->material->texture, matfx->fx[0].e.envTex);
+ _rpMatFXD3D8AtomicMatFXEnvRender_ps2(inst, flags, 0, inst->material->texture, matfx->fx[0].e.envTex);
+ break;
+ }
+ case rpMATFXEFFECTBUMPENVMAP:
+ _rpMatFXD3D8AtomicMatFXBumpMapRender(inst, flags, inst->material->texture, matfx->fx[0].b.bumpedTex, matfx->fx[1].e.envTex);
+ break;
+ case rpMATFXEFFECTDUAL:
+ _rpMatFXD3D8AtomicMatFXDualPassRender(inst, flags, inst->material->texture, matfx->fx[0].d.dualTex);
+ break;
+ }
+ }
+ inst++;
+ }
+
+ if (forceBlack) {
+ RwD3D8SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG2);
+ RwD3D8SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
+ }
+}
+
+void
+ReplaceMatFxCallback()
+{
+ RxD3D8AllInOneSetRenderCallBack(
+ RxPipelineFindNodeByName(RpMatFXGetD3D8Pipeline(rpMATFXD3D8ATOMICPIPELINE), RxNodeDefinitionGetD3D8AtomicAllInOne()->name, nil, nil),
+ _rwD3D8AtomicMatFXRenderCallback);
+
+}
+#endif // PS2_MATFX
-#endif
+#endif // !LIBRW
diff --git a/src/rw/RwPS2AlphaTest.cpp b/src/rw/RwPS2AlphaTest.cpp
new file mode 100644
index 00000000..c0d68355
--- /dev/null
+++ b/src/rw/RwPS2AlphaTest.cpp
@@ -0,0 +1,247 @@
+#ifndef LIBRW
+
+#define WITHD3D
+#include "common.h"
+#ifdef PS2_ALPHA_TEST
+#include "rwcore.h"
+
+extern "C" {
+RwBool _rwD3D8RenderStateIsVertexAlphaEnable(void);
+RwBool _rwD3D8RenderStateVertexAlphaEnable(RwBool enable);
+RwRaster *_rwD3D8RWGetRasterStage(RwUInt32 stage);
+}
+
+extern bool gPS2alphaTest;
+
+void
+_rxD3D8DualPassRenderCallback(RwResEntry *repEntry, void *object, RwUInt8 type, RwUInt32 flags)
+{
+ RxD3D8ResEntryHeader *resEntryHeader;
+ RxD3D8InstanceData *instancedData;
+ RwInt32 numMeshes;
+ RwBool lighting;
+ RwBool vertexAlphaBlend;
+ RwBool forceBlack;
+ RwUInt32 ditherEnable;
+ RwUInt32 shadeMode;
+ void *lastVertexBuffer;
+
+ /* Get lighting state */
+ RwD3D8GetRenderState(D3DRS_LIGHTING, &lighting);
+
+ forceBlack = FALSE;
+
+ if (lighting) {
+ if (flags & rxGEOMETRY_PRELIT) {
+ /* Emmisive color from the vertex colors */
+ RwD3D8SetRenderState(D3DRS_COLORVERTEX, TRUE);
+ RwD3D8SetRenderState(D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_COLOR1);
+ } else {
+ /* Emmisive color from material, set to black in the submit node */
+ RwD3D8SetRenderState(D3DRS_COLORVERTEX, FALSE);
+ RwD3D8SetRenderState(D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_MATERIAL);
+ }
+ } else {
+ if ((flags & rxGEOMETRY_PRELIT) == 0) {
+ forceBlack = TRUE;
+
+ RwD3D8GetRenderState(D3DRS_DITHERENABLE, &ditherEnable);
+ RwD3D8GetRenderState(D3DRS_SHADEMODE, &shadeMode);
+
+ RwD3D8SetRenderState(D3DRS_TEXTUREFACTOR, 0xff000000);
+ RwD3D8SetRenderState(D3DRS_DITHERENABLE, FALSE);
+ RwD3D8SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT);
+ }
+ }
+
+ /* Enable clipping */
+ if (type == rpATOMIC) {
+ RpAtomic *atomic;
+ RwCamera *cam;
+
+ atomic = (RpAtomic *)object;
+
+ cam = RwCameraGetCurrentCamera();
+ // RWASSERT(cam);
+
+ if (RwD3D8CameraIsSphereFullyInsideFrustum(cam, RpAtomicGetWorldBoundingSphere(atomic))) {
+ RwD3D8SetRenderState(D3DRS_CLIPPING, FALSE);
+ } else {
+ RwD3D8SetRenderState(D3DRS_CLIPPING, TRUE);
+ }
+ } else {
+ RpWorldSector *worldSector;
+ RwCamera *cam;
+
+ worldSector = (RpWorldSector *)object;
+
+ cam = RwCameraGetCurrentCamera();
+ // RWASSERT(cam);
+
+ if (RwD3D8CameraIsBBoxFullyInsideFrustum(cam, RpWorldSectorGetTightBBox(worldSector))) {
+ RwD3D8SetRenderState(D3DRS_CLIPPING, FALSE);
+ } else {
+ RwD3D8SetRenderState(D3DRS_CLIPPING, TRUE);
+ }
+ }
+
+ /* Set texture to NULL if hasn't any texture flags */
+ if ((flags & (rxGEOMETRY_TEXTURED | rpGEOMETRYTEXTURED2)) == 0) {
+ RwD3D8SetTexture(NULL, 0);
+
+ if (forceBlack) {
+ RwD3D8SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG2);
+ RwD3D8SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TFACTOR);
+
+ RwD3D8SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
+ }
+ }
+
+ /* Get vertex alpha Blend state */
+ vertexAlphaBlend = _rwD3D8RenderStateIsVertexAlphaEnable();
+
+ /* Set Last vertex buffer to force the call */
+ lastVertexBuffer = (void *)0xffffffff;
+
+ /* Get the instanced data */
+ resEntryHeader = (RxD3D8ResEntryHeader *)(repEntry + 1);
+ instancedData = (RxD3D8InstanceData *)(resEntryHeader + 1);
+
+ /*
+ * Data shared between meshes
+ */
+
+ /*
+ * Set the Default Pixel shader
+ */
+ RwD3D8SetPixelShader(0);
+
+ /*
+ * Vertex shader
+ */
+ RwD3D8SetVertexShader(instancedData->vertexShader);
+
+ /* Get the number of meshes */
+ numMeshes = resEntryHeader->numMeshes;
+ while (numMeshes--) {
+ // RWASSERT(instancedData->material != NULL);
+
+ if ((flags & (rxGEOMETRY_TEXTURED | rpGEOMETRYTEXTURED2))) {
+ RwD3D8SetTexture(instancedData->material->texture, 0);
+
+ if (forceBlack) {
+ /* Only change the colorop, we need to use the texture alpha channel */
+ RwD3D8SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG2);
+ RwD3D8SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TFACTOR);
+ }
+ }
+
+ if (instancedData->vertexAlpha || (0xFF != instancedData->material->color.alpha)) {
+ if (!vertexAlphaBlend) {
+ vertexAlphaBlend = TRUE;
+
+ _rwD3D8RenderStateVertexAlphaEnable(TRUE);
+ }
+ } else {
+ if (vertexAlphaBlend) {
+ vertexAlphaBlend = FALSE;
+
+ _rwD3D8RenderStateVertexAlphaEnable(FALSE);
+ }
+ }
+
+ if (lighting) {
+ if (instancedData->vertexAlpha) {
+ RwD3D8SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
+ } else {
+ RwD3D8SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);
+ }
+
+ RwD3D8SetSurfaceProperties(&instancedData->material->color, &instancedData->material->surfaceProps, (flags & rxGEOMETRY_MODULATE));
+ }
+
+ /*
+ * Render
+ */
+
+ /* Set the stream source */
+ if (lastVertexBuffer != instancedData->vertexBuffer) {
+ RwD3D8SetStreamSource(0, instancedData->vertexBuffer, instancedData->stride);
+
+ lastVertexBuffer = instancedData->vertexBuffer;
+ }
+ if (!gPS2alphaTest) {
+ /* Set the Index buffer */
+ if (instancedData->indexBuffer != NULL) {
+ RwD3D8SetIndices(instancedData->indexBuffer, instancedData->baseIndex);
+
+ /* Draw the indexed primitive */
+ RwD3D8DrawIndexedPrimitive((D3DPRIMITIVETYPE)instancedData->primType, 0, instancedData->numVertices, 0, instancedData->numIndices);
+ } else {
+ RwD3D8DrawPrimitive((D3DPRIMITIVETYPE)instancedData->primType, instancedData->baseIndex, instancedData->numVertices);
+ }
+ } else {
+ RwD3D8SetIndices(instancedData->indexBuffer, instancedData->baseIndex);
+
+ int hasAlpha, alphafunc, alpharef, zwrite;
+ RwD3D8GetRenderState(D3DRS_ALPHABLENDENABLE, &hasAlpha);
+ RwD3D8GetRenderState(D3DRS_ZWRITEENABLE, &zwrite);
+ if (hasAlpha && zwrite) {
+ RwD3D8GetRenderState(D3DRS_ALPHAFUNC, &alphafunc);
+ RwD3D8GetRenderState(D3DRS_ALPHAREF, &alpharef);
+
+ RwD3D8SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
+ RwD3D8SetRenderState(D3DRS_ALPHAREF, 128);
+
+ if (instancedData->indexBuffer)
+ RwD3D8DrawIndexedPrimitive(instancedData->primType, 0, instancedData->numVertices, 0, instancedData->numIndices);
+ else
+ RwD3D8DrawPrimitive(instancedData->primType, instancedData->baseIndex, instancedData->numVertices);
+
+ RwD3D8SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_LESS);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, FALSE);
+
+ if (instancedData->indexBuffer)
+ RwD3D8DrawIndexedPrimitive(instancedData->primType, 0, instancedData->numVertices, 0, instancedData->numIndices);
+ else
+ RwD3D8DrawPrimitive(instancedData->primType, instancedData->baseIndex, instancedData->numVertices);
+
+ RwD3D8SetRenderState(D3DRS_ALPHAFUNC, alphafunc);
+ RwD3D8SetRenderState(D3DRS_ALPHAREF, alpharef);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)TRUE);
+ } else {
+ if (instancedData->indexBuffer)
+ RwD3D8DrawIndexedPrimitive(instancedData->primType, 0, instancedData->numVertices, 0, instancedData->numIndices);
+ else
+ RwD3D8DrawPrimitive(instancedData->primType, instancedData->baseIndex, instancedData->numVertices);
+ }
+ }
+
+ /* Move onto the next instancedData */
+ instancedData++;
+ }
+
+ if (forceBlack) {
+ RwD3D8SetRenderState(D3DRS_DITHERENABLE, ditherEnable);
+ RwD3D8SetRenderState(D3DRS_SHADEMODE, shadeMode);
+
+ if (_rwD3D8RWGetRasterStage(0)) {
+ RwD3D8SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
+ RwD3D8SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
+ } else {
+ RwD3D8SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG2);
+ RwD3D8SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
+ }
+ }
+}
+
+void
+ReplaceAtomicPipeCallback()
+{
+ RxD3D8AllInOneSetRenderCallBack(RxPipelineFindNodeByName(RXPIPELINEGLOBAL(platformAtomicPipeline), RxNodeDefinitionGetD3D8AtomicAllInOne()->name, nil, nil),
+ _rxD3D8DualPassRenderCallback);
+}
+
+#endif // PS2_ALPHA_TEST
+
+#endif // !LIBRW \ No newline at end of file
diff --git a/src/rw/VisibilityPlugins.cpp b/src/rw/VisibilityPlugins.cpp
index 22edcb68..f6a9c3b5 100644
--- a/src/rw/VisibilityPlugins.cpp
+++ b/src/rw/VisibilityPlugins.cpp
@@ -797,12 +797,12 @@ CVisibilityPlugins::FrameCopyConstructor(void *dst, const void *src, int32, int3
}
void
-CVisibilityPlugins::SetFrameHierarchyId(RwFrame *frame, int32 id)
+CVisibilityPlugins::SetFrameHierarchyId(RwFrame *frame, uintptr id)
{
FRAMEEXT(frame)->id = id;
}
-int32
+uintptr
CVisibilityPlugins::GetFrameHierarchyId(RwFrame *frame)
{
return FRAMEEXT(frame)->id;
diff --git a/src/rw/VisibilityPlugins.h b/src/rw/VisibilityPlugins.h
index b367d7ee..dd02f2e1 100644
--- a/src/rw/VisibilityPlugins.h
+++ b/src/rw/VisibilityPlugins.h
@@ -103,10 +103,10 @@ public:
struct FrameExt
{
// BUG: this is abused to hold a pointer by SetClumpModelInfo
- int32 id;
+ uintptr id;
};
- static void SetFrameHierarchyId(RwFrame *frame, int32 id);
- static int32 GetFrameHierarchyId(RwFrame *frame);
+ static void SetFrameHierarchyId(RwFrame *frame, uintptr id);
+ static uintptr GetFrameHierarchyId(RwFrame *frame);
static void *FrameConstructor(void *object, int32 offset, int32 len);
static void *FrameDestructor(void *object, int32 offset, int32 len);