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:
@@ -387,6 +387,29 @@ which the desktop build does not apply.
|
|||||||
the sprite from where it should sit, since it shares its coordinate
|
the sprite from where it should sit, since it shares its coordinate
|
||||||
system with this patch's own size override rather than with the
|
system with this patch's own size override rather than with the
|
||||||
bitmap's real pixel dimensions.
|
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
|
- **`05-desktop-fix-texture-cache-collision.patch`** - `OpenGL.cc`'s
|
||||||
per-bitmap GL texture cache (`texturesByBitsPtr`) was keyed by
|
per-bitmap GL texture cache (`texturesByBitsPtr`) was keyed by
|
||||||
`bm->bits | (w << 32) | (h << 48)`, a plain bitwise OR rather than a
|
`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
|
numbered the same way as `engine-patches/` (section 4.4's own process
|
||||||
applies: scratch copy, `patch -p1`, regenerate via `diff -u` rather than
|
applies: scratch copy, `patch -p1`, regenerate via `diff -u` rather than
|
||||||
hand-editing hunks), applied on top of the regular `engine-patches/`
|
hand-editing hunks), applied on top of the regular `engine-patches/`
|
||||||
series, never in place of it. Currently one patch, adding a debug dump
|
series, never in place of it. Two patches so far:
|
||||||
hotkey: pressing **K** in-game dumps every frame of the
|
- **`01`** - a debug dump hotkey: pressing **K** in-game dumps every
|
||||||
currently/most-recently-drawn critter's animation to `dumps/` (created
|
frame of the currently/most-recently-drawn critter's animation to
|
||||||
next to the running binary) as raw palette-index pixel data - 2-byte LE
|
`dumps/` (created next to the running binary) as raw palette-index
|
||||||
width, 2-byte LE height, then width\*height index bytes, one file per
|
pixel data - 2-byte LE width, 2-byte LE height, then width\*height
|
||||||
frame, named `id<resource-id>_frame<N>.raw`. Deliberately independent of
|
index bytes, one file per frame, named `id<resource-id>_frame<N>.raw`.
|
||||||
the renderer's own texture/GL state, so a frame already corrupted in the
|
Deliberately independent of the renderer's own texture/GL state, so a
|
||||||
dump is a decode-time bug, while a frame that's clean in the dump but
|
frame already corrupted in the dump is a decode-time bug, while a
|
||||||
wrong on screen is a rendering-time one.
|
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
|
- `engine-debug-tools/dump2png/` - converts those `.raw` dumps into
|
||||||
viewable PNGs using the real game palette (the dump format has no
|
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
|
palette of its own, to keep the in-game dump path from depending on the
|
||||||
|
|||||||
@@ -200,7 +200,15 @@
|
|||||||
_g3d_bitmap_clut = (p->i & 0x00ff00) + grd_screen->ltab;
|
_g3d_bitmap_clut = (p->i & 0x00ff00) + grd_screen->ltab;
|
||||||
_g3d_bitmap_poly = vpl;
|
_g3d_bitmap_poly = vpl;
|
||||||
return (g3_bitmap_common(bm, p));
|
return (g3_bitmap_common(bm, p));
|
||||||
@@ -185,6 +196,15 @@
|
@@ -176,6 +187,7 @@
|
||||||
|
grs_vertex *tempG1, *tempG2;
|
||||||
|
fix tempResult;
|
||||||
|
int32_t bm_w, bm_h;
|
||||||
|
+ int32_t tex_w, tex_h;
|
||||||
|
fix dx, dy;
|
||||||
|
|
||||||
|
// MLA- these were globals, I made them locals for PPC speed, they aren't
|
||||||
|
@@ -185,6 +197,15 @@
|
||||||
long rm2;
|
long rm2;
|
||||||
long rm3;
|
long rm3;
|
||||||
|
|
||||||
@@ -216,7 +224,7 @@
|
|||||||
#ifdef stereo_on
|
#ifdef stereo_on
|
||||||
if (_g3d_stereo & 1) {
|
if (_g3d_stereo & 1) {
|
||||||
|
|
||||||
@@ -209,9 +229,11 @@
|
@@ -209,9 +230,23 @@
|
||||||
if ((p->codes & CC_CLIP_OVERFLOW) != 0)
|
if ((p->codes & CC_CLIP_OVERFLOW) != 0)
|
||||||
return (0L);
|
return (0L);
|
||||||
|
|
||||||
@@ -225,12 +233,71 @@
|
|||||||
- bm_h = bm->h;
|
- bm_h = bm->h;
|
||||||
+ // copy a few things into locals - w_override/h_override, if set (see
|
+ // copy a few things into locals - w_override/h_override, if set (see
|
||||||
+ // _g3d_bitmap_w_override's own comment), take the place of the bitmap's
|
+ // _g3d_bitmap_w_override's own comment), take the place of the bitmap's
|
||||||
+ // own pixel dimensions here.
|
+ // own pixel dimensions here, for the on-screen quad's world-space size
|
||||||
|
+ // only. tex_w/tex_h stay the bitmap's own real dimensions always: the
|
||||||
|
+ // quad's u/v bounds (below) are pixel coordinates into bm's own actual
|
||||||
|
+ // pixel data - the software renderer's scanline texture mapper
|
||||||
|
+ // (h_map(), gentm.c) interpolates and samples them literally, so
|
||||||
|
+ // overriding them to a smaller size here would make it only ever read
|
||||||
|
+ // part of a bitmap bigger than that override (such as an upscaled mod's
|
||||||
|
+ // replacement art), cropping the rest. OpenGL doesn't read u/v from here
|
||||||
|
+ // at all (opengl_bitmap() always maps the whole real texture over the
|
||||||
|
+ // quad), which is why this only ever showed up in the software
|
||||||
|
+ // renderer.
|
||||||
+ bm_w = w_override ? w_override : bm->w;
|
+ bm_w = w_override ? w_override : bm->w;
|
||||||
+ bm_h = h_override ? h_override : bm->h;
|
+ bm_h = h_override ? h_override : bm->h;
|
||||||
|
+ tex_w = bm->w;
|
||||||
|
+ tex_h = bm->h;
|
||||||
|
|
||||||
tempL = p->gZ; // mov eax,[edi].z
|
tempL = p->gZ; // mov eax,[edi].z
|
||||||
tempL <<= 8; // sal eax,8 ;should be
|
tempL <<= 8; // sal eax,8 ;should be
|
||||||
|
@@ -299,7 +334,7 @@
|
||||||
|
tempG1->y = tempL2;
|
||||||
|
|
||||||
|
// vpl[1][2] = bitmap.w-1
|
||||||
|
- tempG1->u = (bm_w - 1) << 16;
|
||||||
|
+ tempG1->u = (tex_w - 1) << 16;
|
||||||
|
|
||||||
|
// vpl[1][3] = 0
|
||||||
|
tempG1->v = 0;
|
||||||
|
@@ -326,10 +361,10 @@
|
||||||
|
tempG1->y = tempL2;
|
||||||
|
|
||||||
|
// vpl[2][2] = bitmap.w-1
|
||||||
|
- tempG1->u = (bm_w - 1) << 16;
|
||||||
|
+ tempG1->u = (tex_w - 1) << 16;
|
||||||
|
|
||||||
|
// vpl[2][3] = bitmap.h-1
|
||||||
|
- tempG1->v = (bm_h - 1) << 16;
|
||||||
|
+ tempG1->v = (tex_h - 1) << 16;
|
||||||
|
|
||||||
|
// vpl[2][4] undefined
|
||||||
|
|
||||||
|
@@ -356,7 +391,7 @@
|
||||||
|
tempG1->u = 0;
|
||||||
|
|
||||||
|
// vpl[3][3] = bitmap.h
|
||||||
|
- tempG1->v = bm_h << 16;
|
||||||
|
+ tempG1->v = tex_h << 16;
|
||||||
|
|
||||||
|
// vpl[3][4] undefined
|
||||||
|
|
||||||
|
@@ -380,11 +415,13 @@
|
||||||
|
if (dy > dx)
|
||||||
|
dx = dy; // get max value in dx
|
||||||
|
|
||||||
|
- // shift down because bm_w isn't fixed, and we only double when twice the size
|
||||||
|
+ // shift down because tex_w isn't fixed, and we only double when twice the size
|
||||||
|
dx >>= 0x11;
|
||||||
|
|
||||||
|
// make sure doubled bitmap won't overflow unpack buffer (that's roughly 1/5 of 64k)
|
||||||
|
- if ((bm_w <= dx) && (bm_w * bm_h <= 12000)) {
|
||||||
|
+ // - against the bitmap's own real size (tex_w/tex_h), same as the u/v this doubles
|
||||||
|
+ // just below: both operate on bm's actual pixel data, not the on-screen override.
|
||||||
|
+ if ((tex_w <= dx) && (tex_w * tex_h <= 12000)) {
|
||||||
|
// first fix all u's and v's
|
||||||
|
for (tempL = 0; tempL < 4; tempL++) {
|
||||||
|
_g3d_bitmap_poly[tempL]->u <<= 1;
|
||||||
--- a/src/Libraries/3D/Source/3d.h
|
--- a/src/Libraries/3D/Source/3d.h
|
||||||
+++ b/src/Libraries/3D/Source/3d.h
|
+++ b/src/Libraries/3D/Source/3d.h
|
||||||
@@ -720,7 +720,8 @@
|
@@ -720,7 +720,8 @@
|
||||||
|
|||||||
Reference in New Issue
Block a user