Fix critter sprites cropped in the software renderer
build / build (push) Successful in 2m41s

g3_bitmap_common() (Bitmap.c) used the same bm_w/bm_h for both the
on-screen quad size and its texture-coordinate bounds. The former
should use patch 04's native-size override for a modded/upscaled
bitmap; the latter must always use the bitmap's own real dimensions,
since that's still what's actually being sampled. OpenGL never hit
this (opengl_bitmap() ignores these bounds and always maps the whole
real texture), but the software renderer's h_map() takes them as
literal pixel coordinates to interpolate, so the override capped how
much of a larger bitmap it ever read - cropping anything past the
original sprite's bounds, such as an upscaled critter's limbs.

Split into a separate tex_w/tex_h pair, always the bitmap's real
size, used for every texture-coordinate computation.

README.md: document this, and the previously-undocumented
engine-debug-tools RSD8 decode tracing patch (02).
This commit is contained in:
ml
2026-10-18 07:33:56 +02:00
parent 9d0a0d5798
commit a8d7ff76df
2 changed files with 115 additions and 12 deletions
+45 -9
View File
@@ -387,6 +387,29 @@ which the desktop build does not apply.
the sprite from where it should sit, since it shares its coordinate
system with this patch's own size override rather than with the
bitmap's real pixel dimensions.
`g3_bitmap_common()`'s world-space size and its texture-coordinate range
are computed from the same `bm_w`/`bm_h` locals, but only the former
should ever use this patch's override - the pixels actually being
sampled are still the bitmap's own real (possibly upscaled) buffer,
regardless of what on-screen size it's drawn at. Overriding both left the
texture-coordinate range capped at the smaller, un-upscaled size while
the real bitmap underneath it was larger, so the renderer only ever
sampled that smaller top-left region of it - cropping off anything past
it, such as an upscaled critter's limbs extending beyond its original
sprite's bounding box. OpenGL never showed this: `opengl_bitmap()`
ignores `g3_bitmap_common()`'s computed `u`/`v` entirely and always maps
the *whole* bound texture over the quad via fixed `0.0`-`1.0` corners.
The software renderer's own scanline texture mapper (`h_map()`,
`gentm.c`) has no such shortcut - it takes `u`/`v` as literal pixel
coordinates into the bitmap and interpolates between exactly the values
it's given, so a capped range there directly caps how much of the real
bitmap it ever reads. Fixed by splitting `g3_bitmap_common()`'s single
`bm_w`/`bm_h` into the override-aware pair (world-space size only) and a
`tex_w`/`tex_h` pair that always holds the bitmap's own real dimensions,
used for every texture-coordinate computation (including the later
blend-buffer-size check, which sizes a buffer against the same real
pixel data these coordinates sample from).
- **`05-desktop-fix-texture-cache-collision.patch`** - `OpenGL.cc`'s
per-bitmap GL texture cache (`texturesByBitsPtr`) was keyed by
`bm->bits | (w << 32) | (h << 48)`, a plain bitwise OR rather than a
@@ -443,15 +466,28 @@ included in `make dist`/`make package`.
numbered the same way as `engine-patches/` (section 4.4's own process
applies: scratch copy, `patch -p1`, regenerate via `diff -u` rather than
hand-editing hunks), applied on top of the regular `engine-patches/`
series, never in place of it. Currently one patch, adding a debug dump
hotkey: pressing **K** in-game dumps every frame of the
currently/most-recently-drawn critter's animation to `dumps/` (created
next to the running binary) as raw palette-index pixel data - 2-byte LE
width, 2-byte LE height, then width\*height index bytes, one file per
frame, named `id<resource-id>_frame<N>.raw`. Deliberately independent of
the renderer's own texture/GL state, so a frame already corrupted in the
dump is a decode-time bug, while a frame that's clean in the dump but
wrong on screen is a rendering-time one.
series, never in place of it. Two patches so far:
- **`01`** - a debug dump hotkey: pressing **K** in-game dumps every
frame of the currently/most-recently-drawn critter's animation to
`dumps/` (created next to the running binary) as raw palette-index
pixel data - 2-byte LE width, 2-byte LE height, then width\*height
index bytes, one file per frame, named `id<resource-id>_frame<N>.raw`.
Deliberately independent of the renderer's own texture/GL state, so a
frame already corrupted in the dump is a decode-time bug, while a
frame that's clean in the dump but wrong on screen is a rendering-time
one.
- **`02`** - RSD8 decode tracing: `gr_rsd8_convert()`/`gr_rsd8_unpack()`
(`engine/src/Libraries/2D/Source/RSD/`) print a `[debug rsd8]` summary
per frame (decode path, source/destination dimensions, bytes written
versus the bitmap's own area) and a `[debug rsd8 op]` line per RLE
opcode consumed, gated by a flag `debug_dump_critter_animation()` (01,
above) sets only around its own decode calls - tracing covers exactly
the frames the K hotkey dumps, not every RSD8 decode in the game. Each
frame is also decoded a second time back to back and logged as
`identical`/`DIFFERS` against the first, to tell a decode result that's
deterministic given the compressed source (a bad source stream, or a
decoder bug it triggers) apart from one that depends on something else,
such as a resource-cache slot being reused mid-decode.
- `engine-debug-tools/dump2png/` - converts those `.raw` dumps into
viewable PNGs using the real game palette (the dump format has no
palette of its own, to keep the in-game dump path from depending on the