fix: port shadow LUT remap to Rust, fixing Indian Nuclear Test crash
Browse filesThe SHADOW_CLEAR path in blit_sprite called BitGrid__RemapPixelsThroughLut
(0x4F6590) as a plain cdecl function, but it's actually a usercall that
expects EAX = BitGrid pointer with one stdcall stack param (RET 0x4).
EAX was never set, so the function read a garbage BitGrid pointer and
wrote to invalid memory.
Replaced the broken asm bridge with a pure Rust port of the function —
a simple double loop remapping 8bpp pixels through a 256-byte LUT.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
crates/openwa-core/src/render/display/blit_sprite.rs
CHANGED
|
@@ -208,10 +208,9 @@ pub unsafe fn blit_sprite(
|
|
| 208 |
let saved = *table_byte;
|
| 209 |
*table_byte = 0;
|
| 210 |
|
| 211 |
-
//
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
clear_fn(table_byte as *mut u8);
|
| 215 |
|
| 216 |
*table_byte = saved;
|
| 217 |
|
|
@@ -452,3 +451,35 @@ pub unsafe fn draw_scaled_sprite(
|
|
| 452 |
DrawScaledSpriteResult::Handled => {}
|
| 453 |
}
|
| 454 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 208 |
let saved = *table_byte;
|
| 209 |
*table_byte = 0;
|
| 210 |
|
| 211 |
+
// BitGrid__RemapPixelsThroughLut (0x4F6590) — remaps layer_2 pixels
|
| 212 |
+
// through the color table.
|
| 213 |
+
remap_pixels_through_shadow_lut(layer2, table_byte as *mut u8);
|
|
|
|
| 214 |
|
| 215 |
*table_byte = saved;
|
| 216 |
|
|
|
|
| 451 |
DrawScaledSpriteResult::Handled => {}
|
| 452 |
}
|
| 453 |
}
|
| 454 |
+
|
| 455 |
+
/// Pure Rust port of `BitGrid__RemapPixelsThroughLut` (0x4F6590).
|
| 456 |
+
///
|
| 457 |
+
/// Remaps every pixel in an 8bpp BitGrid through a 256-byte LUT.
|
| 458 |
+
/// The inner loop is unrolled 4x, matching the original.
|
| 459 |
+
unsafe fn remap_pixels_through_shadow_lut(bitgrid: *mut DisplayBitGrid, color_table: *const u8) {
|
| 460 |
+
let grid = &*bitgrid;
|
| 461 |
+
if grid.cells_per_unit != 8 {
|
| 462 |
+
return;
|
| 463 |
+
}
|
| 464 |
+
|
| 465 |
+
let data = grid.data;
|
| 466 |
+
let stride = grid.row_stride as usize;
|
| 467 |
+
let height = grid.height as usize;
|
| 468 |
+
// The original passes stride/4 as the inner loop count (4 pixels per iteration).
|
| 469 |
+
let quads_per_row = stride / 4;
|
| 470 |
+
|
| 471 |
+
let lut = core::slice::from_raw_parts(color_table, 256);
|
| 472 |
+
let mut row_ptr = data;
|
| 473 |
+
|
| 474 |
+
for _ in 0..height {
|
| 475 |
+
let mut p = row_ptr;
|
| 476 |
+
for _ in 0..quads_per_row {
|
| 477 |
+
*p = lut[*p as usize];
|
| 478 |
+
*p.add(1) = lut[*p.add(1) as usize];
|
| 479 |
+
*p.add(2) = lut[*p.add(2) as usize];
|
| 480 |
+
*p.add(3) = lut[*p.add(3) as usize];
|
| 481 |
+
p = p.add(4);
|
| 482 |
+
}
|
| 483 |
+
row_ptr = row_ptr.add(stride);
|
| 484 |
+
}
|
| 485 |
+
}
|