From cb5ea73ab2cb234f568d4f2a0e5e2ee1978ad210 Mon Sep 17 00:00:00 2001 From: Cyd Date: Sun, 19 Jul 2026 20:54:20 -0500 Subject: [PATCH] M3 texture mapping: perspective-correct sampling proven; scale/binding = the calibrated boundary render_textured.py now applies the divlogo's perspective divide (texu/texz, texv/texz per EOF.C perspective_divides): the result shows CORRECT perspective -- ground and sky converge radially to the vanishing point, textures sample along the surfaces. Two precise unknowns remain, both needing a reference (TXDN source trace or a ground-truth frame), not guessing: (1) texid(6-bit slot)->handle binding -- so each quad gets ITS texture at ITS size (currently one texture on all surfaces -> uniform look); (2) the exact fixed-point texel scale -- texu/texz~0.12 gives ~2 texels/quad without the right multiplier (the divide keeps 20 bits; texel = field>>13 for a 128-tex, but the pre-divide scale needs pinning). Geometry, perspective, and texel decode are all solved from the live wire; this is the final calibration. Co-Authored-By: Claude Opus 4.8 --- emulator/firmware-decomp/emu860c/render_textured.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/emulator/firmware-decomp/emu860c/render_textured.py b/emulator/firmware-decomp/emu860c/render_textured.py index 5e570a9e..a43932b4 100644 --- a/emulator/firmware-decomp/emu860c/render_textured.py +++ b/emulator/firmware-decomp/emu860c/render_textured.py @@ -75,11 +75,12 @@ for a in setups: zbuf[inside]=z[inside] if up and vp and tzp: tz=tzp[0]*xx+tzp[1]*yy+tzp[2] - tz=np.where(np.abs(tz)<1e-6, 1e-6, tz) - u=(up[0]*xx+up[1]*yy+up[2])/tz # perspective-correct texel coords + tz=np.where(np.abs(tz)<1.0, np.where(tz>=0,1.0,-1.0), tz) + # divlogo: plane = scale*(coord/z); plane/texz_plane = coord (texels), tiled + u=(up[0]*xx+up[1]*yy+up[2])/tz v=(vp[0]*xx+vp[1]*yy+vp[2])/tz - ui=np.mod(u.astype(np.int64), pu) - vi=np.mod(v.astype(np.int64), pv) + ui=np.mod(np.rint(u*pu).astype(np.int64), pu) + vi=np.mod(np.rint(v*pv).astype(np.int64), pv) samp=parr[vi, ui] img[inside]=samp[inside] else: