forked from Ports/goldeneye-pc-port
Merge pull request #18 from jkdansereau/fix/d176a-sky-path-b
D176(a): render the sky on PC (Path B — screen-space emit)
This commit is contained in:
5 files changed
+263
-11
No files matched your search
+52
-10
@@ -47,17 +47,39 @@ this doc.
|
||||
|
||||
## Defect 1 — texcoord shear (clouds smeared into streaks)
|
||||
|
||||
`skyPortRenderPoly` uses `tc = unk20 × 32.0f` — a magic number. GBI vertex
|
||||
`tc` is **S8.8 texel** space; the real RSP path applies the sky image's tile
|
||||
shifts to the streamed S/T. Fix spec:
|
||||
`skyPortRenderPoly` uses `tc = unk20 × 32.0f` — a magic number.
|
||||
|
||||
1. Read the base-tile descriptor of the cloud image (`skywaterimages[0]`,
|
||||
GIMG offset `0xFB4` per M-36) from the extracted assets/sidecar — get W, H
|
||||
and shifts/shiftt.
|
||||
2. Cross-check against how `gfx_pc.cpp` addresses texels for a known-good
|
||||
textured DL (the working reference).
|
||||
3. Replace the magic: if streamed S/T are image fractions f ∈ [0,1), then
|
||||
`tc = f × (W << 8)` / `f × (H << 8)`. Verify on `-level_22`.
|
||||
### M-82 update — the scale is right, the magnitude is the bug
|
||||
|
||||
- **Cloud texture is `s_skywaterimages[0]` = `IMAGE_CLOUDS_GRAYSCALE`,
|
||||
`0x40 × 0x40` (64×64), `G_IM_FMT_IA` / `G_IM_SIZ_8b`, `G_TX_WRAP`/`G_TX_WRAP`**
|
||||
(`assets/oddtextures.c:646`). Not a fraction-indexed texture — it *tiles*.
|
||||
- **GE's own screen-space textured-quad idiom is `tc = width << 5`**
|
||||
(`src/game/glass2.c:678,689` — `sImageTableEntry.width << 5` /
|
||||
`.height << 5`). `<< 5` = ×32 = the S10.5 texel fixed-point fast3d expects,
|
||||
and it divides `tc` by `tex_width` before GL_REPEAT. So the patch's `× 32.0f`
|
||||
**is the correct scale** — provided `unk20`/`unk24` are already in *texel*
|
||||
units (they are: the cloud-tiling math in `sub_GAME_7F097388` /
|
||||
`CloudRepeat(skyheight)=10000` produces texel coords in the thousands, and
|
||||
M-47 measured `unk20` reaching ±20 000 near the horizon).
|
||||
- **The bug: `(s16)(20000 * 32)` overflows.** `Vtx.tc` is `s16` (±32767); a
|
||||
horizon vertex needs `tc` ≈ 640 000. It wraps/saturates → the streak.
|
||||
- **Fix (no fast3d change, no grid needed for the near/mid sky):** phase-fold
|
||||
every vertex of *one primitive* by the **same** multiple of the tile period
|
||||
(64 texels), so inter-vertex deltas are preserved but magnitudes stay in
|
||||
s16 range:
|
||||
```c
|
||||
s32 foldS = (s32)floorf(vmin_unk20 / 64.0f) * 64; // vmin over this prim's verts
|
||||
s32 foldT = (s32)floorf(vmin_unk24 / 64.0f) * 64;
|
||||
tc[0] = (s16)((v[i]->unk20 - foldS) * 32.0f);
|
||||
tc[1] = (s16)((v[i]->unk24 - foldT) * 32.0f);
|
||||
```
|
||||
This is exact wherever the S/T *span across a single triangle* is
|
||||
< ~1000 texels (s16 range ÷ 32). It holds for the corner-quad tessellation
|
||||
the current patch emits everywhere except triangles that straddle the
|
||||
horizon line, where the span diverges — those still need Defect-2's
|
||||
finer/adaptive tessellation. Land the fold first (fixes most of the frame),
|
||||
keep the grid as the horizon-band follow-up.
|
||||
|
||||
## Defect 2 — vertical coverage (band fills only top ~25%)
|
||||
|
||||
@@ -83,3 +105,23 @@ Next steps (one focused session):
|
||||
Finish **Path B** first — geometry already works; both defects are unit/
|
||||
vertex-set questions answerable in one render-iterate session. Keep Path A
|
||||
as fallback; it is now fully specified by this doc if B stalls.
|
||||
|
||||
## Verification ask (M-82 — for the next session with a display)
|
||||
|
||||
The Defect-1 phase-fold is committed to PR #18 but **unverified visually**
|
||||
(this session had no display). One check settles it:
|
||||
|
||||
1. `./build-pc/ge007.x86_64.exe -level_22` (Statue, night). At the intro the
|
||||
camera faces the horizon within a few seconds.
|
||||
2. Look at the upper half of the frame:
|
||||
- **Black** → Path B still not emitting (regression from the rebase —
|
||||
check `skyPortRenderPoly` is reached; `GE_D176=1`).
|
||||
- **Clouds, but smeared into horizontal streaks** → the fold didn't take;
|
||||
re-check `unk20`/`unk24` really are texels (probe their range).
|
||||
- **Recognisable tiled cloud texture, correct near/mid, ragged or missing
|
||||
right at the horizon line** → fold works; that ragged band is Defect 2
|
||||
→ adaptive tessellation is the next task.
|
||||
- **Looks right** → close Defect 1, mark PR #18 ready pending a
|
||||
`-level_36`/`-29`/Dam-exterior spot check.
|
||||
3. A `GE_PCDUMP="330-390:30"` capture of that run attached to PR #18 is enough
|
||||
for a remote reviewer to make the same call.
|
||||
@@ -21,7 +21,7 @@ once the game is playable start-to-finish without crashes.
|
||||
| **D172** | Bullet-impact / blood particle spray renders magenta or cyan instead of dark red (visible on guards hit at close range on Silo). | **Root-cause candidate found, static research done** (`docs/dev/D172-PARTICLE-COLOR-RESEARCH.md`). Particles get CC/tile state from 15 ROM records replayed via `gSPDisplayList` (`explosion.c:894`); each record contains an opcode **0xB9** that fast3d does not handle → the D146 unknown-opcode guard kills the sub-DL before the record's `G_SETCOMBINE`+`G_SETTIMG` apply → particles draw with stale state = magenta/cyan. SETCOMBINE decode itself verified correct. Verify in-game: watch console for `D146: unknown GBI opcode 0xb9` while shooting (rate-limited to 20). Fix: decode 0xB9 semantics (ginit.s missing from repo — trace gmain.s 0x80–0xBF group or infer from data) + implement in fast3d. |
|
||||
| **D178** | Objectives not listed correctly on the pre-mission briefing screen (the mission overview shown before starting a level). | **M-36 triage: the objective lines are BLANK, not wrong.** `GE_STARTMENU=10` Dam briefing renders the header fine ("OHMSS / Agent: James Bond / Mission 1: Arkangelsk / Part i: Dam / PRIMARY OBJECTIVES:") then just the bullet "a." with no text and no b/c/d. → **D143/D151 blank-text family** (`langGet()` → NULL → silent blank), *not* a propDef walk / difficulty decode. **Family B** in `docs/dev/M-36-TRIAGE.md` — find which lang bank the front-end briefing flow fails to load. Re-confirm the exact shape in a *real* briefing (the `GE_STARTMENU` boot skips real save state). Close relatives: D151 (watch objective text blank — type-35/23 `text` slot u16→u32 fix, M-28; interactive re-verify was still pending), D143 (briefing/objective text blank via `langGet` NULL), D157 (objective difficulty byte offset — could make difficulty-gated objectives appear/disappear wrongly). The pre-start briefing is a *different surface* from the in-level watch, so D151's fix may not cover it. **Next:** ask user which level + what exactly shows vs expected; compare against `docs/dev/LEVEL-OBJECTIVES.md` (regenerated post-D157); if lines are blank → D143/D151 family (`langGet` NULL guard = silent blank), if wrong objectives listed → propDef type-23 record walk / difficulty decode. |
|
||||
| **D175** | In-game stutter / brief hang during normal play — observed opening a door on Runway (mission 3, `-level_35`) and also on Surface. No backtrace captured (gdb attach missed the window; it self-recovered). | **Observed, not investigated** (user QA report). Matches known transient-hang classes rather than looking new: D155 (post-slow-load catch-up spiral — clamped), D156 (anim NaN loop — guarded, prints one-shot stderr diag if it fires), D134 (SP/DP task-done event swallowed — fixed M-22, Runway was an original victim), D147/D152 (audio `s_imLock` steal = ~2 s hiccup). Door-open specifically = new room first visible → one-off texture-import/frame spike (likely benign). **Next:** reproduce under `tools_pc/debug.ps1` with the box idle; check console for the D156 stderr diag; if it recurs, attach gdb mid-hang and pattern-match `bt` (import_texture = benign slow frame; model.c:3131 spin = D156; pthread_mutex_lock on s_imLock = D147/D152). |
|
||||
| **D176** | Surface exterior renders wrong (two co-located defects). **(a)** Sky is solid **black** — the skybox / sky gradient does not draw at all (reference: warm sunset cloud gradient). **(b)** The perimeter **tree-line backdrop renders as grey TV-static / comb interlacing** instead of snow-laden pines — the geometry is present and roughly the right silhouette but every tree texture is scrambled noise. Ground, tunnel and the dish/bunker building draw fine. | **Observed, screenshots committed** (M-35, user QA; `docs/img/bugs/d176-surface-exterior-our-build.png` vs `-reference.png`). Level is the shared Surface exterior — user reached it Dam→Surface on Agent so this is **Surface (i) `-level_36`** (confirm it also affects `-level_43`). **(a)** black sky: **M-36 partial (findings.md "D176(a)").** Env data is correct (`Sky.Clouds=1`, `CloudRGB=240,120,30`, `SkyImageId=0`); `skyRender` runs the cloud path and classifies corners correctly (switch case 12), but `skyRenderTri`/`skyRenderFull` emit nothing — not even the `env->RGB` fill shows. Not root-caused: next is probing `sub_GAME_7F097388` projected coords, verifying `skywaterimages[0]` resolves on PC (`image_bank.c` GIMG offset `0xFB4`), and a fast3d sky-tri trace. `GE_D176=1` probe shipped. **M-37: ROOT-CAUSED** — `skyRenderTri`/`skyRenderFull` build geometry *exclusively* as `G_RDPHALF_*` immediates, which `gfx_pc.cpp` deliberately no-ops (identical no-op in the PD port); fix = decode the RDPHALF tri-raster stream in fast3d (~1 session, genuine new code). **M-42: `-level_22` (Statue) confirmed a clean headless repro** — bare boot, frame ~360, upper half pure black; use it to verify the decoder. **M-47 + read-only consolidation:** Path B draft exists (`scratchpad/sky.patch`, `skyPortRenderPoly` PORT hook — geometry+texture reach GL, two unit defects open) and the full RDPHALF wire format is now decoded (S15.1 half-packing, 8-component perspective-interpolated vertex vectors); next session is mechanical per `docs/dev/D176a-SKY-NOTES.md`. `-level_36`/`-43` intro cams face down (not a sky test without `GE_INPUTSCRIPT`). **(b)** tree/rock static: **M-36 triage — NOT the D159 family.** `texSwapAltRowBytes` is a full `#ifdef PORT` no-op (`image.c:2199`), it cannot cause this. Real cause: `port/fast3d/gfx_pc.cpp` `import_texture_*` assume `line_size_bytes == full_image_line_size_bytes` (`SUPPORT_CHECK`; rgba16's is commented out *"trips ... with a garbage size"* `:658`) → non-PoT / sub-rect tiles get a flat linear read → diagonal row shear = grey static. **Family A** in `docs/dev/M-36-TRIAGE.md`. Fix: honour `line_size_bytes` as the real source pitch. Same defect as D182(2). |
|
||||
| **D176** | Surface exterior renders wrong (two co-located defects). **(a)** Sky is solid **black** — the skybox / sky gradient does not draw at all (reference: warm sunset cloud gradient). **(b)** The perimeter **tree-line backdrop renders as grey TV-static / comb interlacing** instead of snow-laden pines — the geometry is present and roughly the right silhouette but every tree texture is scrambled noise. Ground, tunnel and the dish/bunker building draw fine. | **Observed, screenshots committed** (M-35, user QA; `docs/img/bugs/d176-surface-exterior-our-build.png` vs `-reference.png`). Level is the shared Surface exterior — user reached it Dam→Surface on Agent so this is **Surface (i) `-level_36`** (confirm it also affects `-level_43`). **(a)** black sky: **M-36 partial (findings.md "D176(a)").** Env data is correct (`Sky.Clouds=1`, `CloudRGB=240,120,30`, `SkyImageId=0`); `skyRender` runs the cloud path and classifies corners correctly (switch case 12), but `skyRenderTri`/`skyRenderFull` emit nothing — not even the `env->RGB` fill shows. Not root-caused: next is probing `sub_GAME_7F097388` projected coords, verifying `skywaterimages[0]` resolves on PC (`image_bank.c` GIMG offset `0xFB4`), and a fast3d sky-tri trace. `GE_D176=1` probe shipped. **M-37: ROOT-CAUSED** — `skyRenderTri`/`skyRenderFull` build geometry *exclusively* as `G_RDPHALF_*` immediates, which `gfx_pc.cpp` deliberately no-ops (identical no-op in the PD port); fix = decode the RDPHALF tri-raster stream in fast3d (~1 session, genuine new code). **M-42: `-level_22` (Statue) confirmed a clean headless repro** — bare boot, frame ~360, upper half pure black; use it to verify the decoder. **M-47 + read-only consolidation:** Path B draft exists (`scratchpad/sky.patch`, `skyPortRenderPoly` PORT hook — geometry+texture reach GL, two unit defects open) and the full RDPHALF wire format is now decoded (S15.1 half-packing, 8-component perspective-interpolated vertex vectors); next session is mechanical per `docs/dev/D176a-SKY-NOTES.md`. `-level_36`/`-43` intro cams face down (not a sky test without `GE_INPUTSCRIPT`). **M-82: PR #18 rebased onto main + Defect-1 fix applied** — cloud tile is `s_skywaterimages[0]` = 64×64 IA8; the patch's `tc = S·32` scale is correct (matches GE's `width<<5` idiom, `glass2.c:678`), the bug was `(s16)` overflow on the ±20k-texel horizon S/T; fix = per-primitive phase-fold to the 64-texel period (`sky.c` `skyPortRenderPoly`, `#ifdef PORT`). Builds clean, no crash (bunker1/statue/surface1 verify PASS). **Unverified visually** — owed: one `-level_22` screenshot (see `D176a-SKY-NOTES.md` "verification ask"). Defect 2 (horizon-band coverage / straddling tris) still open → adaptive tessellation. **(b)** tree/rock static: **M-36 triage — NOT the D159 family.** `texSwapAltRowBytes` is a full `#ifdef PORT` no-op (`image.c:2199`), it cannot cause this. Real cause: `port/fast3d/gfx_pc.cpp` `import_texture_*` assume `line_size_bytes == full_image_line_size_bytes` (`SUPPORT_CHECK`; rgba16's is commented out *"trips ... with a garbage size"* `:658`) → non-PoT / sub-rect tiles get a flat linear read → diagonal row shear = grey static. **Family A** in `docs/dev/M-36-TRIAGE.md`. Fix: honour `line_size_bytes` as the real source pitch. Same defect as D182(2). |
|
||||
| **D174** | "No blood effect" — user reports no visible blood when shooting guards / into surfaces. | **User QA report; likely D120, unverified.** Decals: the D120 `PointUsage[]` converter fix (M-30) was never interactively verified and only takes effect after a full sidecar regen (`d43 && d69 && d88 --regen`) — check whether the playtest build had regenerated sidecars before concluding the fix failed. Spray: D172 observed the particle spray *drawing* (wrong color, magenta/cyan) on Silo — if the user sees no spray either, that's new info (different weapon/range, or the D172 decode is worse than "wrong color"). First step: BUNKER1 firefight with regenerated sidecars; if decals still absent, instrument the `chr.c:3328` decal walk. |
|
||||
| **D173** | Third-person Bond model (the player-representing figure shown at level start) spawns too high — floats well above the ground "a lot of the time" while the actual player spawn is correct. Same symptom on the Cuba end credits: JB stands ~6 ft in the air above Natalya. | **Confirmed still present across the full 21-level playthrough (M-49).** **Observed, not investigated** (user QA report). D75 animated-model family but a *position* defect, not absence — M-33 confirmed the gun-barrel Bond renders fine upright. Suspects: (a) intro/credits puppet chr spawn position vs the model's base transform; (b) anim root-motion accumulation (`modelSetAnimFrame2WithChrStuff`, D156 area) offsetting the rendered joints above the body origin; (c) a `coord3d`/packed-float decode in the intro camera/model setup. "Player spawning is OK" localises it to the render-side model, not `g_CurrentPlayer` state. |
|
||||
| **D182** | SELECT FILE screen degrades after navigating away and back (main menu → file select, or backing out of file select and re-entering). On the fresh screen the 007 gun-barrel spiral / Bond silhouette renders behind the file boxes; after a round-trip **the Bond image stops drawing entirely** and the whole background gains the **comb / interlacing** artifact (horizontal line scramble). File boxes, text and the Copy/Erase icons still draw. | **Observed, screenshot committed** (M-35, user QA; `docs/img/bugs/d182-file-select-backout-20260902.png`). Two symptoms, likely linked: **(1)** background 3D image stops rendering after re-entry → a front-end model/DL whose `render_pos` / segment binding is only valid on first construction (D149 / D75 `constructor_menuXX` family — the dossier/wallet models have the same "renders once" behavior). **(2)** interlacing = **M-36 triage: Family A**, the `import_texture_*` `line` vs `full_image_line` shear (see D176(b) / `docs/dev/M-36-TRIAGE.md`) — **not** the D159 `texSwapAltRowBytes` path (that is a full PORT no-op). Open question: why only *after* a round-trip — first import may land `line == width`, re-import may not, or the tile descriptor is stale on re-entry. Repro: `GE_STARTMENU` to file-select, back out with ESC/B, re-enter; `GE_DTEX` on the spiral texture across both visits. Shares defect (2) with D176(b). |
|
||||
|
||||
@@ -5090,6 +5090,90 @@ M-42 clean headless black-sky repro.
|
||||
`-level_29` — confirm also black, proving it is the shared emit path and not a
|
||||
Surface-only asset.
|
||||
|
||||
### D176(a) — M-46: Path B implemented (`src/game/sky.c`, `#ifdef PORT`)
|
||||
|
||||
Path B is in. `src/game/sky.c` only; N64 path kept byte-for-byte under `#else`.
|
||||
|
||||
**What changed.** A new file-scope `#ifdef PORT` helper `skyPortRenderPoly(gdl,
|
||||
SkyRelated38 **v, nverts)` and an early `#ifdef PORT` return in both
|
||||
`skyRenderTri` (3 verts, `arg1..arg3`) and `skyRenderFull` (4 verts,
|
||||
`arg1..arg4`), placed right after the `sp444/sp488 == 0` degenerate-area guard
|
||||
and `1.0f / area` so all shared early-outs still run. The helper:
|
||||
|
||||
- `dynAllocateVertices(n)` + two `dynAllocateMatrix()` from the vtx pool
|
||||
(same lifetime idiom as the bondview2 watch-gauge ortho overlay and
|
||||
explosion.c billboards).
|
||||
- `guOrtho(proj, l, l+w, t+h, t, -32768, 32768, 1)` where `l/t/w/h =
|
||||
getPlayer_c_screen{left,top,width,height}()` — maps the already-projected
|
||||
pixel coords 1:1 into clip space, Y flipped (screen-down → NDC-up); identity
|
||||
modelview. `gSPMatrix` LOAD PROJECTION then MODELVIEW. `bg.c` reloads the
|
||||
perspective projection at the top of `bgLevelRender` (lines 638/689/…), so
|
||||
leaving ortho loaded after `skyRender` is safe.
|
||||
- Per vertex: `ob = {unk28, unk2c, unk30} * 0.25` (the `*4` subpixel scale the
|
||||
RDP path used); `tc = {unk20, unk24} * 32` (standard N64 S10.5); `cn = rgba`
|
||||
from the struct.
|
||||
- `gSPClearGeometryMode(G_LIGHTING|G_CULL_BOTH|G_FOG)` +
|
||||
`gSPSetGeometryMode(G_SHADE|G_SHADING_SMOOTH)`, then `gSPVertex` +
|
||||
`gSP1Triangle(0,1,2)` (tri) / `gSP2Triangles(0,1,3, 0,3,2)` (quad, winding
|
||||
irrelevant with culling off). Combiner (`SHADE,ENV,TEXEL0,ENV`), env colour
|
||||
and `texSelect(&skywaterimages[SkyImageId/WaterImageId], 1,0,2)` are already
|
||||
emitted by the caller immediately before — the helper does not touch them.
|
||||
|
||||
**Verified.** `src/game/sky.c` compiles clean under the real PC build flags
|
||||
(`gcc.exe … -DPORT=1 -std=gnu11 -Wall`, exit 0, no new warnings) with the
|
||||
worktree's `build-pc/` CMake configuration. Full link + run NOT done: the
|
||||
worktree has no `data/` ROM so assets can't be extracted here. Every symbol the
|
||||
helper uses (`dynAllocate*`, `guOrtho`, `guMtxIdent`, `gSPVertex`,
|
||||
`gSP{1,2}Triangle{,s}`, `osVirtualToPhysical`) is already linked by the compiled
|
||||
set, so link is expected clean.
|
||||
|
||||
**Owed to a human (cannot headless-verify):**
|
||||
1. Eyeball `-level_22` (Statue, night) frame ~360, bare boot no input — the
|
||||
M-42 black-sky repro. Expect a rendered moonlit sky in the upper half.
|
||||
Also spot-check `-level_36` (Surface), `-level_29` (Streets).
|
||||
2. **Untested risk — texture scale.** `tc = unk20/unk24 * 32` is the
|
||||
conventional guess; `unk20/unk24` come out of `sub_GAME_7F097388` as
|
||||
`unk0c * (65535/65536)` with `unk0c ≈ worldX*0.1` for clouds. If the sky
|
||||
texture is tiled wrong / smeared, the fix is localised to the two `tc[]`
|
||||
lines in `skyPortRenderPoly` (multiplier, or an explicit `gSPTexture`
|
||||
scaling override) — no other code moves.
|
||||
3. **Untested risk — ortho Z / depth.** `ob[2] = unk30*0.25` in `[0,8192]`
|
||||
under an `[-32768,32768]` ortho; sky renders first into a cleared buffer so
|
||||
depth ordering should not matter, but if the sky Z-fights or is culled,
|
||||
drop `ob[2]` to 0.
|
||||
4. Seam/precision check vs the N64 RDP subpixel edge-walk (the Path A
|
||||
motivation) — only relevant once it renders at all.
|
||||
|
||||
**Confidence:** MODERATE. The emit-path substitution is sound and matches the
|
||||
established screen-space-overlay idiom; compile is clean. The two numeric
|
||||
unknowns (texture scale, and whether fast3d's viewport transform composes with
|
||||
this ortho exactly as the projection math intends) need one visual check.
|
||||
|
||||
### D176(a) — M-82: PR #18 rebased; Defect 1 (texcoord) fixed by static analysis
|
||||
|
||||
- **PR #18 rebased onto `main`** (was 5 days stale, `docs/porting-notes.md`
|
||||
conflict resolved). Builds clean; `bunker1` verify PASS, `worst_cell`
|
||||
unchanged (sky.c change is `#ifdef PORT` and only touches cloud-sky levels).
|
||||
- **Defect 1 root-caused, no visual iteration needed.** The M-46 "untested
|
||||
risk — texture scale" is resolved:
|
||||
- Cloud tile = `s_skywaterimages[0]` = `IMAGE_CLOUDS_GRAYSCALE`, **64×64
|
||||
IA8, `G_TX_WRAP`** (`assets/oddtextures.c:646`). It *tiles* — S/T are not
|
||||
[0,1) fractions.
|
||||
- GE's own screen-space textured-quad idiom is `tc = width << 5`
|
||||
(`src/game/glass2.c:678`), so the patch's `× 32.0f` **is the right scale**.
|
||||
- `unk20`/`unk24` are texel coords reaching ±20 000 near the horizon (M-47),
|
||||
so `(s16)(S × 32)` **overflows** → the streak.
|
||||
- **Fix (committed):** per-primitive phase-fold — subtract the same
|
||||
multiple of the 64-texel tile period from every vertex of one triangle
|
||||
before scaling. Preserves inter-vertex deltas (hence the interpolated
|
||||
texture); keeps `tc` in s16 range. Exact for any triangle whose S/T span
|
||||
is < ~1000 texels — i.e. everything except triangles straddling the
|
||||
horizon line, which remain Defect 2.
|
||||
- **Defect 2 (coverage / horizon-straddling tris) still open** → adaptive
|
||||
tessellation, denser toward the horizon.
|
||||
- **Owed:** one `-level_22` visual check — see `docs/dev/D176a-SKY-NOTES.md`
|
||||
"Verification ask".
|
||||
|
||||
---
|
||||
|
||||
## D177 — Ladders non-functional: `count`/`rooms` land in the high half of a widened pointer (M-36)
|
||||
|
||||
@@ -451,6 +451,14 @@ through a converter or a runtime bswap fixup reads scrambled.
|
||||
logic). 2D pixel space is `viGetX()` x `viGetY()`. Return NULL when the
|
||||
overlay is closed so the frame is byte-for-byte unchanged.
|
||||
|
||||
- **Verbatim RDP triangle commands chopped into `gImmp1(G_RDPHALF_1/_CONT/_2)`
|
||||
pairs** (GE's `skyRenderTri`/`skyRenderFull` hand-build an edge-walked
|
||||
`G_TRI_FILL`/`G_TRI_SHADE_TXTR` for the modified RSP ucode to reassemble) are
|
||||
silently dropped by fast3d — it has no RDP triangle rasteriser. Substitute a
|
||||
normal `gSPVertex` + `gSP*Triangle` batch behind `#ifdef PORT`: if the game
|
||||
code already screen-space-projected the verts, re-emit them under a
|
||||
`guOrtho(l,r,b,t,…)` + identity modelview matching the projection's pixel
|
||||
extents, `#else` keeps the stream verbatim (D176(a), M-46).
|
||||
- Z buffer cleared by pointing the color image at it + fill-rect → does
|
||||
nothing in fast3d; must emit `G_CLEAR_DEPTH_EXT` (D105).
|
||||
- LOD / detail mip tiles: fast3d fabricates a crop when detail textures
|
||||
|
||||
+118
@@ -14,6 +14,9 @@
|
||||
#include "othermodemicrocode.h"
|
||||
#include "fr.h"
|
||||
#include "image_bank.h"
|
||||
#ifdef PORT
|
||||
#include "dyn.h"
|
||||
#endif
|
||||
|
||||
#define SKYABS(val) (val >= 0.0f ? (val) : -(val))
|
||||
|
||||
@@ -1474,6 +1477,95 @@ bool skyVerticesAreTheSame(SkyRelated38 *arg0, SkyRelated38 *arg1)
|
||||
return sqrtf((f0 * f0) + (f1 * f1)) < 1.0f ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
#ifdef PORT
|
||||
/*
|
||||
* D176(a) Path B (M-46) -- black-sky fix. Full rationale in
|
||||
* docs/dev/findings.md section F, "D176(a)".
|
||||
*
|
||||
* skyRenderTri / skyRenderFull normally build their geometry as a verbatim
|
||||
* N64 RDP triangle command, chopped into 32-bit halves and carried as
|
||||
* gImmp1(G_RDPHALF_1 / _CONT / _2, word) pairs for GE's modified RSP ucode
|
||||
* (rsp/graphics/gmain.s) to reassemble and DMA to the RDP as an edge-walked
|
||||
* G_TRI_FILL / G_TRI_SHADE_TXTR. The PC software RSP (port/fast3d) has no RDP
|
||||
* triangle rasteriser and deliberately drops G_RDPHALF_* (gfx_pc.cpp), so
|
||||
* every cloud-sky level rendered a solid black upper half.
|
||||
*
|
||||
* The SkyRelated38 verts handed to these functions are already fully
|
||||
* screen-space projected by sub_GAME_7F097388:
|
||||
* unk28 = screenX * 4, unk2c = screenY * 4, unk30 = screenZ (0..0x7fff),
|
||||
* unk34 = 1/w, unk20 / unk24 = S / T, r/g/b/a = per-vertex colour.
|
||||
* Under PORT we skip the RDPHALF encode entirely and re-emit the same
|
||||
* triangle(s) as an ordinary gSPVertex + gSP*Triangle batch under a
|
||||
* pixel-space ortho projection the software RSP can consume. The combiner
|
||||
* (SHADE,ENV,TEXEL0,ENV), env colour and texSelect(&skywaterimages[...])
|
||||
* are all already emitted by the caller. This is a pure N64-RSP-idiom
|
||||
* substitution (same class as the G_TRI4 / dynamic-lighting PORT branches
|
||||
* elsewhere in src/): the N64 (#else) path below is byte-for-byte unchanged.
|
||||
*/
|
||||
static Gfx *skyPortRenderPoly(Gfx *gdl, SkyRelated38 **v, s32 nverts)
|
||||
{
|
||||
Vtx *vtx = dynAllocateVertices(nverts < 3 ? 3 : nverts);
|
||||
Mtx *proj = dynAllocateMatrix();
|
||||
Mtx *mv = dynAllocateMatrix();
|
||||
f32 l = getPlayer_c_screenleft();
|
||||
f32 t = getPlayer_c_screentop();
|
||||
f32 r = l + getPlayer_c_screenwidth();
|
||||
f32 b = t + getPlayer_c_screenheight();
|
||||
s32 i;
|
||||
|
||||
/* D176(a) Defect 1 (M-82): unk20/unk24 are S/T in *texel* units for the
|
||||
* 64x64 cloud tile (s_skywaterimages[0]) and reach many thousands near
|
||||
* the horizon -- (s16)(S * 32) overflows Vtx.tc and streaks the clouds.
|
||||
* GL_REPEAT has period tex_width (64), so fold every vertex of this one
|
||||
* primitive by the SAME multiple of 64: magnitudes drop into s16 range,
|
||||
* inter-vertex deltas (hence the interpolated texture) are preserved
|
||||
* exactly. Triangles whose S/T span exceeds ~1000 texels (only those
|
||||
* straddling the horizon) still need Defect-2's finer tessellation. */
|
||||
f32 foldS = v[0]->unk20, foldT = v[0]->unk24;
|
||||
for (i = 1; i < nverts; i++)
|
||||
{
|
||||
if (v[i]->unk20 < foldS) foldS = v[i]->unk20;
|
||||
if (v[i]->unk24 < foldT) foldT = v[i]->unk24;
|
||||
}
|
||||
foldS = (f32) ((s32) floorf(foldS / 64.0f) * 64);
|
||||
foldT = (f32) ((s32) floorf(foldT / 64.0f) * 64);
|
||||
|
||||
guOrtho(proj, l, r, b, t, -32768.0f, 32768.0f, 1.0f);
|
||||
guMtxIdent(mv);
|
||||
|
||||
for (i = 0; i < nverts; i++)
|
||||
{
|
||||
vtx[i].v.ob[0] = (s16) (v[i]->unk28 * 0.25f);
|
||||
vtx[i].v.ob[1] = (s16) (v[i]->unk2c * 0.25f);
|
||||
vtx[i].v.ob[2] = (s16) (v[i]->unk30 * 0.25f);
|
||||
vtx[i].v.flag = 0;
|
||||
vtx[i].v.tc[0] = (s16) ((v[i]->unk20 - foldS) * 32.0f);
|
||||
vtx[i].v.tc[1] = (s16) ((v[i]->unk24 - foldT) * 32.0f);
|
||||
vtx[i].v.cn[0] = (u8) v[i]->r;
|
||||
vtx[i].v.cn[1] = (u8) v[i]->g;
|
||||
vtx[i].v.cn[2] = (u8) v[i]->b;
|
||||
vtx[i].v.cn[3] = (u8) v[i]->a;
|
||||
}
|
||||
|
||||
gSPMatrix(gdl++, osVirtualToPhysical(proj), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
|
||||
gSPMatrix(gdl++, osVirtualToPhysical(mv), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
||||
gSPClearGeometryMode(gdl++, G_LIGHTING | G_CULL_BOTH | G_FOG);
|
||||
gSPSetGeometryMode(gdl++, G_SHADE | G_SHADING_SMOOTH);
|
||||
gSPVertex(gdl++, osVirtualToPhysical(vtx), nverts, 0);
|
||||
|
||||
if (nverts >= 4)
|
||||
{
|
||||
gSP2Triangles(gdl++, 0, 1, 3, 0, 3, 2, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
gSP1Triangle(gdl++, 0, 1, 2, 0);
|
||||
}
|
||||
|
||||
return gdl;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Address: 0x7F097818
|
||||
*/
|
||||
@@ -1619,6 +1711,18 @@ Gfx *skyRenderTri(Gfx *gdl, SkyRelated38 *arg1, SkyRelated38 *arg2, SkyRelated38
|
||||
|
||||
sp440 = 1.0f / sp444;
|
||||
|
||||
#ifdef PORT
|
||||
{
|
||||
/* D176(a) Path B: re-emit as screen-space geometry (see skyPortRenderPoly).
|
||||
* skyRenderTri is only ever called textured in this file; `textured` is
|
||||
* honoured only in that the caller has set the textured combiner. */
|
||||
SkyRelated38 *portv[3];
|
||||
portv[0] = arg1;
|
||||
portv[1] = arg2;
|
||||
portv[2] = arg3;
|
||||
return skyPortRenderPoly(gdl, portv, 3);
|
||||
}
|
||||
#else
|
||||
sp484 = arg1;
|
||||
sp480 = arg2;
|
||||
sp47c = arg3;
|
||||
@@ -1966,6 +2070,7 @@ Gfx *skyRenderTri(Gfx *gdl, SkyRelated38 *arg1, SkyRelated38 *arg2, SkyRelated38
|
||||
gImmp1(gdl++, G_RDPHALF_1, (spb8 & 0x0000ffff) << 16 | (spb4 & 0x0000ffff));
|
||||
gImmp1(gdl++, G_RDPHALF_2, (spb0 & 0x0000ffff) << 16 | (spac & 0x0000ffff));
|
||||
}
|
||||
#endif
|
||||
|
||||
return gdl;
|
||||
}
|
||||
@@ -2120,6 +2225,18 @@ Gfx *skyRenderFull(Gfx *gdl, SkyRelated38 *arg1, SkyRelated38 *arg2, SkyRelated3
|
||||
|
||||
sp484 = 1.0f / sp488;
|
||||
|
||||
#ifdef PORT
|
||||
{
|
||||
/* D176(a) Path B: re-emit the sky quad as screen-space geometry
|
||||
* (see skyPortRenderPoly). arg1..arg4 are TL,TR,BL,BR corners. */
|
||||
SkyRelated38 *portv[4];
|
||||
portv[0] = arg1;
|
||||
portv[1] = arg2;
|
||||
portv[2] = arg3;
|
||||
portv[3] = arg4;
|
||||
return skyPortRenderPoly(gdl, portv, 4);
|
||||
}
|
||||
#else
|
||||
sp4cc = arg1;
|
||||
sp4c8 = arg2;
|
||||
sp4c4 = arg3;
|
||||
@@ -2484,6 +2601,7 @@ Gfx *skyRenderFull(Gfx *gdl, SkyRelated38 *arg1, SkyRelated38 *arg2, SkyRelated3
|
||||
gImmp1(gdl++, G_RDPHALF_1, (spb0 & 0x0000ffff) << 16 | (spac & 0x0000ffff));
|
||||
gImmp1(gdl++, G_RDPHALF_2, (spa8 & 0x0000ffff) << 16 | (spa4 & 0x0000ffff));
|
||||
}
|
||||
#endif
|
||||
|
||||
return gdl;
|
||||
}
|
||||
Reference in new issue
Block a user