From a2428aac1e4ee900fa4934aafa2b734cfdd8c16b Mon Sep 17 00:00:00 2001 From: joshuarwood Date: Fri, 2 May 2025 11:53:02 -0500 Subject: [PATCH 1/8] working to document format used for 16 bit depth integers --- src/game/game_13c510.c | 28 ++++++++++++++++++++++++---- src/include/game/game_13c510.h | 2 +- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/game/game_13c510.c b/src/game/game_13c510.c index c2b4b81e9..95da0f8a8 100644 --- a/src/game/game_13c510.c +++ b/src/game/game_13c510.c @@ -44,11 +44,31 @@ void artifactsTick(void) schedIncrementFrontArtifacts(); } -u16 func0f13c574(f32 arg0) +u16 floatToIntDepth(f32 arg0) { + /** + * Method to convert a 32 bit floating point depth value + * to the unsigned 16 bit integer depth format used by + * the zbuffer available on the N64. The argument arg0 + * represents z normalized to [0, 1] * 32704.0f. + * + * It works by scaling the depth value up to a large + * integer and applying different scaling factors + * before scaling back down to an unsigned 16 bit + * integer. It is probably intended to reduce z-fighting + * by adding more differentiation to distant z values. + * The scaling is done using bitwise operations + * to form the most & least significant bytes of the + * resulting 16 bit integer, likely because bit shift + * operations are faster than division. + * + * TO DO: figure why the output appears with a >> 2 shift. + * It might be worth it to simplify some of the externally + * applied scaling factors if it can match the N64 compilation. + */ u32 value = arg0 * 8.0f; - u32 left; - u32 right = value; + u32 left; // forms the most significant byte of the final u16 + u32 right = value; // forms the least significant byte of the final u16 if (value > 0x3f800) { right = value & 0x7ff; @@ -359,7 +379,7 @@ void artifactsCalculateGlaresForRoom(s32 roomnum) #ifndef PLATFORM_N64 artifact->unk02 = artifactTestLos(&spec, &g_BgRooms[roomnum].pos, xi, yi); #endif - artifact->unk04 = func0f13c574(f0) >> 2; + artifact->unk04 = floatToIntDepth(f0) >> 2; artifact->unk08 = &g_ZbufPtr1[viGetWidth() * yi + xi]; artifact->light = &roomlights[i]; artifact->type = ARTIFACTTYPE_GLARE; diff --git a/src/include/game/game_13c510.h b/src/include/game/game_13c510.h index d8ee2f6dd..f84ad1395 100644 --- a/src/include/game/game_13c510.h +++ b/src/include/game/game_13c510.h @@ -6,7 +6,7 @@ void artifactsClear(void); void artifactsTick(void); -u16 func0f13c574(f32 arg0); +u16 floatToIntDepth(f32 arg0); s32 func0f13c710(f32 arg0); void artifactsCalculateGlaresForRoom(s32 roomnum); u8 func0f13d3c4(u8 arg0, u8 arg1); From 75e34ace8c57637f3e37f06133e6098024e5a699 Mon Sep 17 00:00:00 2001 From: joshuarwood Date: Sat, 3 May 2025 16:06:10 -0500 Subject: [PATCH 2/8] added Ryan Dwyer's comment describing how artifact handling behaves --- src/game/game_13c510.c | 88 +++++++++++++++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 13 deletions(-) diff --git a/src/game/game_13c510.c b/src/game/game_13c510.c index 95da0f8a8..f66851b6e 100644 --- a/src/game/game_13c510.c +++ b/src/game/game_13c510.c @@ -23,6 +23,70 @@ #include "game/prop.h" #endif +/** + * Artifacts are points of interest in the z-buffer. + * + * They correspond to: + * - Individual circles in the lens flare effect from the sun. + * - Individual corners of each light fixture's box. + * + * The game needs to do line of sight checks to these points. The collision + * system would normally be used for line of sight checks, but it only works + * with basic geometric volumes and also doesn't take into account the player's + * gun. Instead, the checks are done by reading from the previous frame's + * z-buffer. + * + * Typically, the z-buffer would be read by the scheduler after a graphics frame + * is rendered, but this only works if the z-buffer is a complete image. + * PD draws the scene, then clears the z-buffer before drawing the player's gun, + * so the z-buffer at the end only contains the player's gun. To work around + * this, the GPU is given commands to read the z-buffer as a texture and copy + * depth values to a safe place before clearing it. Then once the frame is + * rendered, the scheduler compares the saved depths with the current z-buffer + * and updates the artifact, applying the minimum of the two depths. + * + * The scheduler maintains 3 arrays of artifacts, each referenced by indexes + * which rotate between them. + * - Artifacts are written by the main thread using the write index. + * The write and front indexes are then incremented. + * - The same artifacts are updated by the scheduler using the pending index. + * The pending index is then updated. + * - The artifacts are then rendered on a later frame using the front index. + * + * In each artifacts array, the first several slots are reserved for the sun + * flare artifacts. The quantity depends on the number of suns in the stage + * (Skedar Ruins has 3) and there are 8 artifacts per sun. The remaining slots + * are used for light fixture corners. The array is big enough to handle at + * least 90 lights on screen at a time. + * + * The initial state of the indexes are write=0, front=1, pending=0. + * These are set in sched_reset_artifacts. + * + * The detailed workflow is: + * - CPU: Light artifacts are determined and added to write artifacts (0) array + * - CPU: Constructs the gdl in this order: + * - Render scene + * - Copy relevant parts of z-buffer to write depths (0) array + * - Clear z-buffer and render gun + * - Render artifacts by reading from front artifacts (1) array + * - CPU: increments write (0 -> 1) and front (1 -> 2) indexes + * - GPU: Executes above task. g_ArtifactDepths0 now contains depths, and is + * pointed to by pending. + * - Scheduler: Reads the z-buffer, which at this point only contains the gun + * depth information, and updates the artifact with the minimum of the two + * - Scheduler: Increments pending (0 -> 1) + * + * It appears that the front index should be initialised to 2 instead, so that + * it's one frame behind the others rather than two frames behind. + * + * There's no doubt this went through several iterations before landing on this + * implementation. It's likely that this was implemented using a single and full + * z-buffer and it worked well until they decided to clear the z-buffer before + * rendering the gun. There is evidence in zbuf.c that they allocated a second + * z-buffer and swapped it. But when memory got too tight they had to change it + * to this texture read method. + */ + u8 *var800a41a0; u32 var800a41a4; u32 var800a41a8; @@ -47,20 +111,18 @@ void artifactsTick(void) u16 floatToIntDepth(f32 arg0) { /** - * Method to convert a 32 bit floating point depth value - * to the unsigned 16 bit integer depth format used by - * the zbuffer available on the N64. The argument arg0 - * represents z normalized to [0, 1] * 32704.0f. + * Method to convert a 32 bit floating point depth value to the + * unsigned 16 bit integer format used by the zbuffer on the N64. + * The argument arg0 represents z normalized to [0, 1] * 32704.0f. * - * It works by scaling the depth value up to a large - * integer and applying different scaling factors - * before scaling back down to an unsigned 16 bit - * integer. It is probably intended to reduce z-fighting - * by adding more differentiation to distant z values. - * The scaling is done using bitwise operations - * to form the most & least significant bytes of the - * resulting 16 bit integer, likely because bit shift - * operations are faster than division. + * It works by converting the depth value to a large, unsigned 32 bit + * integer before scaling back down to an unsigned 16 bit integer. + * The scaling is done using bit shift operations on the most & least + * significant bytes of the resulting 16 bit integer, likely because + * bit shift operations are faster than division. The segmentation of + * this calculation at values 0x3f800, 0x3f000, etc. is probably + * intended to reduce z-fighting by adding more differentiation for + * distant z values. * * TO DO: figure why the output appears with a >> 2 shift. * It might be worth it to simplify some of the externally From 0d6c55798260d955ef0731f9ee717e24be859663 Mon Sep 17 00:00:00 2001 From: joshuarwood Date: Sat, 3 May 2025 19:57:52 -0500 Subject: [PATCH 3/8] updated variable names to match Ryan Dwyer's work clarifying the zbuffer behavior --- src/game/bondgun.c | 10 +++--- src/game/game_13c510.c | 80 ++++++++++++++++++++++++++---------------- src/game/sky.c | 10 +++--- src/game/zbuf.c | 36 +++++++++---------- src/include/types.h | 18 +++++----- src/lib/sched.c | 16 ++++----- 6 files changed, 95 insertions(+), 75 deletions(-) diff --git a/src/game/bondgun.c b/src/game/bondgun.c index 2f929cb35..3d463d16e 100644 --- a/src/game/bondgun.c +++ b/src/game/bondgun.c @@ -8477,7 +8477,7 @@ glabel var7f1aca90 /* f0a71e4: 100002d5 */ b .L0f0a7d3c /* f0a71e8: 8fbf0034 */ lw $ra,0x34($sp) .L0f0a71ec: -/* f0a71ec: 0fc5d9ad */ jal zbufDrawArtifactsOffscreen +/* f0a71ec: 0fc5d9ad */ jal zbufSaveArtifactDepths /* f0a71f0: 8fa4014c */ lw $a0,0x14c($sp) /* f0a71f4: afa2014c */ sw $v0,0x14c($sp) /* f0a71f8: 0c002ca0 */ jal viPrepareZbuf @@ -9318,7 +9318,7 @@ glabel var7f1aca90 /* f0a71e4: 100002d5 */ b .L0f0a7d3c /* f0a71e8: 8fbf0034 */ lw $ra,0x34($sp) .L0f0a71ec: -/* f0a71ec: 0fc5d9ad */ jal zbufDrawArtifactsOffscreen +/* f0a71ec: 0fc5d9ad */ jal zbufSaveArtifactDepths /* f0a71f0: 8fa4014c */ lw $a0,0x14c($sp) /* f0a71f4: afa2014c */ sw $v0,0x14c($sp) /* f0a71f8: 0c002ca0 */ jal viPrepareZbuf @@ -10159,7 +10159,7 @@ glabel var7f1aca90 /* f0a4f30: 100002cd */ beqz $zero,.NB0f0a5a68 /* f0a4f34: 8fbf0034 */ lw $ra,0x34($sp) .NB0f0a4f38: -/* f0a4f38: 0fc5c4d5 */ jal zbufDrawArtifactsOffscreen +/* f0a4f38: 0fc5c4d5 */ jal zbufSaveArtifactDepths /* f0a4f3c: 8fa40144 */ lw $a0,0x144($sp) /* f0a4f40: afa20144 */ sw $v0,0x144($sp) /* f0a4f44: 0c002d00 */ jal viPrepareZbuf @@ -10956,9 +10956,7 @@ void bgunRender(Gfx **gdlptr) return; } -#ifdef PLATFORM_N64 // TODO - gdl = zbufDrawArtifactsOffscreen(gdl); -#endif + gdl = zbufSaveArtifactDepths(gdl); gdl = viPrepareZbuf(gdl); gdl = vi0000b1d0(gdl); diff --git a/src/game/game_13c510.c b/src/game/game_13c510.c index f66851b6e..ae79b10dd 100644 --- a/src/game/game_13c510.c +++ b/src/game/game_13c510.c @@ -439,14 +439,14 @@ void artifactsCalculateGlaresForRoom(s32 roomnum) if (index < MAX_ARTIFACTS) { #ifndef PLATFORM_N64 - artifact->unk02 = artifactTestLos(&spec, &g_BgRooms[roomnum].pos, xi, yi); + artifact->visiblelos = artifactTestLos(&spec, &g_BgRooms[roomnum].pos, xi, yi); #endif - artifact->unk04 = floatToIntDepth(f0) >> 2; - artifact->unk08 = &g_ZbufPtr1[viGetWidth() * yi + xi]; + artifact->expecteddepth = floatToIntDepth(f0) >> 2; + artifact->zbufptr = &g_ZbufPtr1[viGetWidth() * yi + xi]; artifact->light = &roomlights[i]; artifact->type = ARTIFACTTYPE_GLARE; - artifact->unk0c.u16_2 = xi; - artifact->unk0c.u16_1 = yi; + artifact->screenx = xi; + artifact->screeny = yi; } } } @@ -457,7 +457,7 @@ void artifactsCalculateGlaresForRoom(s32 roomnum) } } -u8 func0f13d3c4(u8 arg0, u8 arg1) +u8 artifactsClamp(u8 arg0, u8 arg1) { if (arg1 >= arg0 + 7) { return arg0 + 7; @@ -505,18 +505,18 @@ Gfx *artifactsRenderGlaresForRoom(Gfx *gdl, s32 roomnum) u16 min; u16 max; f32 lightop_cur_frac; - s32 t2; + s32 numgood; struct light *light; u8 *s3; s32 k; s32 count; - u16 t4; + u16 actualdepth; f32 add; s32 l; f32 brightness; - s32 avg; + s32 tolerance; f32 f0; - s32 v1; + s32 difference; s32 r; s32 g; s32 b; @@ -542,6 +542,12 @@ Gfx *artifactsRenderGlaresForRoom(Gfx *gdl, s32 roomnum) struct light *light2 = artifacts[i].light; count = 0; + /** + * light arifacts are created from several, closely spaced + * textures that give the appearance of a dynamic light glare + * as the character moves. Loop to count all the sub-artifacts + * in this light. + */ for (j = i; j < MAX_ARTIFACTS && artifacts[j].type == ARTIFACTTYPE_GLARE && artifacts[j].light == light2; j++) { count++; } @@ -552,51 +558,65 @@ Gfx *artifactsRenderGlaresForRoom(Gfx *gdl, s32 roomnum) if (roomnum == light->roomnum) { lightindex = ((uintptr_t)light - (uintptr_t)g_BgLightsFileData) / sizeof(struct light); s3 = &var800a41a0[lightindex * 3]; - t2 = 0; + numgood = 0; min = 0xffff; max = 0; + /** + * loop to determine the min & max depth of + * the sub-artifacts composing this room light. + */ for (k = i; k < i + count; k++) { - if (artifacts[k].unk04 > max) { - max = artifacts[k].unk04; + if (artifacts[k].expecteddepth > max) { + max = artifacts[k].expecteddepth; } - if (artifacts[k].unk04 < min) { - min = artifacts[k].unk04; + if (artifacts[k].expecteddepth < min) { + min = artifacts[k].expecteddepth; } } - avg = (max - min) >> 1; + /** + * Define a depth tolerance from the min & max + * depths of sub-artifacts for a given light. + * This will be used to determine which light + * artifacts are visible when comparing depth + * values of lights to other items rendered + * on screen. Without this, the lights would + * constantly flicker due to z-fighting caused + * by the low precision of the N64 depth. + */ + tolerance = (max - min) >> 1; - if (avg < 25) { - avg = 25; + if (tolerance < 25) { + tolerance = 25; } for (k = i; k < i + count; k++) { -#ifdef PLATFORM_N64 - u16 tmp; - t4 = (artifacts[k].unk02 & 0xfffc) >> 2; - tmp = artifacts[k].unk04; + u16 expecteddepth; + actualdepth = (artifacts[k].actualdepth & 0xfffc) >> 2; + expecteddepth = artifacts[k].expecteddepth; - if (tmp < t4) { - v1 = t4 - tmp; + if (expecteddepth < actualdepth) { + difference = actualdepth - expecteddepth; } else { - v1 = tmp - t4; + difference = expecteddepth - actualdepth; } - if (avg >= v1) { - t2++; +#ifdef PLATFORM_N64 + if (difference <= tolerance) { + numgood++; } #else - t2 += artifacts[k].unk02; + numgood += artifacts[k].visiblelos; #endif artifacts[k].type = ARTIFACTTYPE_FREE; } - s3[0] = func0f13d3c4(s3[0], t2 * 2); + s3[0] = artifactsClamp(s3[0], numgood * 2); - if (t2 > 0) { + if (numgood > 0) { brightness = viGetFovY() * 0.017453292f; add = cosf(brightness) / sinf(brightness) * 14.6f; diff --git a/src/game/sky.c b/src/game/sky.c index e610cad83..d5252919c 100644 --- a/src/game/sky.c +++ b/src/game/sky.c @@ -2518,11 +2518,11 @@ void skyCreateSunArtifact(struct artifact *artifact, s32 x, s32 y) sunpos.x = env->suns[i].pos[0]; sunpos.y = env->suns[i].pos[1]; sunpos.z = env->suns[i].pos[2]; - artifact->unk02 = artifactTestLos(&sunpos, &zero, x, y) * 0xfffc; + artifact->visiblelos = artifactTestLos(&sunpos, &zero, x, y) * 0xfffc; #endif - artifact->unk08 = &g_ZbufPtr1[(s32)camGetScreenWidth() * y + x]; - artifact->unk0c.u16_2 = x; - artifact->unk0c.u16_1 = y; + artifact->zbufptr = &g_ZbufPtr1[(s32)camGetScreenWidth() * y + x]; + artifact->screenx = x; + artifact->screeny = y; artifact->type = ARTIFACTTYPE_CIRCLE; } } @@ -2533,7 +2533,7 @@ f32 skyGetArtifactGroupIntensityFrac(struct artifact *artifacts) s32 i; for (i = 0; i < 8; i++) { - if (artifacts[i].type == ARTIFACTTYPE_CIRCLE && artifacts[i].unk02 == 0xfffc) { + if (artifacts[i].type == ARTIFACTTYPE_CIRCLE && artifacts[i].actualdepth == 0xfffc) { sum += 0.125f; } } diff --git a/src/game/zbuf.c b/src/game/zbuf.c index cf1b62140..0d1d2bb53 100644 --- a/src/game/zbuf.c +++ b/src/game/zbuf.c @@ -177,23 +177,23 @@ u16 *zbufGetArtifactsCfb(s32 index) return addr; } -Gfx *zbufDrawArtifactsOffscreen(Gfx *gdl) +Gfx *zbufSaveArtifactDepths(Gfx *gdl) { struct artifact *artifacts = schedGetWriteArtifacts(); u32 stack; - u16 *sp4c = g_ZbufPtr1; - u32 s4 = 0; - u16 *sp44; - u16 *s2; - u16 *image; + u16 *zbuf = g_ZbufPtr1; + u32 numsamples = 0; + u16 *samples; + u16 *thissample; + u16 *zbufrow; s32 i; viGetBackBuffer(); - sp44 = zbufGetArtifactsCfb(g_SchedWriteArtifactsIndex); + samples = zbufGetArtifactsCfb(g_SchedWriteArtifactsIndex); g_SchedSpecialArtifactIndexes[g_SchedWriteArtifactsIndex] = 1; gDPPipeSync(gdl++); - gDPSetColorImage(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_16b, viGetBufWidth(), OS_PHYSICAL_TO_K0(sp44)); + gDPSetColorImage(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_16b, viGetBufWidth(), OS_PHYSICAL_TO_K0(samples)); gDPSetScissor(gdl++, G_SC_NON_INTERLACE, 0, 0, SCREEN_320, SCREEN_240); gDPSetCycleType(gdl++, G_CYC_COPY); gDPSetTile(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 0, 0x0000, 5, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD); @@ -220,24 +220,24 @@ Gfx *zbufDrawArtifactsOffscreen(Gfx *gdl) if (1); if (artifacts[i].type != ARTIFACTTYPE_FREE) { - s2 = &sp44[s4]; - image = &sp4c[artifacts[i].unk0c.u16_1 * viGetWidth()]; + thissample = &samples[numsamples]; + zbufrow = &zbuf[artifacts[i].screeny * viGetWidth()]; gDPPipeSync(gdl++); - gDPSetTextureImage(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_16b, SCREEN_320, image); + gDPSetTextureImage(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_16b, SCREEN_320, zbufrow); gDPLoadSync(gdl++); gDPLoadBlock(gdl++, 5, 0, 0, viGetWidth() - 1, 0); gDPPipeSync(gdl++); gSPTextureRectangle(gdl++, - s4 << 2, 0, - (s4 + 3) << 2, 0, - G_TX_RENDERTILE, (artifacts[i].unk0c.u16_2 * 32) + 16, 0x0010, 0x1000, 0); + numsamples << 2, 0, + (numsamples + 3) << 2, 0, + G_TX_RENDERTILE, (artifacts[i].screenx * 32) + 16, 0x0010, 0x1000, 0); - artifacts[i].unk0c.u16p = s2; - s4++; + artifacts[i].depthptr = thissample; + numsamples++; - if (s2); + if (thissample); } } @@ -251,7 +251,7 @@ Gfx *zbufDrawArtifactsOffscreen(Gfx *gdl) gDPSetTexturePersp(gdl++, G_TP_PERSP); gDPSetColorDither(gdl++, G_CD_BAYER); - if (sp44); + if (samples); return gdl; } diff --git a/src/include/types.h b/src/include/types.h index 1da61867b..702c6d6d0 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -3494,17 +3494,19 @@ struct audioconfig { struct artifact { u16 type; - u16 unk02; - u16 unk04; - u16 unk06; - u16 *unk08; + u16 actualdepth; + u16 expecteddepth; + u16 *zbufptr; +#ifndef PLATFORM_N64 + u16 visiblelos; +#endif union { - u16 *u16p; + u16 *depthptr; struct { - u16 u16_1; - u16 u16_2; + u16 screeny; + u16 screenx; }; - } unk0c; + }; struct light *light; }; diff --git a/src/lib/sched.c b/src/lib/sched.c index 266e4cb68..b70906336 100644 --- a/src/lib/sched.c +++ b/src/lib/sched.c @@ -540,20 +540,20 @@ void schedUpdatePendingArtifacts(void) struct artifact *artifact = &artifacts[i]; if (artifact->type != ARTIFACTTYPE_FREE) { - u16 *unk08 = artifact->unk08; - u16 value08 = unk08[0]; + u16 *currdepthptr = artifact->zbufptr; + u16 currdepth = *currdepthptr; if (g_SchedSpecialArtifactIndexes[g_SchedPendingArtifactsIndex] == 1) { - u16 *unk0c = artifact->unk0c.u16p; - u16 value0c = unk0c[0]; + u16 *prevdepthptr = artifact->depthptr; + u16 prevdepth = *prevdepthptr; - if (value0c > value08) { - artifact->unk02 = value08; + if (currdepth < prevdepth) { + artifact->actualdepth = currdepth; } else { - artifact->unk02 = value0c; + artifact->actualdepth = prevdepth; } } else { - artifact->unk02 = value08; + artifact->actualdepth = currdepth; } } } From 400865ec256db0f0f5fddd654aaa409042fc3b97 Mon Sep 17 00:00:00 2001 From: joshuarwood Date: Sat, 3 May 2025 20:17:29 -0500 Subject: [PATCH 4/8] added debugging to pin point seg fault --- src/game/bondgun.c | 5 +++++ src/game/game_13c510.c | 16 ++++++++++++++++ src/game/zbuf.c | 8 ++++++-- src/lib/sched.c | 5 +++++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/game/bondgun.c b/src/game/bondgun.c index 3d463d16e..87edc9b9b 100644 --- a/src/game/bondgun.c +++ b/src/game/bondgun.c @@ -57,6 +57,7 @@ #include "game/stagetable.h" #include "video.h" #include "platform.h" +#include // remove after debugging #endif #define GUNLOADSTATE_FLUX 0 @@ -10938,6 +10939,8 @@ glabel var7f1aca90 // Mismatch: Goal uses different codegen for accessing vertices void bgunRender(Gfx **gdlptr) { + printf("\nsrc/game/bondgun.c:bgunRender()"); + fflush(stdout); Gfx *gdl = *gdlptr; struct modelrenderdata renderdata = {NULL, true, 3}; // 10c struct player *player; @@ -11190,6 +11193,8 @@ void bgunRender(Gfx **gdlptr) viGetViewLeft() + viGetViewWidth(), viGetViewTop() + viGetViewHeight()); *gdlptr = gdl; + printf("\n done!"); + fflush(stdout); } #endif diff --git a/src/game/game_13c510.c b/src/game/game_13c510.c index ae79b10dd..fa215a31c 100644 --- a/src/game/game_13c510.c +++ b/src/game/game_13c510.c @@ -21,6 +21,7 @@ #include "lib/lib_17ce0.h" #include "game/player.h" #include "game/prop.h" +#include // remove after debugging #endif /** @@ -214,6 +215,9 @@ bool artifactTestLos(struct coord *spec, struct coord *roompos, s32 xi, s32 yi) void artifactsCalculateGlaresForRoom(s32 roomnum) { + printf("\nsrc/game/game_13c510.c:artifactsCalculateGlaresForRoom(%d)", roomnum); + fflush(stdout); + s32 i; s32 j; s32 k; @@ -455,6 +459,8 @@ void artifactsCalculateGlaresForRoom(s32 roomnum) } } } + printf("\n done!"); + fflush(stdout); } u8 artifactsClamp(u8 arg0, u8 arg1) @@ -472,6 +478,9 @@ u8 artifactsClamp(u8 arg0, u8 arg1) Gfx *artifactsConfigureForGlares(Gfx *gdl) { + printf("\nsrc/game/game_13c510.c:artifactsConfigureForGlares()"); + fflush(stdout); + struct stagetableentry *stage = stageGetCurrent(); texSelect(&gdl, &g_TexLightGlareConfigs[stage->light_type], 4, 0, 2, 1, NULL); @@ -486,6 +495,8 @@ Gfx *artifactsConfigureForGlares(Gfx *gdl) gDPSetAlphaDither(gdl++, G_AD_PATTERN); gDPSetTexturePersp(gdl++, G_TP_NONE); + printf("\n done!"); + fflush(stdout); return gdl; } @@ -498,6 +509,9 @@ Gfx *artifactsUnconfigureForGlares(Gfx *gdl) Gfx *artifactsRenderGlaresForRoom(Gfx *gdl, s32 roomnum) { + printf("\nsrc/game/game_13c510.c:artifactsRenderGlaresForRoom(%d)", roomnum); + fflush(stdout); + s32 i; s32 j; s32 lightindex; @@ -740,5 +754,7 @@ Gfx *artifactsRenderGlaresForRoom(Gfx *gdl, s32 roomnum) } } + printf("\n done!"); + fflush(stdout); return gdl; } diff --git a/src/game/zbuf.c b/src/game/zbuf.c index 0d1d2bb53..3668616f3 100644 --- a/src/game/zbuf.c +++ b/src/game/zbuf.c @@ -10,6 +10,7 @@ #include "lib/memp.h" #include "data.h" #include "types.h" +#include // remove after debugging u32 g_ZbufWidth; u32 g_ZbufHeight; @@ -125,7 +126,6 @@ Gfx *zbufConfigureRdp(Gfx *gdl) */ Gfx *zbufClear(Gfx *gdl) { -#ifdef PLATFORM_N64 s32 left; s32 right; @@ -149,7 +149,7 @@ Gfx *zbufClear(Gfx *gdl) gDPFillRectangle(gdl++, left, 0, right, playerGetFbHeight() - 1); gDPPipeSync(gdl++); -#else +#ifndef PLATFORM_N64 gDPClearDepthEXT(gdl++); #endif @@ -188,6 +188,8 @@ Gfx *zbufSaveArtifactDepths(Gfx *gdl) u16 *zbufrow; s32 i; + printf("\nsrc/game/zbuf.c:zbufSaveArtifactDepths()"); + fflush(stdout); viGetBackBuffer(); samples = zbufGetArtifactsCfb(g_SchedWriteArtifactsIndex); g_SchedSpecialArtifactIndexes[g_SchedWriteArtifactsIndex] = 1; @@ -253,5 +255,7 @@ Gfx *zbufSaveArtifactDepths(Gfx *gdl) if (samples); + printf("\n done!"); + fflush(stdout); return gdl; } diff --git a/src/lib/sched.c b/src/lib/sched.c index b70906336..a954357ad 100644 --- a/src/lib/sched.c +++ b/src/lib/sched.c @@ -19,6 +19,7 @@ #include "lib/joy.h" #include "data.h" #include "types.h" +#include // remove after debugging /* * private typedefs and defines @@ -533,6 +534,8 @@ void schedResetArtifacts(void) void schedUpdatePendingArtifacts(void) { + printf("\nsrc/lib/sched.c:schedUpdatePendingArtifacts()"); + fflush(stdout); struct artifact *artifacts = schedGetPendingArtifacts(); s32 i; @@ -561,6 +564,8 @@ void schedUpdatePendingArtifacts(void) g_SchedSpecialArtifactIndexes[g_SchedPendingArtifactsIndex] = 0; schedIncrementPendingArtifacts(); + printf("\n done!"); + fflush(stdout); } /** From 062de5bb7badc98914635236cb80ac37ea83166c Mon Sep 17 00:00:00 2001 From: joshuarwood Date: Sun, 11 May 2025 11:59:11 -0500 Subject: [PATCH 5/8] clear up debugging statements --- src/game/bondgun.c | 7 ++----- src/game/game_13c510.c | 30 ++++++++---------------------- src/game/zbuf.c | 16 ++++++++++------ src/lib/sched.c | 5 ----- 4 files changed, 20 insertions(+), 38 deletions(-) diff --git a/src/game/bondgun.c b/src/game/bondgun.c index 87edc9b9b..a46e66721 100644 --- a/src/game/bondgun.c +++ b/src/game/bondgun.c @@ -57,7 +57,6 @@ #include "game/stagetable.h" #include "video.h" #include "platform.h" -#include // remove after debugging #endif #define GUNLOADSTATE_FLUX 0 @@ -10939,8 +10938,6 @@ glabel var7f1aca90 // Mismatch: Goal uses different codegen for accessing vertices void bgunRender(Gfx **gdlptr) { - printf("\nsrc/game/bondgun.c:bgunRender()"); - fflush(stdout); Gfx *gdl = *gdlptr; struct modelrenderdata renderdata = {NULL, true, 3}; // 10c struct player *player; @@ -10959,7 +10956,9 @@ void bgunRender(Gfx **gdlptr) return; } +#ifdef PLATFORM_N64 gdl = zbufSaveArtifactDepths(gdl); +#endif gdl = viPrepareZbuf(gdl); gdl = vi0000b1d0(gdl); @@ -11193,8 +11192,6 @@ void bgunRender(Gfx **gdlptr) viGetViewLeft() + viGetViewWidth(), viGetViewTop() + viGetViewHeight()); *gdlptr = gdl; - printf("\n done!"); - fflush(stdout); } #endif diff --git a/src/game/game_13c510.c b/src/game/game_13c510.c index fa215a31c..4dde60b57 100644 --- a/src/game/game_13c510.c +++ b/src/game/game_13c510.c @@ -21,7 +21,6 @@ #include "lib/lib_17ce0.h" #include "game/player.h" #include "game/prop.h" -#include // remove after debugging #endif /** @@ -109,7 +108,7 @@ void artifactsTick(void) schedIncrementFrontArtifacts(); } -u16 floatToIntDepth(f32 arg0) +u16 floatToN64Depth(f32 arg0) { /** * Method to convert a 32 bit floating point depth value to the @@ -124,10 +123,6 @@ u16 floatToIntDepth(f32 arg0) * this calculation at values 0x3f800, 0x3f000, etc. is probably * intended to reduce z-fighting by adding more differentiation for * distant z values. - * - * TO DO: figure why the output appears with a >> 2 shift. - * It might be worth it to simplify some of the externally - * applied scaling factors if it can match the N64 compilation. */ u32 value = arg0 * 8.0f; u32 left; // forms the most significant byte of the final u16 @@ -215,9 +210,6 @@ bool artifactTestLos(struct coord *spec, struct coord *roompos, s32 xi, s32 yi) void artifactsCalculateGlaresForRoom(s32 roomnum) { - printf("\nsrc/game/game_13c510.c:artifactsCalculateGlaresForRoom(%d)", roomnum); - fflush(stdout); - s32 i; s32 j; s32 k; @@ -445,7 +437,13 @@ void artifactsCalculateGlaresForRoom(s32 roomnum) #ifndef PLATFORM_N64 artifact->visiblelos = artifactTestLos(&spec, &g_BgRooms[roomnum].pos, xi, yi); #endif - artifact->expecteddepth = floatToIntDepth(f0) >> 2; + /** + * the game performs artifact depth comparison using + * the original N64 depth values divided by 4, which + * is accomplished by bit shifting the N64 depth value + * to the right using >> 2 + */ + artifact->expecteddepth = floatToN64Depth(f0) >> 2; artifact->zbufptr = &g_ZbufPtr1[viGetWidth() * yi + xi]; artifact->light = &roomlights[i]; artifact->type = ARTIFACTTYPE_GLARE; @@ -459,8 +457,6 @@ void artifactsCalculateGlaresForRoom(s32 roomnum) } } } - printf("\n done!"); - fflush(stdout); } u8 artifactsClamp(u8 arg0, u8 arg1) @@ -478,9 +474,6 @@ u8 artifactsClamp(u8 arg0, u8 arg1) Gfx *artifactsConfigureForGlares(Gfx *gdl) { - printf("\nsrc/game/game_13c510.c:artifactsConfigureForGlares()"); - fflush(stdout); - struct stagetableentry *stage = stageGetCurrent(); texSelect(&gdl, &g_TexLightGlareConfigs[stage->light_type], 4, 0, 2, 1, NULL); @@ -495,8 +488,6 @@ Gfx *artifactsConfigureForGlares(Gfx *gdl) gDPSetAlphaDither(gdl++, G_AD_PATTERN); gDPSetTexturePersp(gdl++, G_TP_NONE); - printf("\n done!"); - fflush(stdout); return gdl; } @@ -509,9 +500,6 @@ Gfx *artifactsUnconfigureForGlares(Gfx *gdl) Gfx *artifactsRenderGlaresForRoom(Gfx *gdl, s32 roomnum) { - printf("\nsrc/game/game_13c510.c:artifactsRenderGlaresForRoom(%d)", roomnum); - fflush(stdout); - s32 i; s32 j; s32 lightindex; @@ -754,7 +742,5 @@ Gfx *artifactsRenderGlaresForRoom(Gfx *gdl, s32 roomnum) } } - printf("\n done!"); - fflush(stdout); return gdl; } diff --git a/src/game/zbuf.c b/src/game/zbuf.c index 3668616f3..d64f79f28 100644 --- a/src/game/zbuf.c +++ b/src/game/zbuf.c @@ -10,7 +10,6 @@ #include "lib/memp.h" #include "data.h" #include "types.h" -#include // remove after debugging u32 g_ZbufWidth; u32 g_ZbufHeight; @@ -126,6 +125,7 @@ Gfx *zbufConfigureRdp(Gfx *gdl) */ Gfx *zbufClear(Gfx *gdl) { +#ifdef PLATFORM_N64 s32 left; s32 right; @@ -149,7 +149,7 @@ Gfx *zbufClear(Gfx *gdl) gDPFillRectangle(gdl++, left, 0, right, playerGetFbHeight() - 1); gDPPipeSync(gdl++); -#ifndef PLATFORM_N64 +#else gDPClearDepthEXT(gdl++); #endif @@ -177,6 +177,14 @@ u16 *zbufGetArtifactsCfb(s32 index) return addr; } +/** + * This method is designed to save artifact depths + * prior to drawing the hands and weapon on-screen + * since drawing them requires clearing the zbuffer + * to avoid clipping the gun model on floors and walls. + * + * TODO: determine if this works with the PC port + */ Gfx *zbufSaveArtifactDepths(Gfx *gdl) { struct artifact *artifacts = schedGetWriteArtifacts(); @@ -188,8 +196,6 @@ Gfx *zbufSaveArtifactDepths(Gfx *gdl) u16 *zbufrow; s32 i; - printf("\nsrc/game/zbuf.c:zbufSaveArtifactDepths()"); - fflush(stdout); viGetBackBuffer(); samples = zbufGetArtifactsCfb(g_SchedWriteArtifactsIndex); g_SchedSpecialArtifactIndexes[g_SchedWriteArtifactsIndex] = 1; @@ -255,7 +261,5 @@ Gfx *zbufSaveArtifactDepths(Gfx *gdl) if (samples); - printf("\n done!"); - fflush(stdout); return gdl; } diff --git a/src/lib/sched.c b/src/lib/sched.c index a954357ad..b70906336 100644 --- a/src/lib/sched.c +++ b/src/lib/sched.c @@ -19,7 +19,6 @@ #include "lib/joy.h" #include "data.h" #include "types.h" -#include // remove after debugging /* * private typedefs and defines @@ -534,8 +533,6 @@ void schedResetArtifacts(void) void schedUpdatePendingArtifacts(void) { - printf("\nsrc/lib/sched.c:schedUpdatePendingArtifacts()"); - fflush(stdout); struct artifact *artifacts = schedGetPendingArtifacts(); s32 i; @@ -564,8 +561,6 @@ void schedUpdatePendingArtifacts(void) g_SchedSpecialArtifactIndexes[g_SchedPendingArtifactsIndex] = 0; schedIncrementPendingArtifacts(); - printf("\n done!"); - fflush(stdout); } /** From f12ae756ef7436090cfdfbf24956d3654310f7ee Mon Sep 17 00:00:00 2001 From: joshuarwood Date: Sun, 11 May 2025 12:17:38 -0500 Subject: [PATCH 6/8] rename game_13c510 files to artifact --- src/game/artifact.c | 746 ++++++++++++++++++++++++++++++++++++ src/game/bg.c | 2 +- src/game/bondgun.c | 2 +- src/game/lv.c | 2 +- src/game/sky.c | 2 +- src/include/game/artifact.h | 20 + 6 files changed, 770 insertions(+), 4 deletions(-) create mode 100644 src/game/artifact.c create mode 100644 src/include/game/artifact.h diff --git a/src/game/artifact.c b/src/game/artifact.c new file mode 100644 index 000000000..03dae835d --- /dev/null +++ b/src/game/artifact.c @@ -0,0 +1,746 @@ +#include +#include "lib/sched.h" +#include "constants.h" +#include "game/camera.h" +#include "game/dlights.h" +#include "game/env.h" +#include "game/game_0b2150.h" +#include "game/tex.h" +#include "game/sky.h" +#include "game/artifact.h" +#include "game/bg.h" +#include "game/stagetable.h" +#include "game/room.h" +#include "bss.h" +#include "lib/vi.h" +#include "lib/mtx.h" +#include "data.h" +#include "types.h" +#ifndef PLATFORM_N64 +#include "lib/collision.h" +#include "lib/lib_17ce0.h" +#include "game/player.h" +#include "game/prop.h" +#endif + +/** + * Artifacts are points of interest in the z-buffer. + * + * They correspond to: + * - Individual circles in the lens flare effect from the sun. + * - Individual corners of each light fixture's box. + * + * The game needs to do line of sight checks to these points. The collision + * system would normally be used for line of sight checks, but it only works + * with basic geometric volumes and also doesn't take into account the player's + * gun. Instead, the checks are done by reading from the previous frame's + * z-buffer. + * + * Typically, the z-buffer would be read by the scheduler after a graphics frame + * is rendered, but this only works if the z-buffer is a complete image. + * PD draws the scene, then clears the z-buffer before drawing the player's gun, + * so the z-buffer at the end only contains the player's gun. To work around + * this, the GPU is given commands to read the z-buffer as a texture and copy + * depth values to a safe place before clearing it. Then once the frame is + * rendered, the scheduler compares the saved depths with the current z-buffer + * and updates the artifact, applying the minimum of the two depths. + * + * The scheduler maintains 3 arrays of artifacts, each referenced by indexes + * which rotate between them. + * - Artifacts are written by the main thread using the write index. + * The write and front indexes are then incremented. + * - The same artifacts are updated by the scheduler using the pending index. + * The pending index is then updated. + * - The artifacts are then rendered on a later frame using the front index. + * + * In each artifacts array, the first several slots are reserved for the sun + * flare artifacts. The quantity depends on the number of suns in the stage + * (Skedar Ruins has 3) and there are 8 artifacts per sun. The remaining slots + * are used for light fixture corners. The array is big enough to handle at + * least 90 lights on screen at a time. + * + * The initial state of the indexes are write=0, front=1, pending=0. + * These are set in sched_reset_artifacts. + * + * The detailed workflow is: + * - CPU: Light artifacts are determined and added to write artifacts (0) array + * - CPU: Constructs the gdl in this order: + * - Render scene + * - Copy relevant parts of z-buffer to write depths (0) array + * - Clear z-buffer and render gun + * - Render artifacts by reading from front artifacts (1) array + * - CPU: increments write (0 -> 1) and front (1 -> 2) indexes + * - GPU: Executes above task. g_ArtifactDepths0 now contains depths, and is + * pointed to by pending. + * - Scheduler: Reads the z-buffer, which at this point only contains the gun + * depth information, and updates the artifact with the minimum of the two + * - Scheduler: Increments pending (0 -> 1) + * + * It appears that the front index should be initialised to 2 instead, so that + * it's one frame behind the others rather than two frames behind. + * + * There's no doubt this went through several iterations before landing on this + * implementation. It's likely that this was implemented using a single and full + * z-buffer and it worked well until they decided to clear the z-buffer before + * rendering the gun. There is evidence in zbuf.c that they allocated a second + * z-buffer and swapped it. But when memory got too tight they had to change it + * to this texture read method. + */ + +u8 *var800a41a0; +u32 var800a41a4; +u32 var800a41a8; +u32 var800a41ac; + +void artifactsClear(void) +{ + struct artifact *artifacts = schedGetWriteArtifacts(); + s32 i; + + for (i = 0; i < MAX_ARTIFACTS; i++) { + artifacts[i].type = ARTIFACTTYPE_FREE; + } +} + +void artifactsTick(void) +{ + schedIncrementWriteArtifacts(); + schedIncrementFrontArtifacts(); +} + +u16 floatToN64Depth(f32 arg0) +{ + /** + * Method to convert a 32 bit floating point depth value to the + * unsigned 16 bit integer format used by the zbuffer on the N64. + * The argument arg0 represents z normalized to [0, 1] * 32704.0f. + * + * It works by converting the depth value to a large, unsigned 32 bit + * integer before scaling back down to an unsigned 16 bit integer. + * The scaling is done using bit shift operations on the most & least + * significant bytes of the resulting 16 bit integer, likely because + * bit shift operations are faster than division. The segmentation of + * this calculation at values 0x3f800, 0x3f000, etc. is probably + * intended to reduce z-fighting by adding more differentiation for + * distant z values. + */ + u32 value = arg0 * 8.0f; + u32 left; // forms the most significant byte of the final u16 + u32 right = value; // forms the least significant byte of the final u16 + + if (value > 0x3f800) { + right = value & 0x7ff; + right &= 0x7ff; + left = 7; + } else if (value > 0x3f000) { + right = value & 0x7ff; + right &= 0x7ff; + left = 6; + } else if (value > 0x3e000) { + right = (value >> 1) & 0x7ff; + right &= 0x7ff; + left = 5; + } else if (value > 0x3c000) { + right = (value >> 2) & 0x7ff; + right &= 0x7ff; + left = 4; + } else if (value > 0x38000) { + right = (value >> 3) & 0x7ff; + right &= 0x7ff; + left = 3; + } else if (value > 0x30000) { + right = (value >> 4) & 0x7ff; + right &= 0x7ff; + left = 2; + } else if (value > 0x20000) { + right = (value >> 5) & 0x7ff; + right &= 0x7ff; + left = 1; + } else { + right = (value >> 6) & 0x7ff; + right &= 0x7ff; + left = 0; + } + + return left << 13 | (right << 2); +} + +s32 artifactsFloatToInt(f32 arg0) +{ + if (arg0 > 0.0f) { + if (arg0 > 2147483520.0f) { + arg0 = 2147483520; + } + } else { + if (arg0 < -2147483520) { + arg0 = -2147483520; + } + } + + return arg0; +} + +#ifndef PLATFORM_N64 + +bool artifactTestLos(struct coord *spec, struct coord *roompos, s32 xi, s32 yi) +{ + s32 i = 0; + + if (!g_Vars.currentplayer) { + return false; + } + + struct coord endpos; + endpos.x = roompos->x + spec->x; + endpos.y = roompos->y + spec->y; + endpos.z = roompos->z + spec->z; + + struct coord gundir2d; + struct coord gunpos2d = {{ 0.f, 0.f, 0.f }}; + struct coord gundir3d; + struct coord gunpos3d = g_Vars.currentplayer->cam_pos; + f32 crosspos[2] = { (f32)xi, (f32)yi }; + cam0f0b4c3c(crosspos, &gundir2d, 1.f); + mtx4RotateVec(camGetProjectionMtxF(), &gundir2d, &gundir3d); + + return shotTestLos(&gunpos2d, &gundir2d, &gunpos3d, &gundir3d, &endpos); +} + +#endif + +void artifactsCalculateGlaresForRoom(s32 roomnum) +{ + s32 i; + s32 j; + s32 k; + s32 l; + f32 f0; + s32 numlights; + f32 viewwidth; + f32 viewheight; + f32 viewleft; + f32 viewtop; + u8 *s1; + f32 x; + f32 y; + f32 f16; + f32 f20; + s32 xi; + s32 yi; + f32 sp190; + f32 brightnessfrac; + f32 thisfrac; + f32 tmp; + f32 tmp2; + f32 tmp3; + f32 sp178; + Mtxf sp138; + Mtxf spf8; + struct coord spec; + f32 spdc[4]; + struct coord origin; + struct coord spc4; + struct light *roomlights; + s32 index; + struct artifact *artifacts = schedGetWriteArtifacts(); + struct coord *campos = &g_Vars.currentplayer->cam_pos; + struct artifact *artifact; + + if (g_Rooms[roomnum].gfxdata != NULL && g_Rooms[roomnum].loaded240) { + numlights = g_Rooms[roomnum].gfxdata->numlights; + + if (numlights != 0) { + roomlights = (struct light *)&g_BgLightsFileData[g_Rooms[roomnum].gfxdata->lightsindex * 0x22]; + s1 = &var800a41a0[g_Rooms[roomnum].gfxdata->lightsindex * 3]; + + roomPopulateMtx(&sp138, roomnum); + mtx00015f88(bgGetScaleBg2Gfx(), &sp138); + mtx4MultMtx4(camGetMtxF006c(), &sp138, &spf8); + + viewwidth = viGetViewWidth(); + viewheight = viGetViewHeight(); + viewleft = viGetViewLeft(); + viewtop = viGetViewTop(); + + for (i = 0; i < numlights; i++) { + origin.x = 0.0f; + origin.y = 0.0f; + origin.z = 0.0f; + + for (j = 0; j < ARRAYCOUNT(roomlights[i].bbox); j++) { + origin.x += roomlights[i].bbox[j].x; + origin.y += roomlights[i].bbox[j].y; + origin.z += roomlights[i].bbox[j].z; + } + + origin.x /= 4.0f; + origin.y /= 4.0f; + origin.z /= 4.0f; + + for (j = 0; j != 3; j++) { + spc4.f[j] = origin.f[j] - (campos->f[j] - g_BgRooms[roomnum].pos.f[j]); + } + + s1[i * 3 + 1] = 0; + s1[i * 3 + 2] = 0; + + tmp = roomlights[i].dirx * roomlights[i].dirx + roomlights[i].diry * roomlights[i].diry + roomlights[i].dirz * roomlights[i].dirz; + f16 = spc4.f[0] * spc4.f[0] + spc4.f[1] * spc4.f[1] + spc4.f[2] * spc4.f[2]; + + if (tmp > 0.0001f && f16 > 0.0001f) { + sp190 = -((roomlights[i].dirx * spc4.f[0] + roomlights[i].diry * spc4.f[1] + roomlights[i].dirz * spc4.f[2]) / sqrtf(tmp * f16)); + + if (sp190 > 0.4f) { + sp190 = 0.4f; + } + + sp190 *= 2.5f; + } else { + sp190 = 0.0f; + } + + if (sp190 > 0.0f) { + for (l = 3; l >= 0; l--) { + spdc[l] = origin.f[0] * spf8.m[0][l] + origin.f[1] * spf8.m[1][l] + origin.f[2] * spf8.m[2][l] + spf8.m[3][l]; + + if (l == 3 && spdc[l] <= 0.0f) { + break; + } + } + + if (spdc[3] > 0.0001f) { + f20 = 1.0f / spdc[3]; + x = artifactsFloatToInt(viewleft + (1.0f + spdc[0] * f20) * (viewwidth * 0.5f)); + y = artifactsFloatToInt(viewtop + (1.0f - spdc[1] * f20) * (viewheight * 0.5f)); + f0 = (spdc[2] * f20 * 511.0f + 511.0f) * 32.0f; + + if (f0 < 32576.0f) { + brightnessfrac = 1.0f; + tmp2 = (brightnessfrac - 1.00f); + + if (x <= 10.0f + viewleft) { + brightnessfrac = 0.0f; + } else if (y <= 30.0f + viewtop) { + brightnessfrac = 0.0f; + } else if (x >= -10.0f + viewleft + viewwidth) { + brightnessfrac = 0.0f; + } else if (y >= -30.0f + viewtop + viewheight) { + brightnessfrac = 0.0f; + } + + sp178 = 1.0f - 2.0f * tmp2; + + if (brightnessfrac != 0.0f) { + brightnessfrac = 1.0f; + + if (x < viewleft + 90.0f) { + thisfrac = (x - (10.0f + viewleft)) / 80.0f; + + if (thisfrac < brightnessfrac) { + brightnessfrac = thisfrac; + } + } + + if (y < viewtop + 100.0f) { + thisfrac = (y - (viewtop + 30.0f)) / 70.0f; + + if (thisfrac < brightnessfrac) { + brightnessfrac = thisfrac; + } + } + + if (x > viewleft + viewwidth - 90.0f) { + thisfrac = (viewleft + viewwidth - 10.0f - x) / 80.0f; + + if (thisfrac < brightnessfrac) { + brightnessfrac = thisfrac; + } + } + + if (y > viewtop + viewheight - 100.0f) { + thisfrac = (viewtop + viewheight - 30.0f - y) / 70.0f; + + if (thisfrac < brightnessfrac) { + brightnessfrac = thisfrac; + } + } + } + + tmp3 = 32300.0f - f0; + + if (tmp3 < 0.0f) { + tmp3 = 0.0f; + } + + if (tmp3 > 1300.0f) { + tmp3 = 1300.0f; + } + + tmp3 *= 1.0f / 1300.0f; + + if (2.0f * tmp2 > 1.0f) { + sp178 = 0.0f; + } + + s1[i * 3 + 1] = sp190 * 255.0f * sp178; + s1[i * 3 + 2] = brightnessfrac * tmp3 * sp190 * 64.0f * 1; + } + } + } + + if (s1[i * 3 + 1] > 0) { + for (j = 0; j < ARRAYCOUNT(roomlights[i].bbox); j++) { + spec.x = origin.x + (roomlights[i].bbox[j].x - origin.x) * 0.6f; + spec.y = origin.y + (roomlights[i].bbox[j].y - origin.y) * 0.6f; + spec.z = origin.z + (roomlights[i].bbox[j].z - origin.z) * 0.6f; + + for (k = 3; k >= 0; k--) { + spdc[k] = spec.f[0] * spf8.m[0][k] + spec.f[1] * spf8.m[1][k] + spec.f[2] * spf8.m[2][k] + spf8.m[3][k]; + + if (k == 3 && spdc[k] <= 0.0f) { + break; + } + } + + if (spdc[3] > 0.0f) { + f20 = 1.0f / spdc[3]; + + if (f20 > 9999.0f) { + f20 = 9999.0f; + } + + if (f20 < -9999.0f) { + f20 = -9999.0f; + } + + xi = artifactsFloatToInt(viewleft + (1.0f + spdc[0] * f20) * (viewwidth * 0.5f)); + yi = artifactsFloatToInt(viewtop + (1.0f - spdc[1] * f20) * (viewheight * 0.5f)); + f0 = (spdc[2] * f20 * 511.0f + 511.0f) * 32.0f; + + if (g_ZbufPtr1 + && xi >= (s32)viewleft + && xi < (s32)(viewleft + viewwidth) + && yi >= (s32)viewtop + && yi < (s32)(viewtop + viewheight) + && f0 < 32576.0f) { + index = envGetCurrent()->numsuns; + index *= 8; + artifact = artifacts; + artifact += index; + + while (artifact->type != ARTIFACTTYPE_FREE) { + index++; + artifact++; + } + + if (index < MAX_ARTIFACTS) { +#ifndef PLATFORM_N64 + artifact->visiblelos = artifactTestLos(&spec, &g_BgRooms[roomnum].pos, xi, yi); +#endif + /** + * the original game performs artifact depth comparison + * using the N64 depth values divided by 4. This is + * accomplished by bit shifting the N64 depth value + * to the right using >> 2 + */ + artifact->expecteddepth = floatToN64Depth(f0) >> 2; + artifact->zbufptr = &g_ZbufPtr1[viGetWidth() * yi + xi]; + artifact->light = &roomlights[i]; + artifact->type = ARTIFACTTYPE_GLARE; + artifact->screenx = xi; + artifact->screeny = yi; + } + } + } + } + } + } + } + } +} + +u8 artifactsClamp(u8 arg0, u8 arg1) +{ + if (arg1 >= arg0 + 7) { + return arg0 + 7; + } + + if (arg1 <= arg0 - 7) { + return arg0 - 7; + } + + return arg1; +} + +Gfx *artifactsConfigureForGlares(Gfx *gdl) +{ + struct stagetableentry *stage = stageGetCurrent(); + + texSelect(&gdl, &g_TexLightGlareConfigs[stage->light_type], 4, 0, 2, 1, NULL); + + gDPSetCycleType(gdl++, G_CYC_1CYCLE); + gDPSetRenderMode(gdl++, G_RM_CLD_SURF, G_RM_CLD_SURF2); + gDPSetTextureFilter(gdl++, G_TF_BILERP); + gDPSetCombineLERP(gdl++, + 0, 0, 0, ENVIRONMENT, TEXEL0, 0, ENVIRONMENT, 0, + 0, 0, 0, ENVIRONMENT, TEXEL0, 0, ENVIRONMENT, 0); + gDPSetColorDither(gdl++, G_CD_BAYER); + gDPSetAlphaDither(gdl++, G_AD_PATTERN); + gDPSetTexturePersp(gdl++, G_TP_NONE); + + return gdl; +} + +Gfx *artifactsUnconfigureForGlares(Gfx *gdl) +{ + gDPSetTexturePersp(gdl++, G_TP_PERSP); + + return gdl; +} + +Gfx *artifactsRenderGlaresForRoom(Gfx *gdl, s32 roomnum) +{ + s32 i; + s32 j; + s32 lightindex; + struct artifact *artifacts; + u16 min; + u16 max; + f32 lightop_cur_frac; + s32 numgood; + struct light *light; + u8 *s3; + s32 k; + s32 count; + u16 actualdepth; + f32 add; + s32 l; + f32 brightness; + s32 tolerance; + f32 f0; + s32 difference; + s32 r; + s32 g; + s32 b; + s32 stack; + u8 colour[4]; + s16 lightroompos[3]; + struct coord lightworldpos; + struct coord lightscreenpos; + f32 spdc[2]; + f32 spd4[2]; + f32 f24; + bool extra; + f32 f26; + + artifacts = schedGetFrontArtifacts(); + lightop_cur_frac = roomGetLightOpCurFrac(roomnum); + + if (g_Rooms[roomnum].gfxdata == NULL || g_Rooms[roomnum].loaded240 == 0) { + return gdl; + } + + for (i = envGetCurrent()->numsuns * 8; i < MAX_ARTIFACTS; i++) { + struct light *light2 = artifacts[i].light; + count = 0; + + /** + * light arifacts are created from several, closely spaced + * textures that give the appearance of a dynamic light glare + * as the character moves. Loop to count all the sub-artifacts + * in this light. + */ + for (j = i; j < MAX_ARTIFACTS && artifacts[j].type == ARTIFACTTYPE_GLARE && artifacts[j].light == light2; j++) { + count++; + } + + light = artifacts[i].light; + + if (count > 0) { + if (roomnum == light->roomnum) { + lightindex = ((uintptr_t)light - (uintptr_t)g_BgLightsFileData) / sizeof(struct light); + s3 = &var800a41a0[lightindex * 3]; + numgood = 0; + min = 0xffff; + max = 0; + + /** + * loop to determine the min & max depth of + * the sub-artifacts composing this room light. + */ + for (k = i; k < i + count; k++) { + if (artifacts[k].expecteddepth > max) { + max = artifacts[k].expecteddepth; + } + + if (artifacts[k].expecteddepth < min) { + min = artifacts[k].expecteddepth; + } + } + + /** + * Define a depth tolerance from the min & max + * depths of sub-artifacts for a given light. + * This will be used to determine which light + * artifacts are visible when comparing depth + * values of lights to other items rendered + * on screen. Without this, the lights would + * constantly flicker due to z-fighting caused + * by the low precision of the N64 depth. + */ + tolerance = (max - min) >> 1; + + if (tolerance < 25) { + tolerance = 25; + } + + for (k = i; k < i + count; k++) { + u16 expecteddepth; + actualdepth = (artifacts[k].actualdepth & 0xfffc) >> 2; + expecteddepth = artifacts[k].expecteddepth; + + if (expecteddepth < actualdepth) { + difference = actualdepth - expecteddepth; + } else { + difference = expecteddepth - actualdepth; + } + +#ifdef PLATFORM_N64 + if (difference <= tolerance) { + numgood++; + } +#else + numgood += artifacts[k].visiblelos; +#endif + + artifacts[k].type = ARTIFACTTYPE_FREE; + } + + s3[0] = artifactsClamp(s3[0], numgood * 2); + + if (numgood > 0) { + brightness = viGetFovY() * 0.017453292f; + add = cosf(brightness) / sinf(brightness) * 14.6f; + + if (lightIsHealthy(roomnum, lightindex - g_Rooms[roomnum].gfxdata->lightsindex)) { + if (!lightIsOn(roomnum, lightindex - g_Rooms[roomnum].gfxdata->lightsindex)) { + continue; + } + + brightness = 1.0f; + } else if (lightTickBroken(roomnum, lightindex - g_Rooms[roomnum].gfxdata->lightsindex)) { + brightness = 0.4f; + } else { + continue; + } + + r = ((light->colour >> 12) & 0xf) * 17; + g = ((light->colour >> 8) & 0xf) * 17; + b = ((light->colour >> 4) & 0xf) * 17; + + if ((r == 0xff && g == 0xff && b == 0xff) || (r == 0xff && g + b < 35)) { + extra = false; + } else { + extra = true; + } + + if (USINGDEVICE(DEVICE_NIGHTVISION)) { + s3[2] *= (s32) (lightop_cur_frac * 7.0f); + } + + f0 = s3[2] * (1.0f / 255.0f); + + skySetOverexposure((s32) ((f32)f0 * r), (s32) ((f32)f0 * g), (s32) ((f32)f0 * b)); + + for (l = 0; l < 3; l++) { + lightroompos[l] = (light->bbox[0].s[l] + light->bbox[1].s[l] + light->bbox[2].s[l] + light->bbox[3].s[l]) / 4; + lightworldpos.f[l] = lightroompos[l] + g_BgRooms[roomnum].pos.f[l]; + lightscreenpos.f[l] = lightworldpos.f[l] - g_Vars.currentplayer->cam_pos.f[l]; + } + + mtx4RotateVecInPlace(camGetWorldToScreenMtxf(), &lightscreenpos); + + cam0f0b4d04(&lightscreenpos, spdc); + + brightness *= 27500.0f / (-lightscreenpos.z < 1.0f ? 1.0f : -lightscreenpos.z); + + if (light->brightnessmult != 0) { + brightness *= light->brightnessmult * (1.0f / 32.0f); + } + + brightness *= s3[1] * (1.0f / 255.0f); + + if (USINGDEVICE(DEVICE_NIGHTVISION)) { + brightness *= 14.0f * lightop_cur_frac; + } + + brightness += add; + brightness *= 2.0f * roomGetSettledLocalBrightnessFrac(roomnum); + + if (brightness > 750.0f) { + brightness = 750.0f; + } + + f24 = stageGetCurrent()->light_width * brightness * 0.01f; + f26 = stageGetCurrent()->light_height * brightness * 0.01f; + + f24 *= viGetViewWidth() * (1.0f / 240.0f) / camGetPerspAspect(); + f26 *= viGetViewHeight() * (1.0f / 240.0f); + + if (brightness > 3.0f) { + f32 alpha = (light->colour & 0xf) * 17; + + colour[0] = r; + colour[1] = g; + colour[2] = b; + + alpha *= stageGetCurrent()->light_alpha / 255.0f; + alpha *= (s3[1] / 255.0f); + alpha *= (s3[0] / 8.0f); + + if (USINGDEVICE(DEVICE_NIGHTVISION)) { + alpha *= lightop_cur_frac * 7.0f; + } + + if (alpha > 255.0f) { + alpha = 255.0f; + } + + colour[3] = alpha; + + gDPSetEnvColor(gdl++, colour[0], colour[1], colour[2], colour[3]); + + spd4[0] = f24; + spd4[1] = f26; + + func0f0b2740(&gdl, spdc, spd4, 64, 64, false, false, false, 1); + + if (extra) { + colour[0] = 0xff; + colour[1] = 0xff; + colour[2] = 0xff; + colour[3] = stageGetCurrent()->light_alpha; + colour[3] = s3[0] * colour[3] / 8; + + gDPSetEnvColor(gdl++, colour[0], colour[1], colour[2], colour[3]); + + spd4[0] = f24 * 0.4f; + spd4[1] = f26 * 0.4f; + + func0f0b2740(&gdl, spdc, spd4, 64, 64, false, false, false, 1); + } + } + } + + s3[1] = 0; + s3[2] = 0; + } + + // This is incrementing i past all the artifacts for this particular + // light, then subtracting 1 because the for loop will add 1. + i = i + count - 1; + } + } + + return gdl; +} diff --git a/src/game/bg.c b/src/game/bg.c index 2a3bab3dc..d1569bdc4 100644 --- a/src/game/bg.c +++ b/src/game/bg.c @@ -15,7 +15,7 @@ #include "game/sky.h" #include "game/stars.h" #include "game/dyntex.h" -#include "game/game_13c510.h" +#include "game/artifact.h" #include "game/game_1531a0.h" #include "game/gfxmemory.h" #include "game/gfxreplace.h" diff --git a/src/game/bondgun.c b/src/game/bondgun.c index a46e66721..7415bf851 100644 --- a/src/game/bondgun.c +++ b/src/game/bondgun.c @@ -10956,7 +10956,7 @@ void bgunRender(Gfx **gdlptr) return; } -#ifdef PLATFORM_N64 +#ifdef PLATFORM_N64 // TODO gdl = zbufSaveArtifactDepths(gdl); #endif gdl = viPrepareZbuf(gdl); diff --git a/src/game/lv.c b/src/game/lv.c index 56d9e9ab3..8db23f155 100644 --- a/src/game/lv.c +++ b/src/game/lv.c @@ -28,7 +28,7 @@ #include "game/portal.h" #include "game/fmb.h" #include "game/sky.h" -#include "game/game_13c510.h" +#include "game/artifact.h" #include "game/game_1531a0.h" #include "game/zbuf.h" #include "game/challenge.h" diff --git a/src/game/sky.c b/src/game/sky.c index d5252919c..f2b276f10 100644 --- a/src/game/sky.c +++ b/src/game/sky.c @@ -17,7 +17,7 @@ #ifndef PLATFORM_N64 #include "video.h" #include "game/gfxmemory.h" -#include "game/game_13c510.h" +#include "game/artifact.h" #include "game/player.h" #endif diff --git a/src/include/game/artifact.h b/src/include/game/artifact.h new file mode 100644 index 000000000..9feae2a18 --- /dev/null +++ b/src/include/game/artifact.h @@ -0,0 +1,20 @@ +#ifndef _IN_GAME_GAME_13C510_H +#define _IN_GAME_GAME_13C510_H +#include +#include "data.h" +#include "types.h" + +void artifactsClear(void); +void artifactsTick(void); +u16 floatToN64Depth(f32 arg0); +s32 artifactsFloatToInt(f32 arg0); +void artifactsCalculateGlaresForRoom(s32 roomnum); +u8 artifactsClamp(u8 arg0, u8 arg1); +Gfx *artifactsConfigureForGlares(Gfx *gdl); +Gfx *artifactsUnconfigureForGlares(Gfx *gdl); +Gfx *artifactsRenderGlaresForRoom(Gfx *gdl, s32 roomnum); +#ifndef PLATFORM_N64 +bool artifactTestLos(struct coord *spec, struct coord *roompos, s32 xi, s32 yi); +#endif + +#endif From 86e6e547922c11f995f51a326e44d5684fa253b8 Mon Sep 17 00:00:00 2001 From: joshuarwood Date: Sun, 11 May 2025 12:22:01 -0500 Subject: [PATCH 7/8] return ifdef to original position following the debugging tests --- src/game/artifact.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game/artifact.c b/src/game/artifact.c index 03dae835d..390c161a6 100644 --- a/src/game/artifact.c +++ b/src/game/artifact.c @@ -595,6 +595,7 @@ Gfx *artifactsRenderGlaresForRoom(Gfx *gdl, s32 roomnum) } for (k = i; k < i + count; k++) { +#ifdef PLATFORM_N64 u16 expecteddepth; actualdepth = (artifacts[k].actualdepth & 0xfffc) >> 2; expecteddepth = artifacts[k].expecteddepth; @@ -605,7 +606,6 @@ Gfx *artifactsRenderGlaresForRoom(Gfx *gdl, s32 roomnum) difference = expecteddepth - actualdepth; } -#ifdef PLATFORM_N64 if (difference <= tolerance) { numgood++; } From 2d59929261513570a1738ffe573b422c8cd673a0 Mon Sep 17 00:00:00 2001 From: joshuarwood Date: Sun, 11 May 2025 12:23:32 -0500 Subject: [PATCH 8/8] syncing moved files --- src/game/game_13c510.c | 746 --------------------------------- src/include/game/game_13c510.h | 20 - 2 files changed, 766 deletions(-) delete mode 100644 src/game/game_13c510.c delete mode 100644 src/include/game/game_13c510.h diff --git a/src/game/game_13c510.c b/src/game/game_13c510.c deleted file mode 100644 index 4dde60b57..000000000 --- a/src/game/game_13c510.c +++ /dev/null @@ -1,746 +0,0 @@ -#include -#include "lib/sched.h" -#include "constants.h" -#include "game/camera.h" -#include "game/dlights.h" -#include "game/env.h" -#include "game/game_0b2150.h" -#include "game/tex.h" -#include "game/sky.h" -#include "game/game_13c510.h" -#include "game/bg.h" -#include "game/stagetable.h" -#include "game/room.h" -#include "bss.h" -#include "lib/vi.h" -#include "lib/mtx.h" -#include "data.h" -#include "types.h" -#ifndef PLATFORM_N64 -#include "lib/collision.h" -#include "lib/lib_17ce0.h" -#include "game/player.h" -#include "game/prop.h" -#endif - -/** - * Artifacts are points of interest in the z-buffer. - * - * They correspond to: - * - Individual circles in the lens flare effect from the sun. - * - Individual corners of each light fixture's box. - * - * The game needs to do line of sight checks to these points. The collision - * system would normally be used for line of sight checks, but it only works - * with basic geometric volumes and also doesn't take into account the player's - * gun. Instead, the checks are done by reading from the previous frame's - * z-buffer. - * - * Typically, the z-buffer would be read by the scheduler after a graphics frame - * is rendered, but this only works if the z-buffer is a complete image. - * PD draws the scene, then clears the z-buffer before drawing the player's gun, - * so the z-buffer at the end only contains the player's gun. To work around - * this, the GPU is given commands to read the z-buffer as a texture and copy - * depth values to a safe place before clearing it. Then once the frame is - * rendered, the scheduler compares the saved depths with the current z-buffer - * and updates the artifact, applying the minimum of the two depths. - * - * The scheduler maintains 3 arrays of artifacts, each referenced by indexes - * which rotate between them. - * - Artifacts are written by the main thread using the write index. - * The write and front indexes are then incremented. - * - The same artifacts are updated by the scheduler using the pending index. - * The pending index is then updated. - * - The artifacts are then rendered on a later frame using the front index. - * - * In each artifacts array, the first several slots are reserved for the sun - * flare artifacts. The quantity depends on the number of suns in the stage - * (Skedar Ruins has 3) and there are 8 artifacts per sun. The remaining slots - * are used for light fixture corners. The array is big enough to handle at - * least 90 lights on screen at a time. - * - * The initial state of the indexes are write=0, front=1, pending=0. - * These are set in sched_reset_artifacts. - * - * The detailed workflow is: - * - CPU: Light artifacts are determined and added to write artifacts (0) array - * - CPU: Constructs the gdl in this order: - * - Render scene - * - Copy relevant parts of z-buffer to write depths (0) array - * - Clear z-buffer and render gun - * - Render artifacts by reading from front artifacts (1) array - * - CPU: increments write (0 -> 1) and front (1 -> 2) indexes - * - GPU: Executes above task. g_ArtifactDepths0 now contains depths, and is - * pointed to by pending. - * - Scheduler: Reads the z-buffer, which at this point only contains the gun - * depth information, and updates the artifact with the minimum of the two - * - Scheduler: Increments pending (0 -> 1) - * - * It appears that the front index should be initialised to 2 instead, so that - * it's one frame behind the others rather than two frames behind. - * - * There's no doubt this went through several iterations before landing on this - * implementation. It's likely that this was implemented using a single and full - * z-buffer and it worked well until they decided to clear the z-buffer before - * rendering the gun. There is evidence in zbuf.c that they allocated a second - * z-buffer and swapped it. But when memory got too tight they had to change it - * to this texture read method. - */ - -u8 *var800a41a0; -u32 var800a41a4; -u32 var800a41a8; -u32 var800a41ac; - -void artifactsClear(void) -{ - struct artifact *artifacts = schedGetWriteArtifacts(); - s32 i; - - for (i = 0; i < MAX_ARTIFACTS; i++) { - artifacts[i].type = ARTIFACTTYPE_FREE; - } -} - -void artifactsTick(void) -{ - schedIncrementWriteArtifacts(); - schedIncrementFrontArtifacts(); -} - -u16 floatToN64Depth(f32 arg0) -{ - /** - * Method to convert a 32 bit floating point depth value to the - * unsigned 16 bit integer format used by the zbuffer on the N64. - * The argument arg0 represents z normalized to [0, 1] * 32704.0f. - * - * It works by converting the depth value to a large, unsigned 32 bit - * integer before scaling back down to an unsigned 16 bit integer. - * The scaling is done using bit shift operations on the most & least - * significant bytes of the resulting 16 bit integer, likely because - * bit shift operations are faster than division. The segmentation of - * this calculation at values 0x3f800, 0x3f000, etc. is probably - * intended to reduce z-fighting by adding more differentiation for - * distant z values. - */ - u32 value = arg0 * 8.0f; - u32 left; // forms the most significant byte of the final u16 - u32 right = value; // forms the least significant byte of the final u16 - - if (value > 0x3f800) { - right = value & 0x7ff; - right &= 0x7ff; - left = 7; - } else if (value > 0x3f000) { - right = value & 0x7ff; - right &= 0x7ff; - left = 6; - } else if (value > 0x3e000) { - right = (value >> 1) & 0x7ff; - right &= 0x7ff; - left = 5; - } else if (value > 0x3c000) { - right = (value >> 2) & 0x7ff; - right &= 0x7ff; - left = 4; - } else if (value > 0x38000) { - right = (value >> 3) & 0x7ff; - right &= 0x7ff; - left = 3; - } else if (value > 0x30000) { - right = (value >> 4) & 0x7ff; - right &= 0x7ff; - left = 2; - } else if (value > 0x20000) { - right = (value >> 5) & 0x7ff; - right &= 0x7ff; - left = 1; - } else { - right = (value >> 6) & 0x7ff; - right &= 0x7ff; - left = 0; - } - - return left << 13 | (right << 2); -} - -s32 func0f13c710(f32 arg0) -{ - if (arg0 > 0.0f) { - if (arg0 > 2147483520.0f) { - arg0 = 2147483520; - } - } else { - if (arg0 < -2147483520) { - arg0 = -2147483520; - } - } - - return arg0; -} - -#ifndef PLATFORM_N64 - -bool artifactTestLos(struct coord *spec, struct coord *roompos, s32 xi, s32 yi) -{ - s32 i = 0; - - if (!g_Vars.currentplayer) { - return false; - } - - struct coord endpos; - endpos.x = roompos->x + spec->x; - endpos.y = roompos->y + spec->y; - endpos.z = roompos->z + spec->z; - - struct coord gundir2d; - struct coord gunpos2d = {{ 0.f, 0.f, 0.f }}; - struct coord gundir3d; - struct coord gunpos3d = g_Vars.currentplayer->cam_pos; - f32 crosspos[2] = { (f32)xi, (f32)yi }; - cam0f0b4c3c(crosspos, &gundir2d, 1.f); - mtx4RotateVec(camGetProjectionMtxF(), &gundir2d, &gundir3d); - - return shotTestLos(&gunpos2d, &gundir2d, &gunpos3d, &gundir3d, &endpos); -} - -#endif - -void artifactsCalculateGlaresForRoom(s32 roomnum) -{ - s32 i; - s32 j; - s32 k; - s32 l; - f32 f0; - s32 numlights; - f32 viewwidth; - f32 viewheight; - f32 viewleft; - f32 viewtop; - u8 *s1; - f32 x; - f32 y; - f32 f16; - f32 f20; - s32 xi; - s32 yi; - f32 sp190; - f32 brightnessfrac; - f32 thisfrac; - f32 tmp; - f32 tmp2; - f32 tmp3; - f32 sp178; - Mtxf sp138; - Mtxf spf8; - struct coord spec; - f32 spdc[4]; - struct coord origin; - struct coord spc4; - struct light *roomlights; - s32 index; - struct artifact *artifacts = schedGetWriteArtifacts(); - struct coord *campos = &g_Vars.currentplayer->cam_pos; - struct artifact *artifact; - - if (g_Rooms[roomnum].gfxdata != NULL && g_Rooms[roomnum].loaded240) { - numlights = g_Rooms[roomnum].gfxdata->numlights; - - if (numlights != 0) { - roomlights = (struct light *)&g_BgLightsFileData[g_Rooms[roomnum].gfxdata->lightsindex * 0x22]; - s1 = &var800a41a0[g_Rooms[roomnum].gfxdata->lightsindex * 3]; - - roomPopulateMtx(&sp138, roomnum); - mtx00015f88(bgGetScaleBg2Gfx(), &sp138); - mtx4MultMtx4(camGetMtxF006c(), &sp138, &spf8); - - viewwidth = viGetViewWidth(); - viewheight = viGetViewHeight(); - viewleft = viGetViewLeft(); - viewtop = viGetViewTop(); - - for (i = 0; i < numlights; i++) { - origin.x = 0.0f; - origin.y = 0.0f; - origin.z = 0.0f; - - for (j = 0; j < ARRAYCOUNT(roomlights[i].bbox); j++) { - origin.x += roomlights[i].bbox[j].x; - origin.y += roomlights[i].bbox[j].y; - origin.z += roomlights[i].bbox[j].z; - } - - origin.x /= 4.0f; - origin.y /= 4.0f; - origin.z /= 4.0f; - - for (j = 0; j != 3; j++) { - spc4.f[j] = origin.f[j] - (campos->f[j] - g_BgRooms[roomnum].pos.f[j]); - } - - s1[i * 3 + 1] = 0; - s1[i * 3 + 2] = 0; - - tmp = roomlights[i].dirx * roomlights[i].dirx + roomlights[i].diry * roomlights[i].diry + roomlights[i].dirz * roomlights[i].dirz; - f16 = spc4.f[0] * spc4.f[0] + spc4.f[1] * spc4.f[1] + spc4.f[2] * spc4.f[2]; - - if (tmp > 0.0001f && f16 > 0.0001f) { - sp190 = -((roomlights[i].dirx * spc4.f[0] + roomlights[i].diry * spc4.f[1] + roomlights[i].dirz * spc4.f[2]) / sqrtf(tmp * f16)); - - if (sp190 > 0.4f) { - sp190 = 0.4f; - } - - sp190 *= 2.5f; - } else { - sp190 = 0.0f; - } - - if (sp190 > 0.0f) { - for (l = 3; l >= 0; l--) { - spdc[l] = origin.f[0] * spf8.m[0][l] + origin.f[1] * spf8.m[1][l] + origin.f[2] * spf8.m[2][l] + spf8.m[3][l]; - - if (l == 3 && spdc[l] <= 0.0f) { - break; - } - } - - if (spdc[3] > 0.0001f) { - f20 = 1.0f / spdc[3]; - x = func0f13c710(viewleft + (1.0f + spdc[0] * f20) * (viewwidth * 0.5f)); - y = func0f13c710(viewtop + (1.0f - spdc[1] * f20) * (viewheight * 0.5f)); - f0 = (spdc[2] * f20 * 511.0f + 511.0f) * 32.0f; - - if (f0 < 32576.0f) { - brightnessfrac = 1.0f; - tmp2 = (brightnessfrac - 1.00f); - - if (x <= 10.0f + viewleft) { - brightnessfrac = 0.0f; - } else if (y <= 30.0f + viewtop) { - brightnessfrac = 0.0f; - } else if (x >= -10.0f + viewleft + viewwidth) { - brightnessfrac = 0.0f; - } else if (y >= -30.0f + viewtop + viewheight) { - brightnessfrac = 0.0f; - } - - sp178 = 1.0f - 2.0f * tmp2; - - if (brightnessfrac != 0.0f) { - brightnessfrac = 1.0f; - - if (x < viewleft + 90.0f) { - thisfrac = (x - (10.0f + viewleft)) / 80.0f; - - if (thisfrac < brightnessfrac) { - brightnessfrac = thisfrac; - } - } - - if (y < viewtop + 100.0f) { - thisfrac = (y - (viewtop + 30.0f)) / 70.0f; - - if (thisfrac < brightnessfrac) { - brightnessfrac = thisfrac; - } - } - - if (x > viewleft + viewwidth - 90.0f) { - thisfrac = (viewleft + viewwidth - 10.0f - x) / 80.0f; - - if (thisfrac < brightnessfrac) { - brightnessfrac = thisfrac; - } - } - - if (y > viewtop + viewheight - 100.0f) { - thisfrac = (viewtop + viewheight - 30.0f - y) / 70.0f; - - if (thisfrac < brightnessfrac) { - brightnessfrac = thisfrac; - } - } - } - - tmp3 = 32300.0f - f0; - - if (tmp3 < 0.0f) { - tmp3 = 0.0f; - } - - if (tmp3 > 1300.0f) { - tmp3 = 1300.0f; - } - - tmp3 *= 1.0f / 1300.0f; - - if (2.0f * tmp2 > 1.0f) { - sp178 = 0.0f; - } - - s1[i * 3 + 1] = sp190 * 255.0f * sp178; - s1[i * 3 + 2] = brightnessfrac * tmp3 * sp190 * 64.0f * 1; - } - } - } - - if (s1[i * 3 + 1] > 0) { - for (j = 0; j < ARRAYCOUNT(roomlights[i].bbox); j++) { - spec.x = origin.x + (roomlights[i].bbox[j].x - origin.x) * 0.6f; - spec.y = origin.y + (roomlights[i].bbox[j].y - origin.y) * 0.6f; - spec.z = origin.z + (roomlights[i].bbox[j].z - origin.z) * 0.6f; - - for (k = 3; k >= 0; k--) { - spdc[k] = spec.f[0] * spf8.m[0][k] + spec.f[1] * spf8.m[1][k] + spec.f[2] * spf8.m[2][k] + spf8.m[3][k]; - - if (k == 3 && spdc[k] <= 0.0f) { - break; - } - } - - if (spdc[3] > 0.0f) { - f20 = 1.0f / spdc[3]; - - if (f20 > 9999.0f) { - f20 = 9999.0f; - } - - if (f20 < -9999.0f) { - f20 = -9999.0f; - } - - xi = func0f13c710(viewleft + (1.0f + spdc[0] * f20) * (viewwidth * 0.5f)); - yi = func0f13c710(viewtop + (1.0f - spdc[1] * f20) * (viewheight * 0.5f)); - f0 = (spdc[2] * f20 * 511.0f + 511.0f) * 32.0f; - - if (g_ZbufPtr1 - && xi >= (s32)viewleft - && xi < (s32)(viewleft + viewwidth) - && yi >= (s32)viewtop - && yi < (s32)(viewtop + viewheight) - && f0 < 32576.0f) { - index = envGetCurrent()->numsuns; - index *= 8; - artifact = artifacts; - artifact += index; - - while (artifact->type != ARTIFACTTYPE_FREE) { - index++; - artifact++; - } - - if (index < MAX_ARTIFACTS) { -#ifndef PLATFORM_N64 - artifact->visiblelos = artifactTestLos(&spec, &g_BgRooms[roomnum].pos, xi, yi); -#endif - /** - * the game performs artifact depth comparison using - * the original N64 depth values divided by 4, which - * is accomplished by bit shifting the N64 depth value - * to the right using >> 2 - */ - artifact->expecteddepth = floatToN64Depth(f0) >> 2; - artifact->zbufptr = &g_ZbufPtr1[viGetWidth() * yi + xi]; - artifact->light = &roomlights[i]; - artifact->type = ARTIFACTTYPE_GLARE; - artifact->screenx = xi; - artifact->screeny = yi; - } - } - } - } - } - } - } - } -} - -u8 artifactsClamp(u8 arg0, u8 arg1) -{ - if (arg1 >= arg0 + 7) { - return arg0 + 7; - } - - if (arg1 <= arg0 - 7) { - return arg0 - 7; - } - - return arg1; -} - -Gfx *artifactsConfigureForGlares(Gfx *gdl) -{ - struct stagetableentry *stage = stageGetCurrent(); - - texSelect(&gdl, &g_TexLightGlareConfigs[stage->light_type], 4, 0, 2, 1, NULL); - - gDPSetCycleType(gdl++, G_CYC_1CYCLE); - gDPSetRenderMode(gdl++, G_RM_CLD_SURF, G_RM_CLD_SURF2); - gDPSetTextureFilter(gdl++, G_TF_BILERP); - gDPSetCombineLERP(gdl++, - 0, 0, 0, ENVIRONMENT, TEXEL0, 0, ENVIRONMENT, 0, - 0, 0, 0, ENVIRONMENT, TEXEL0, 0, ENVIRONMENT, 0); - gDPSetColorDither(gdl++, G_CD_BAYER); - gDPSetAlphaDither(gdl++, G_AD_PATTERN); - gDPSetTexturePersp(gdl++, G_TP_NONE); - - return gdl; -} - -Gfx *artifactsUnconfigureForGlares(Gfx *gdl) -{ - gDPSetTexturePersp(gdl++, G_TP_PERSP); - - return gdl; -} - -Gfx *artifactsRenderGlaresForRoom(Gfx *gdl, s32 roomnum) -{ - s32 i; - s32 j; - s32 lightindex; - struct artifact *artifacts; - u16 min; - u16 max; - f32 lightop_cur_frac; - s32 numgood; - struct light *light; - u8 *s3; - s32 k; - s32 count; - u16 actualdepth; - f32 add; - s32 l; - f32 brightness; - s32 tolerance; - f32 f0; - s32 difference; - s32 r; - s32 g; - s32 b; - s32 stack; - u8 colour[4]; - s16 lightroompos[3]; - struct coord lightworldpos; - struct coord lightscreenpos; - f32 spdc[2]; - f32 spd4[2]; - f32 f24; - bool extra; - f32 f26; - - artifacts = schedGetFrontArtifacts(); - lightop_cur_frac = roomGetLightOpCurFrac(roomnum); - - if (g_Rooms[roomnum].gfxdata == NULL || g_Rooms[roomnum].loaded240 == 0) { - return gdl; - } - - for (i = envGetCurrent()->numsuns * 8; i < MAX_ARTIFACTS; i++) { - struct light *light2 = artifacts[i].light; - count = 0; - - /** - * light arifacts are created from several, closely spaced - * textures that give the appearance of a dynamic light glare - * as the character moves. Loop to count all the sub-artifacts - * in this light. - */ - for (j = i; j < MAX_ARTIFACTS && artifacts[j].type == ARTIFACTTYPE_GLARE && artifacts[j].light == light2; j++) { - count++; - } - - light = artifacts[i].light; - - if (count > 0) { - if (roomnum == light->roomnum) { - lightindex = ((uintptr_t)light - (uintptr_t)g_BgLightsFileData) / sizeof(struct light); - s3 = &var800a41a0[lightindex * 3]; - numgood = 0; - min = 0xffff; - max = 0; - - /** - * loop to determine the min & max depth of - * the sub-artifacts composing this room light. - */ - for (k = i; k < i + count; k++) { - if (artifacts[k].expecteddepth > max) { - max = artifacts[k].expecteddepth; - } - - if (artifacts[k].expecteddepth < min) { - min = artifacts[k].expecteddepth; - } - } - - /** - * Define a depth tolerance from the min & max - * depths of sub-artifacts for a given light. - * This will be used to determine which light - * artifacts are visible when comparing depth - * values of lights to other items rendered - * on screen. Without this, the lights would - * constantly flicker due to z-fighting caused - * by the low precision of the N64 depth. - */ - tolerance = (max - min) >> 1; - - if (tolerance < 25) { - tolerance = 25; - } - - for (k = i; k < i + count; k++) { - u16 expecteddepth; - actualdepth = (artifacts[k].actualdepth & 0xfffc) >> 2; - expecteddepth = artifacts[k].expecteddepth; - - if (expecteddepth < actualdepth) { - difference = actualdepth - expecteddepth; - } else { - difference = expecteddepth - actualdepth; - } - -#ifdef PLATFORM_N64 - if (difference <= tolerance) { - numgood++; - } -#else - numgood += artifacts[k].visiblelos; -#endif - - artifacts[k].type = ARTIFACTTYPE_FREE; - } - - s3[0] = artifactsClamp(s3[0], numgood * 2); - - if (numgood > 0) { - brightness = viGetFovY() * 0.017453292f; - add = cosf(brightness) / sinf(brightness) * 14.6f; - - if (lightIsHealthy(roomnum, lightindex - g_Rooms[roomnum].gfxdata->lightsindex)) { - if (!lightIsOn(roomnum, lightindex - g_Rooms[roomnum].gfxdata->lightsindex)) { - continue; - } - - brightness = 1.0f; - } else if (lightTickBroken(roomnum, lightindex - g_Rooms[roomnum].gfxdata->lightsindex)) { - brightness = 0.4f; - } else { - continue; - } - - r = ((light->colour >> 12) & 0xf) * 17; - g = ((light->colour >> 8) & 0xf) * 17; - b = ((light->colour >> 4) & 0xf) * 17; - - if ((r == 0xff && g == 0xff && b == 0xff) || (r == 0xff && g + b < 35)) { - extra = false; - } else { - extra = true; - } - - if (USINGDEVICE(DEVICE_NIGHTVISION)) { - s3[2] *= (s32) (lightop_cur_frac * 7.0f); - } - - f0 = s3[2] * (1.0f / 255.0f); - - skySetOverexposure((s32) ((f32)f0 * r), (s32) ((f32)f0 * g), (s32) ((f32)f0 * b)); - - for (l = 0; l < 3; l++) { - lightroompos[l] = (light->bbox[0].s[l] + light->bbox[1].s[l] + light->bbox[2].s[l] + light->bbox[3].s[l]) / 4; - lightworldpos.f[l] = lightroompos[l] + g_BgRooms[roomnum].pos.f[l]; - lightscreenpos.f[l] = lightworldpos.f[l] - g_Vars.currentplayer->cam_pos.f[l]; - } - - mtx4RotateVecInPlace(camGetWorldToScreenMtxf(), &lightscreenpos); - - cam0f0b4d04(&lightscreenpos, spdc); - - brightness *= 27500.0f / (-lightscreenpos.z < 1.0f ? 1.0f : -lightscreenpos.z); - - if (light->brightnessmult != 0) { - brightness *= light->brightnessmult * (1.0f / 32.0f); - } - - brightness *= s3[1] * (1.0f / 255.0f); - - if (USINGDEVICE(DEVICE_NIGHTVISION)) { - brightness *= 14.0f * lightop_cur_frac; - } - - brightness += add; - brightness *= 2.0f * roomGetSettledLocalBrightnessFrac(roomnum); - - if (brightness > 750.0f) { - brightness = 750.0f; - } - - f24 = stageGetCurrent()->light_width * brightness * 0.01f; - f26 = stageGetCurrent()->light_height * brightness * 0.01f; - - f24 *= viGetViewWidth() * (1.0f / 240.0f) / camGetPerspAspect(); - f26 *= viGetViewHeight() * (1.0f / 240.0f); - - if (brightness > 3.0f) { - f32 alpha = (light->colour & 0xf) * 17; - - colour[0] = r; - colour[1] = g; - colour[2] = b; - - alpha *= stageGetCurrent()->light_alpha / 255.0f; - alpha *= (s3[1] / 255.0f); - alpha *= (s3[0] / 8.0f); - - if (USINGDEVICE(DEVICE_NIGHTVISION)) { - alpha *= lightop_cur_frac * 7.0f; - } - - if (alpha > 255.0f) { - alpha = 255.0f; - } - - colour[3] = alpha; - - gDPSetEnvColor(gdl++, colour[0], colour[1], colour[2], colour[3]); - - spd4[0] = f24; - spd4[1] = f26; - - func0f0b2740(&gdl, spdc, spd4, 64, 64, false, false, false, 1); - - if (extra) { - colour[0] = 0xff; - colour[1] = 0xff; - colour[2] = 0xff; - colour[3] = stageGetCurrent()->light_alpha; - colour[3] = s3[0] * colour[3] / 8; - - gDPSetEnvColor(gdl++, colour[0], colour[1], colour[2], colour[3]); - - spd4[0] = f24 * 0.4f; - spd4[1] = f26 * 0.4f; - - func0f0b2740(&gdl, spdc, spd4, 64, 64, false, false, false, 1); - } - } - } - - s3[1] = 0; - s3[2] = 0; - } - - // This is incrementing i past all the artifacts for this particular - // light, then subtracting 1 because the for loop will add 1. - i = i + count - 1; - } - } - - return gdl; -} diff --git a/src/include/game/game_13c510.h b/src/include/game/game_13c510.h deleted file mode 100644 index f84ad1395..000000000 --- a/src/include/game/game_13c510.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _IN_GAME_GAME_13C510_H -#define _IN_GAME_GAME_13C510_H -#include -#include "data.h" -#include "types.h" - -void artifactsClear(void); -void artifactsTick(void); -u16 floatToIntDepth(f32 arg0); -s32 func0f13c710(f32 arg0); -void artifactsCalculateGlaresForRoom(s32 roomnum); -u8 func0f13d3c4(u8 arg0, u8 arg1); -Gfx *artifactsConfigureForGlares(Gfx *gdl); -Gfx *artifactsUnconfigureForGlares(Gfx *gdl); -Gfx *artifactsRenderGlaresForRoom(Gfx *gdl, s32 roomnum); -#ifndef PLATFORM_N64 -bool artifactTestLos(struct coord *spec, struct coord *roompos, s32 xi, s32 yi); -#endif - -#endif