forked from Ports/goldeneye-pc-port
M-30: D154 re-audit — fix vtxoff, port bgTestBulletHitBackground G_SETTILE sibling, add GE_D154 diagnostic
Re-audited the M-28 bgTestRayIntersectionInRoom GBI-parser port (bg.c): - G_TRI1 (w1>>16/8/0 & 0xff /10) and all 12 G_TRI4 nibble recoveries cross-checked twice against the N64 #else path and the raw BE-word bit layout -- both CORRECT, no change. - BUG: vtxoff read gdl->dma.par & 0xf. The PC Gdma_le shim maps .par to bits 0-23 of word0 (packed length, 16-aligned) not the N64 byte-1 params field at bits 16-23, so vtxoff was silently 0 -> wrong vtxbase[idx] for any G_VTX batch with v0 != 0. Now ((u32)gdl->words.w0 >> 16) & 0xf. - Sibling ported: bgTestBulletHitBackground tail (post-hit G_SETTILE back-scan for tileformat/tilesize) was itself an unported raw ((u8*)gdl)[0]/[1] + 64-bit words.w0<<11>>30 parser over the same D85-widened 16-byte room DL. #ifdef PORT: opcode from bits 24-31, byte1 from bits 16-23, (u32)-forced 32-bit width for the tilesize shift. N64 path kept under #else. - Diagnostic: GE_D154=1 logs the parsed cmd / vtx-index stream (call header + per-TRI1/TRI4 idx) for the first 64 invocations so the integrator/user can eyeball the parse. Verification is playtest-gated (shoot a wall/floor on an idle machine) -- the no-input level sweep never enters this function. Build green (ntsc-final, 242/242). ABI/GBI-parse only, no game-logic change. docs/PCPortResearch.md D154 + PORT-LEARNINGS §B updated.
This commit is contained in:
1 parent
6f45df9dde
commit
75641fb0b7
3 files changed
+93
-10
No files matched your search
@@ -843,7 +843,7 @@ covers D24–D69; the log continues in §H (D32 procedure, D70–D121).
|
||||
| D141 | **Watch-menu item-model crash (M-27), exposed by D140.** Pressing Start → watch page renders → `set_enviro_fog_for_items_in_solo_watch_menu` (`gunfire.c:1620`) → `modelGetNodeRwData(&model, root)` with `root` garbage → AV reading `root->Opcode` (`model.c:478`). `gunfire.c:1720-1743` walks `bodymodel->Switches[]` (a `ModelNode*` array) with **raw byte offsets** `((u8*)Switches) + j + 0x48` / `+ 0x5c` and `j += 4` — assumes 4-byte N64 pointers. `0x48/4=18`, `0x5c/4=23`, `k=j>>2=0..4` → intent is `Switches[18+k]` and `Switches[23+k]`. PC's 8-byte stride makes the raw math read misaligned garbage → bogus non-NULL `ModelNode*`. PORT-LEARNINGS §B (raw hardcoded stride into a pointer array, cf. D128). Fix: `#ifdef PORT` uses `bodymodel->Switches[18 + (j>>2)]` / `[23 + (j>>2)]`. | FIXED (`src/game/gunfire.c`, `#ifdef PORT`). Watch page now renders (weapon page verified — mirrored text D114/D116, dark weapon model D75, both parked cosmetic). `-level_09`/`-level_20` unregressed. |
|
||||
| D150 | **Watch objective/briefing page crash (M-28).** Opening the watch → BRIEF (any subpage) or OBJECTIVES page → AV in `strcat` (`str.c:25`, `Rdi/src = 0`). The pages assemble their display text with `strcpy`/`strcat(buf, langGet(id))` (`options.c:3940-4068`, `front.c:3538-3562`, `propobj.c`). `langGet()` returns **NULL** on PC for a string bank the menu flow never loaded (D129/D143 guards — briefing/objective banks in the in-level watch flow), so `strcat(buf, NULL)` derefs NULL. On N64 those ids always resolve so the decomp never guards. Twist: `str.c`'s `strcpy/strncpy/strcat` are `__nonnull__` **builtins** to GCC, so a plain `if (src == NULL)` on the parameter is optimised away as provably-dead (verified: `-Og` elided it, no `test` in the disassembly). Fix: `#ifdef PORT` NULL guards that launder the pointer through an empty `__asm__` (`GE_IS_NULL()` / `ge_launder_ptr()`) so the check survives — NULL src → treat as empty string (blank text, not a crash), NULL dst → return. Same philosophy as the D143 textRender/textMeasure NULL guards, one layer down. Inert on N64. | FIXED (`src/str.c`, `#ifdef PORT`). Build green (`ntsc-final`); `-level_09` 600+ frames @ 91.67% unregressed. Watch-page repro is interactive — user to re-verify. PORT-LEARNINGS §C. |
|
||||
| D152 | **Mission-failed / objective-failed → permanent black screen (M-28, user bug report — LIVE process inspected, not yet fixed).** User killed Trevelyan in Facility (Ctrl = fire, no crouch bind) → failed the objective → screen faded to black and never came back; process stayed alive under `debug.ps1`. `gdb.txt` (kept running): rendering stops dead at frame 12600 (`frames=12657` frozen across 206 heartbeat dumps / ~7 real min), VI pacemaker still posts. **Deadlock on `s_imLock`** — the D147 recursive-mutex that backs `osSetIntMask`. Both consumer threads are blocked in `pthread_mutex_lock(&s_imLock)` and neither owns it: `mainThread` = `sndSetScalerApplyVolumeAllSfxSlot` → `sndApplyVolumeAllSfxSlot` → `sndSetSfxSlotVolume` → `alEvtqPostEvent` (`event.c:82`) → `osSetIntMask(OS_IM_NONE)` (`libultra.c:1232`); `amMain`/audioThread = `amHandleFrameMessage` → `alAudioFrame` → `sndPlayerVoiceHandler` → `alEvtqNextEvent` (`event.c:47`) → `osSetIntMask(OS_IM_NONE)`. `sndSetScalerApplyVolumeAllSfxSlot` is the **mission-failed audio fade-out** (ramps `g_sndSfxVolumeScale` → 0 each frame, `AL_SNDP_RELEASE_EVT` posted per active `ALSoundState` per frame) — so the fade-to-black *is* the intended fail transition, and it hammers the event queue hard enough that the `osSetIntMask` lock is left owned by a party not in the 3-thread dump (a leaked unbalanced `OS_IM_NONE` — libaudio has early-return mask paths — or a transient thread that acquired it and exited; `gdb.txt` shows `New Thread`/`exited` churn every few k frames). D147's "the decomp never blocks while holding OS_IM_NONE → cannot deadlock" assumption is **falsified** by this path. Same family as D147 / PORT-LEARNINGS §D4. | MITIGATED (`port/src/libultra.c`, M-28, `#ifdef PORT`/port-only). `osSetIntMask` is now a **self-healing** logical lock: `OS_IM_NONE`/`OS_IM_ALL` acquire/release a process-wide recursive critical section tracked by `s_imHeld`/`s_imOwner`/`s_imDepth` under a short bookkeeping mutex `s_imMx` + condvar. Normal (balanced, microsecond) audio critical sections behave exactly as the D147 recursive mutex did. A waiter that blocks **> 2 s** (`OS_IM_STUCK_NS`) concludes the holder leaked it, logs `LOG_ERROR` with the stale `s_imOwner` + the stealing caller's return address, and **steals** the section — so a leaked/unbalanced `OS_IM_NONE` (or an acquire-and-exit transient thread) can no longer wedge the game forever; worst case is a ~2 s audio hiccup + a log line naming the leak. Builds clean. Still OPEN: the exact leaking call site (find it from the `D152: ... stealing from owner=` log next time it fires) and the proper narrow fix (dedicated `ALEventQueue` lock, or restore-on-thread-exit). Regression check deferred — `-level_09`/`-level_20` both flaky under the current machine load (D117/D134), and clean `master` itself has a separate nondeterministic `-level_09` frame ~900-1400 `0xc0000005` (see below). |
|
||||
| D154 | **`bg.c` room-geometry ray/hit-test GBI parser port (M-28, WRITTEN / UNVERIFIED / UNCOMMITTED).** `bgTestRayIntersectionInRoom` (`bg.c:3331`, called by `bgTestBulletHitBackground` on every shot that resolves against background geometry) is the D135 sibling flagged since M-23: raw `((u8*)gdl)[k]` / `((u32*)gdl)[i]` byte/word indexing into what is now the 16-byte PC `Gfx` room DL (D85 `bgWidenRoomGdl` + `texLoadFromGdl`) → desync → OOB `vtxbase[idx]` / walk-off AV the first time you shoot a wall or floor. Ported `#ifdef PORT` (N64 verbatim under `#else`): `vtxoff`/`vtxbase`/`op` via the `.dma` view (matches the already-ported `bgBuildRoomVtxBounds`); G_TRI1 indices from `(w1>>16/8/0)&0xff /10`; the 12 G_TRI4 nibble extractions from `(u32)gdl->words.w0/.w1` (each mapped from the N64 byte/halfword layout — table in the code comment, cross-checked twice); both `texturenum` recoveries → `-1` (the KSEG0 `*(u16*)(w1-8)` deref is invalid for the port's converted GDLs, same as D135; texnum only picks the impact decal/sound, parked D77). Builds clean. **Verification blocked** — a no-input `GE_PCDUMP` capture never fires a bullet so it never calls this function; needs a real firefight into a wall on an idle machine (this session's box was thrashed → D153/driver crash on every run). | UNVERIFIED — build green, `#ifdef PORT` only. Next: idle-machine wall-shoot test + `-level_09` framediff, then commit. PORT-LEARNINGS §B (D135 corollary). |
|
||||
| D154 | **`bg.c` room-geometry ray/hit-test GBI parser port (M-28, WRITTEN / UNVERIFIED / UNCOMMITTED).** `bgTestRayIntersectionInRoom` (`bg.c:3331`, called by `bgTestBulletHitBackground` on every shot that resolves against background geometry) is the D135 sibling flagged since M-23: raw `((u8*)gdl)[k]` / `((u32*)gdl)[i]` byte/word indexing into what is now the 16-byte PC `Gfx` room DL (D85 `bgWidenRoomGdl` + `texLoadFromGdl`) → desync → OOB `vtxbase[idx]` / walk-off AV the first time you shoot a wall or floor. Ported `#ifdef PORT` (N64 verbatim under `#else`): `vtxoff`/`vtxbase`/`op` via the `.dma` view (matches the already-ported `bgBuildRoomVtxBounds`); G_TRI1 indices from `(w1>>16/8/0)&0xff /10`; the 12 G_TRI4 nibble extractions from `(u32)gdl->words.w0/.w1` (each mapped from the N64 byte/halfword layout — table in the code comment, cross-checked twice); both `texturenum` recoveries → `-1` (the KSEG0 `*(u16*)(w1-8)` deref is invalid for the port's converted GDLs, same as D135; texnum only picks the impact decal/sound, parked D77). Builds clean. **Verification blocked** — a no-input `GE_PCDUMP` capture never fires a bullet so it never calls this function; needs a real firefight into a wall on an idle machine (this session's box was thrashed → D153/driver crash on every run). | **M-30 re-audit + fixes (still playtest-gated for final verify).** Cross-checked the ported G_TRI1 + all 12 G_TRI4 nibble recoveries twice against the N64 `#else` and the raw BE-word bit derivation — **G_TRI1 and G_TRI4 are correct**. **Two bugs fixed:** (1) `vtxoff` — the port read `gdl->dma.par & 0xf`, but the PC `Gdma_le` shim (`port/shim/PR/gbi.h`) maps `.par` to bits 0-23 of word0 (the packed *length*, always 16-aligned) not the N64 byte-1 params field at bits 16-23, so vtxoff was silently forced to 0 (breaks any G_VTX batch with `v0 != 0`, i.e. multi-batch rooms → wrong `vtxbase[idx]` → OOB). Now `((u32)gdl->words.w0 >> 16) & 0xf`. (2) **Sibling ported** — `bgTestBulletHitBackground` tail (`bg.c:~3841`, the post-hit G_SETTILE back-scan for `tileformat`/`tilesize`) was itself an unported raw `((u8*)gdl)[0]`/`[1]` + 64-bit `words.w0 << 11 >> 30` parser over the same widened DL; wrapped `#ifdef PORT` (opcode from bits 24-31, byte1 from bits 16-23, `(u32)`-forced 32-bit width for the tilesize shift). **Diagnostic:** `GE_D154=1` → `osSyncPrintf` of the parsed cmd/vtx-index stream (call header + per-TRI1/TRI4 `idx`) for the first 64 invocations, for the user/integrator to eyeball. Build green (`ntsc-final`, 242/242). Runtime unverifiable in a worktree (no `data/`); still needs a firefight-into-wall on an idle machine + `-level_09` framediff. Confidence: HIGH on the mechanical correctness (bit-for-bit vs N64), MEDIUM that nothing else in the walk still bites. PORT-LEARNINGS §B (D135 corollary). |
|
||||
| D156 | **Facility outro-cutscene "hang" — the actual fix (M-29, user bug report, 2nd occurrence after D155).** After D155 shipped the user re-ran the playthrough and it hung again at the end of Facility — same stack (`modelSetAnimFrame2WithChrStuff` ← `modelTickAnim` ← `chrUpdateAnim` ← `chrTick` ← `playerTick` ← `propsTick` ← `lvlRender` ← `bossMainloop`) but this time **`frames=12962` frozen CONSTANT across ~200 heartbeat dumps / minutes** — a true infinite loop, not the D155 slow-catch-up spiral. Root: the `while (1)` at `model.c:3131` in `modelSetAnimFrame2WithChrStuff` steps the root-motion accumulation one anim frame at a time from `framea` (`model->animframe1`) to `frameb` (`frame`, accumulated in `modelTickAnim` as `frame += playspeed * speed` per tick). If `frameb` arrives **NaN or blown up** — a cutscene anim whose blend/transition math produces a huge/non-finite `model->speed`/`playspeed`/`timespeed` (`model.c:3436` `/ model->unkb0`, `:3477` `/ model->timespeed`, both guarded `> 0` but not against tiny values) — then `floorFloatToInt(frameb)` yields garbage, `endframe - curframe` ≈ 2^31, and the loop (each iteration: `sub_GAME_7F06D3F4` joint transform + `cosf`/`sinf` + `modelConstrainOrWrapAnimFrame`) runs effectively forever. **Likely deeper cause (unconfirmed, needs the repro):** these speed/blend fields are `Model` struct members; if this model is punned/inline (D100/D140 family) and `sizeof(Model)` growth misaligned them, they read garbage exactly when a cutscene sets an unusual anim transition. | GUARDED (`src/game/model.c`, `#ifdef PORT`): (1) in `modelSetAnimFrame2WithChrStuff`, if `frameb` is non-finite or `|frameb| >= 1e6` snap it to `framea` (loop then does ~0 iterations; the `modelConstrainOrWrapAnimFrame` at :3211 still clamps `model->frameb` to a valid frame); (2) in `modelTickAnim` after the tick loop, if `frame`/`frame2` went non-finite/absurd fall back to the pre-loop `model->animframe1`/`animframe2` so the NaN can't poison model state every frame. `!(x > -1e6f && x < 1e6f)` catches NaN too. Anim frames are 0..few-hundred so 1e6 is a safe ceiling. Verified: build green; `-level_09` frame 200 unregressed (guards never fire in normal play). **User to re-verify the Facility outro.** If it still hangs, the NaN source is upstream — dump `model->speed/playspeed/timespeed/unkb0` in `modelTickAnim` during the cutscene. PORT-LEARNINGS §E. |
|
||||
| D155 | **Facility outro-cutscene end → "hang" = unclamped `deltaFrames` spiral (M-29, user bug report).** User watched the Facility outro cutscene; at the end the game froze (process alive, kernel-heartbeat dumps). Symbolicated `mainThread` stack from the port's own hang dump: `modelConstrainOrWrapAnimFrame` ← `modelTickAnim` ← `chrUpdateAnim` ← `chrTick` ← `playerTick` ← `propsTick` ← `lvlRender`, sampled there across *every* heartbeat dump. Root cause: `waitForNextFrame()` (`src/game/frametiming.c`) sets `nextFrameTime = (osGetCount() − prev + 387937) / 775875` and passes it **unclamped** to `updateFrameCounters` as `deltaFrames`. `osGetCount()` is wall-clock on the port (D117), not VI-locked, so a real-time stall — the asset load at the cutscene→debrief boundary, made far worse by the user running a local LLM on the same box — makes `nextFrameTime` balloon to hundreds/thousands. That becomes `speedgraphframes` → `g_ClockTimer`, which drives `modelTickAnim(model, g_ClockTimer, 1)`'s `while (numticks-- > 0)` loop once per character per render, plus dozens of `for (i = 0; i < g_ClockTimer; i++)` sim loops (`bondhead.c`, `bondview2.c`, `explosion.c`, `options.c`…). One render then does thousands of anim ticks × N characters → multi-second frame → heartbeat trips, and the slow frame feeds an even bigger delta next time → unrecoverable spiral. The N64 was physically VI-bound and never produced `deltaFrames > ~2`. Timing-compensation class, cf. D117/D134. | FIXED (`src/game/frametiming.c`, `#ifdef PORT` — clamp `nextFrameTime` to `FRAMETIMING_PORT_MAX_CATCHUP` = 6). After a hitch the sim just resumes at real-time-ish pace instead of spiralling, exactly as the console did when it dropped frames under load. N64 path verbatim. Confidence: high (stack + arithmetic both point here). PORT-LEARNINGS §E. |
|
||||
| D153 | **`-level_09` frame ~900–1400 `0xc0000005` = D117/D134 load flakiness, NOT a bug (M-28).** Reproduced 6/6 while the machine was under heavy concurrent build+run load; on a **quiet** machine `-level_09` ran past frame 2400 with 0 heartbeats, no crash. Same false-positive class the docs warn about every session (M-13..M-22, M-25 Silo ~frame 300 freeze). The crash PC was in a system DLL (a `memcpy` off a buffer) and the frame varied run-to-run — both consistent with the port's host-scheduling jitter under load (`osGetCount` is wall-clock, variable-timestep sim), not a deterministic defect. `romdataFixupMusicSeqTable: seqCount 63 exceeds blob capacity 1` is an EXPECTED benign warning on the header-only first `romdataFixupMusicSeqTable` call (music.c:736; the full-size second call at :742 is silent) — not related. **Lesson: don't regression-test while builds/other runs are in flight.** | NOT A BUG — closed. Run anchors on a quiet machine. |
|
||||
|
||||
+18
-2
@@ -119,10 +119,26 @@ expressed in N64 `Gfx`/`Vtx` units is **half-size** on PC.
|
||||
`(word >> (8*(3-i))) & 0xff`). `gdl++` (advances by `sizeof(Gfx)`) is already
|
||||
correct. Watch `(s32)ptr` truncation in vtx-base math and `x | 0x80000000`
|
||||
KSEG0 folds (identity on PC — just drop the OR, and guard segmented w1).
|
||||
Instances: `bgTestHitOnObj` (`propobj.c`, FIXED); `bg.c` room-geometry
|
||||
hit-test `sub_GAME_…` (`~3373-3646`, still latent — shooting walls).
|
||||
Instances: `bgTestHitOnObj` (`propobj.c`, FIXED); `bgTestRayIntersectionInRoom`
|
||||
+ `bgTestBulletHitBackground` tail (`bg.c`, D154 — ported M-28, re-audited +
|
||||
bug-fixed M-30, playtest-gated).
|
||||
PD ground truth: `pd_port` uses `gdl->dma.cmd` + `GFX_W0_BYTE(i)`/`GFX_W1_BYTE(i)`
|
||||
macros (`3-i` / `11-i` on 64-bit LE).
|
||||
- **D154 corollary — the PC `Gdma_le` shim's `.par` is NOT the N64 params byte.**
|
||||
When porting a room/model DL GBI parser, only `.dma.cmd` is safe to read
|
||||
through the `port/shim/PR/gbi.h` `Gfx` union: that shim lays `Gdma_le` out as
|
||||
`par:24` (bits 0-23 of word0 = the *packed length* from `gDma1p`), `cmd:8`
|
||||
(bits 24-31). The N64 `Gdma` has `cmd:8` (byte 0) then `par:8` (**byte 1**,
|
||||
bits 16-23 = the `((n-1)<<4)|v0` G_VTX params). So an N64 `((u8*)gdl)[1]` /
|
||||
N64-semantics `.dma.par` becomes `((u32)gdl->words.w0 >> 16) & 0xff` on PC —
|
||||
**`gdl->dma.par` gives bits 0-23 (length), and `& 0xf` on it is always 0**
|
||||
because `len == 16*n`. The original D154 port had exactly this bug (vtxoff
|
||||
forced to 0). Same trap latent in `bgBuildRoomVtxBounds` (`gdl.dma.par>>4&0xf`
|
||||
reads PC bits 4-7, not N64 bits 20-23 — currently tolerated). Rule: for
|
||||
anything but the opcode, extract the bit-field explicitly from
|
||||
`(u32)gdl->words.w0` / `.w1`, don't trust the named `.dma.*` sub-fields.
|
||||
Also: a `words.w0 << k >> m` bit-extract idiom that relied on 32-bit
|
||||
truncation on N64 must be `(u32)`-cast first on PC (`words.w0` is 64-bit).
|
||||
- **Also bites RAW hardcoded struct-stride writes, not just Gfx/Vtx.**
|
||||
D128: `sub_GAME_7F0B37EC` did `((u8*)g_BgPortals)[(portal<<3)+6] |= 2`
|
||||
— the N64 `bg_portal_data_entry` is 8B (`ptr@0, cr1@4..cb2@7`); on PC
|
||||
|
||||
+74
-7
@@ -3386,7 +3386,13 @@ bool bgTestRayIntersectionInRoom(coord3d *from, coord3d *to, coord3d *dir, RoomV
|
||||
* texturenum recovery (a KSEG0 deref 8 bytes before the texture data) is
|
||||
* not valid for the port's converted GDLs -> return -1 like D135; it only
|
||||
* flavours the bullet-impact decal/sound (parked with D77). */
|
||||
vtxoff = gdl->dma.par & 0xf;
|
||||
/* D154 addendum (M-30): the N64 line reads BYTE 1 of word0 -- bits 16-23,
|
||||
* the G_VTX params byte ((n-1)<<4 | v0) -- so vtxoff = v0. The prior port
|
||||
* used gdl->dma.par, but the PC Gdma_le shim maps `par` to bits 0-23 of
|
||||
* word0 (the packed length field), so `& 0xf` yielded 0 (len == 16*n is
|
||||
* always 16-aligned), silently forcing vtxoff = 0. Extract byte 1
|
||||
* explicitly from the recovered 32-bit word0 instead. */
|
||||
vtxoff = ((u32)gdl->words.w0 >> 16) & 0xf;
|
||||
temp.vertices = (Vertex *)g_BgRoomInfo[roomnum].vertices;
|
||||
vtxbase = (Vertex *)((uintptr_t)temp.vertices + ((u32)gdl->words.w1 & 0x00ffffff));
|
||||
#else
|
||||
@@ -3404,6 +3410,23 @@ bool bgTestRayIntersectionInRoom(coord3d *from, coord3d *to, coord3d *dir, RoomV
|
||||
op = *((s8 *) gdl);
|
||||
#endif
|
||||
|
||||
#ifdef PORT
|
||||
/* D154 diagnostic: GE_D154=1 logs the parsed command / vtx-index stream
|
||||
* for the first 64 invocations. This function only runs when a bullet
|
||||
* resolves against background geometry, so it is invisible to the
|
||||
* no-input level sweep -- verification of the GBI parse is playtest-gated
|
||||
* (shoot a wall/floor on an idle machine and eyeball this stream). */
|
||||
{
|
||||
static s32 d154_calls = 0;
|
||||
d154_calls++;
|
||||
if (d154_calls <= 64 && getenv("GE_D154")) {
|
||||
osSyncPrintf("D154 call#%d room=%d gdlidx=%d vtxoff=%d op=%d hdr w0=%08x w1=%08x\n",
|
||||
d154_calls, (int)roomnum, (int)point->gdlindex, (int)vtxoff,
|
||||
(int)op, (unsigned)(u32)gdl[-1].words.w0, (unsigned)(u32)gdl[-1].words.w1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((op != G_VTX) && (op != ((s8) G_ENDDL)))
|
||||
{
|
||||
local.roominfo = temp.roominfo;
|
||||
@@ -3423,6 +3446,11 @@ bool bgTestRayIntersectionInRoom(coord3d *from, coord3d *to, coord3d *dir, RoomV
|
||||
idx[0] = (((u8 *) gdl)[5] / 10) - vtxoff;
|
||||
idx[1] = (((u8 *) gdl)[6] / 10) - vtxoff;
|
||||
idx[2] = (((u8 *) gdl)[7] / 10) - vtxoff;
|
||||
#endif
|
||||
#ifdef PORT
|
||||
if (getenv("GE_D154"))
|
||||
osSyncPrintf("D154 TRI1 w1=%08x idx=%d,%d,%d\n",
|
||||
(unsigned)(u32)gdl->words.w1, (int)idx[0], (int)idx[1], (int)idx[2]);
|
||||
#endif
|
||||
i = 0;
|
||||
|
||||
@@ -3604,6 +3632,12 @@ bool bgTestRayIntersectionInRoom(coord3d *from, coord3d *to, coord3d *dir, RoomV
|
||||
idx2[2] = (((u32) ((u16 *) gdl)[1]) >> 12) - vtxoff;
|
||||
}
|
||||
#endif
|
||||
#ifdef PORT
|
||||
if (getenv("GE_D154"))
|
||||
osSyncPrintf("D154 TRI4 s2=%d w0=%08x w1=%08x idx2=%d,%d,%d\n",
|
||||
(int)s2, (unsigned)(u32)gdl->words.w0, (unsigned)(u32)gdl->words.w1,
|
||||
(int)idx2[0], (int)idx2[1], (int)idx2[2]);
|
||||
#endif
|
||||
|
||||
i = 0;
|
||||
|
||||
@@ -3838,28 +3872,61 @@ bool bgTestBulletHitBackground(coord3d *from, coord3d *to, s32 roomnum, struct H
|
||||
{
|
||||
point = (RoomVtxBatchBounds *)hit->tricmd;
|
||||
|
||||
if (((u8 *)((Gfx*)point))[0] != G_SETTILE)
|
||||
#ifdef PORT
|
||||
/* D154 sibling (M-30): unported N64 GBI parser walking the same
|
||||
* D85-widened 16-byte room DL. On N64 ((u8*)gdl)[0] is the opcode
|
||||
* byte and ((u8*)gdl)[1] is byte 1 of word0; on PC those raw indices
|
||||
* read the low bytes of the 64-bit word0 (garbage). Recover the
|
||||
* opcode from bits 24-31 of the 32-bit word0, byte 1 from bits 16-23.
|
||||
* tilesize keeps the N64 (w0 << 11) >> 30 = bits 19-20 idiom but must
|
||||
* force 32-bit width first (words.w0 is 64-bit on PC). ABI/GBI-parse
|
||||
* only, no behaviour change. */
|
||||
if ((((u32)((Gfx*)point)->words.w0 >> 24) & 0xff) != G_SETTILE)
|
||||
{
|
||||
while ((Gfx *)g_BgRoomInfo[roomnum].ptr_expanded_mapping_info < ((Gfx*)point))
|
||||
while ((Gfx *)g_BgRoomInfo[roomnum].ptr_expanded_mapping_info < ((Gfx*)point))
|
||||
{
|
||||
point = (RoomVtxBatchBounds *)((Gfx *)point - 1);
|
||||
if (((u8 *)((Gfx*)point))[0] == G_SETTILE)
|
||||
if ((((u32)((Gfx*)point)->words.w0 >> 24) & 0xff) == G_SETTILE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (((Gfx*)point) == g_BgRoomInfo[roomnum].ptr_expanded_mapping_info)
|
||||
if (((Gfx*)point) == g_BgRoomInfo[roomnum].ptr_expanded_mapping_info)
|
||||
{
|
||||
hit->tileformat = -1;
|
||||
hit->tilesize = -1;
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
hit->tileformat = (((u32)((Gfx*)point)->words.w0 >> 16) & 0xff) >> 5;
|
||||
hit->tilesize = ((u32)((Gfx*)point)->words.w0 << 11) >> 30;
|
||||
}
|
||||
#else
|
||||
if (((u8 *)((Gfx*)point))[0] != G_SETTILE)
|
||||
{
|
||||
while ((Gfx *)g_BgRoomInfo[roomnum].ptr_expanded_mapping_info < ((Gfx*)point))
|
||||
{
|
||||
point = (RoomVtxBatchBounds *)((Gfx *)point - 1);
|
||||
if (((u8 *)((Gfx*)point))[0] == G_SETTILE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (((Gfx*)point) == g_BgRoomInfo[roomnum].ptr_expanded_mapping_info)
|
||||
{
|
||||
hit->tileformat = -1;
|
||||
hit->tilesize = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
hit->tileformat = ((u32)((u8 *)((Gfx*)point))[1]) >> 5;
|
||||
hit->tilesize = (((Gfx*)point)->words.w0 << 11) >> 30;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return found;
|
||||
|
||||
Reference in new issue
Block a user