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 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-19 20:54:20 -05:00
co-authored by Claude Opus 4.8
parent bc59e39f41
commit cb5ea73ab2
@@ -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: