paavohtl commited on
Commit
4a4cdc9
·
1 Parent(s): 1b3fdc4

refactor: type set_active_layer return + propagate PaletteContext

Browse files

Cascades a typed `*mut PaletteContext` return through the chain that
starts at `DisplayGfx::set_active_layer` (slot 5) and feeds the GfxDir
loaders.

- Slot 5 vtable signature retyped from `*mut u8` to
`*mut PaletteContext`. Doc-comment promoted from one line to
explain what the result is used for downstream.

- `gfx_resource_create` (`FUN_004F6300` port), `call_gfx_find_and_load`,
and `call_gfx_load_and_wrap` now take `display_ctx: *mut PaletteContext`
instead of `*mut u8`. The single internal `IMG_Decode` call still
casts back to `*mut u8` since `IMG_Decode` is WA-side.

- `compute_complex_gradient` (`render/display/gradient.rs`) takes
`layer3_ctx: *mut PaletteContext` and passes it through to
`call_gfx_find_and_load` without any casts.

- `wa_load_sprites` naked-asm bridge's `_layer_ctx` parameter retyped
to `*mut PaletteContext` to match what its only caller passes after
`set_active_layer`. The naked asm body is unchanged — pointer types
are zero-cost on x86.

- The `+0x606` byte arithmetic at
`ddgame_constructor.rs:969` (the gradient sky-height read) is now
a clean `(*layer3_ctx).cache_count` field access. The cast/offset
pair `*(layer3_ctx.add(0x606) as *const i16)` is gone.

- One redundant `as *mut PaletteContext` cast removed from
`load_sprite_by_layer`'s call to `set_active_layer`.

- `gfx_resource_create_trampoline`'s impl wrapper in DLL adds one
explicit `as *mut PaletteContext` cast since the trampoline catches
an opaque stack pointer from the WA-side caller. Documented in a
comment that all known WA call sites pass a `set_active_layer`
return value (i.e. a `PaletteContext*`).

No behavior changes — all pointer ops are zero-cost casts on x86.
Headless replay tests pass 15/15.

crates/openwa-core/src/engine/ddgame_constructor.rs CHANGED
@@ -182,7 +182,7 @@ unsafe extern "C" fn wa_load_sprites(
182
  _sprite_data: *mut u8,
183
  _display_flags: u32,
184
  _param4: u32,
185
- _layer_ctx: *mut u8, // → ESI
186
  ) {
187
  core::arch::naked_asm!(
188
  "push esi",
@@ -664,7 +664,7 @@ unsafe fn init_graphics_and_resources(
664
  gfx_resource = gfx_resource_create(
665
  gfx_dir,
666
  rb(va::STR_MASKS_IMG) as *const core::ffi::c_char,
667
- palette_ctx,
668
  );
669
  }
670
 
@@ -966,7 +966,7 @@ unsafe fn init_graphics_and_resources(
966
  // ── Gradient image (0x030) ──
967
  let level_height = (*ddgame).level_height as i32;
968
  let layer3_ctx = (*disp).set_active_layer(3);
969
- let s_var1 = *(layer3_ctx.add(0x606) as *const i16);
970
 
971
  if s_var1 < 0x61 && level_height == 0x2B8 {
972
  // Simple gradient: load gradient.img directly
 
182
  _sprite_data: *mut u8,
183
  _display_flags: u32,
184
  _param4: u32,
185
+ _layer_ctx: *mut crate::render::palette::PaletteContext, // → ESI
186
  ) {
187
  core::arch::naked_asm!(
188
  "push esi",
 
664
  gfx_resource = gfx_resource_create(
665
  gfx_dir,
666
  rb(va::STR_MASKS_IMG) as *const core::ffi::c_char,
667
+ palette_ctx as *mut crate::render::palette::PaletteContext,
668
  );
669
  }
670
 
 
966
  // ── Gradient image (0x030) ──
967
  let level_height = (*ddgame).level_height as i32;
968
  let layer3_ctx = (*disp).set_active_layer(3);
969
+ let s_var1 = (*layer3_ctx).cache_count;
970
 
971
  if s_var1 < 0x61 && level_height == 0x2B8 {
972
  // Simple gradient: load gradient.img directly
crates/openwa-core/src/render/display/gradient.rs CHANGED
@@ -111,7 +111,7 @@ impl PaletteContext {
111
  pub(crate) unsafe fn compute_complex_gradient(
112
  ddgame: *mut DDGame,
113
  land_dir: *mut GfxDir,
114
- layer3_ctx: *mut u8,
115
  sky_height: i16,
116
  ) {
117
  let mut palette = PaletteContext::new();
 
111
  pub(crate) unsafe fn compute_complex_gradient(
112
  ddgame: *mut DDGame,
113
  land_dir: *mut GfxDir,
114
+ layer3_ctx: *mut crate::render::palette::PaletteContext,
115
  sky_height: i16,
116
  ) {
117
  let mut palette = PaletteContext::new();
crates/openwa-core/src/render/display/vtable.rs CHANGED
@@ -67,9 +67,14 @@ pub struct DisplayGfxVtable {
67
  /// set layer color (0x5231E0, RET 0x8)
68
  #[slot(4)]
69
  pub set_layer_color: fn(this: *mut DisplayGfx, layer: i32, color: i32),
70
- /// set active layer, returns layer context ptr (0x523270, RET 0x4)
 
 
 
 
 
71
  #[slot(5)]
72
- pub set_active_layer: fn(this: *mut DisplayGfx, layer: i32) -> *mut u8,
73
  /// get sprite info by layer and id (0x523500, RET 0x10)
74
  ///
75
  /// Looks up sprite metadata for the given layer ID. Checks sprite_ptrs
@@ -1457,9 +1462,12 @@ unsafe fn palette_context_init(ctx: *mut PaletteContext, range_min: i16, range_m
1457
  ///
1458
  /// Returns the `PaletteContext*` for `layer` (1-3), or null if out of
1459
  /// range. Used as palette data input for `update_palette`.
1460
- pub unsafe extern "thiscall" fn set_active_layer(this: *mut DisplayGfx, layer: i32) -> *mut u8 {
 
 
 
1461
  match Layer::try_from_i32(layer) {
1462
- Some(layer) => (*this).base.layer_contexts[layer.idx()] as *mut u8,
1463
  None => core::ptr::null_mut(),
1464
  }
1465
  }
@@ -1902,7 +1910,7 @@ pub unsafe fn load_sprite_by_layer(
1902
  return 1;
1903
  }
1904
 
1905
- let palette_ctx = set_active_layer(this, layer as i32) as *mut PaletteContext;
1906
 
1907
  if !is_valid_sprite_id(id as i32) {
1908
  return 0;
 
67
  /// set layer color (0x5231E0, RET 0x8)
68
  #[slot(4)]
69
  pub set_layer_color: fn(this: *mut DisplayGfx, layer: i32, color: i32),
70
+ /// set active layer, returns layer context ptr (0x523270, RET 0x4).
71
+ ///
72
+ /// Returns the `PaletteContext*` for the requested layer (1-3),
73
+ /// or null if the index is out of range. Callers feed the result to
74
+ /// `update_palette` (slot 24) and to GfxDir loaders that need a
75
+ /// palette context for color remapping.
76
  #[slot(5)]
77
+ pub set_active_layer: fn(this: *mut DisplayGfx, layer: i32) -> *mut PaletteContext,
78
  /// get sprite info by layer and id (0x523500, RET 0x10)
79
  ///
80
  /// Looks up sprite metadata for the given layer ID. Checks sprite_ptrs
 
1462
  ///
1463
  /// Returns the `PaletteContext*` for `layer` (1-3), or null if out of
1464
  /// range. Used as palette data input for `update_palette`.
1465
+ pub unsafe extern "thiscall" fn set_active_layer(
1466
+ this: *mut DisplayGfx,
1467
+ layer: i32,
1468
+ ) -> *mut PaletteContext {
1469
  match Layer::try_from_i32(layer) {
1470
+ Some(layer) => (*this).base.layer_contexts[layer.idx()],
1471
  None => core::ptr::null_mut(),
1472
  }
1473
  }
 
1910
  return 1;
1911
  }
1912
 
1913
+ let palette_ctx = set_active_layer(this, layer as i32);
1914
 
1915
  if !is_valid_sprite_id(id as i32) {
1916
  return 0;
crates/openwa-core/src/render/sprite/gfx_dir.rs CHANGED
@@ -350,7 +350,7 @@ pub unsafe fn gfx_dir_load_dir(handler: *mut u8) -> i32 {
350
  pub unsafe fn gfx_resource_create(
351
  gfx_dir: *mut GfxDir,
352
  name: *const core::ffi::c_char,
353
- output: *mut u8,
354
  ) -> *mut u8 {
355
  // 1. Try FindEntry → cached load → DisplayGfx wrap
356
  let entry = gfx_dir_find_entry(name, gfx_dir);
@@ -375,7 +375,7 @@ pub unsafe fn gfx_resource_create(
375
  // IMG_Decode: stdcall(output, raw_image, 1), RET 0xC
376
  let decode: unsafe extern "stdcall" fn(*mut u8, *mut u8, i32) -> *mut u8 =
377
  core::mem::transmute(rb(va::IMG_DECODE) as usize);
378
- let result = decode(output, raw_image as *mut u8, 1);
379
 
380
  GfxDirStream::destroy_raw(raw_image);
381
 
@@ -388,7 +388,7 @@ pub unsafe fn gfx_resource_create(
388
  pub(crate) unsafe fn call_gfx_find_and_load(
389
  gfx_dir: *mut GfxDir,
390
  name: &core::ffi::CStr,
391
- display_ctx: *mut u8,
392
  ) -> *mut u8 {
393
  let name_ptr = name.as_ptr() as *const u8;
394
  let entry = gfx_dir_find_entry(name_ptr.cast(), gfx_dir);
@@ -415,7 +415,7 @@ pub(crate) unsafe fn call_gfx_find_and_load(
415
  pub(crate) unsafe fn call_gfx_load_and_wrap(
416
  gfx_dir: *mut GfxDir,
417
  name: *const core::ffi::c_char,
418
- display_ctx: *mut u8,
419
  ) -> *mut u8 {
420
  let image = call_gfx_load_image(gfx_dir, name);
421
  if image.is_null() {
@@ -424,7 +424,7 @@ pub(crate) unsafe fn call_gfx_load_and_wrap(
424
  // FUN_004F5F80(display_ctx, image, 1) — stdcall, RET 0xC (3 params)
425
  let f: unsafe extern "stdcall" fn(*mut u8, *mut u8, u32) -> *mut u8 =
426
  core::mem::transmute(rb(va::IMG_DECODE) as usize);
427
- let result = f(display_ctx, image as *mut u8, 1);
428
  GfxDirStream::destroy_raw(image);
429
  result
430
  }
 
350
  pub unsafe fn gfx_resource_create(
351
  gfx_dir: *mut GfxDir,
352
  name: *const core::ffi::c_char,
353
+ output: *mut crate::render::palette::PaletteContext,
354
  ) -> *mut u8 {
355
  // 1. Try FindEntry → cached load → DisplayGfx wrap
356
  let entry = gfx_dir_find_entry(name, gfx_dir);
 
375
  // IMG_Decode: stdcall(output, raw_image, 1), RET 0xC
376
  let decode: unsafe extern "stdcall" fn(*mut u8, *mut u8, i32) -> *mut u8 =
377
  core::mem::transmute(rb(va::IMG_DECODE) as usize);
378
+ let result = decode(output as *mut u8, raw_image as *mut u8, 1);
379
 
380
  GfxDirStream::destroy_raw(raw_image);
381
 
 
388
  pub(crate) unsafe fn call_gfx_find_and_load(
389
  gfx_dir: *mut GfxDir,
390
  name: &core::ffi::CStr,
391
+ display_ctx: *mut crate::render::palette::PaletteContext,
392
  ) -> *mut u8 {
393
  let name_ptr = name.as_ptr() as *const u8;
394
  let entry = gfx_dir_find_entry(name_ptr.cast(), gfx_dir);
 
415
  pub(crate) unsafe fn call_gfx_load_and_wrap(
416
  gfx_dir: *mut GfxDir,
417
  name: *const core::ffi::c_char,
418
+ display_ctx: *mut crate::render::palette::PaletteContext,
419
  ) -> *mut u8 {
420
  let image = call_gfx_load_image(gfx_dir, name);
421
  if image.is_null() {
 
424
  // FUN_004F5F80(display_ctx, image, 1) — stdcall, RET 0xC (3 params)
425
  let f: unsafe extern "stdcall" fn(*mut u8, *mut u8, u32) -> *mut u8 =
426
  core::mem::transmute(rb(va::IMG_DECODE) as usize);
427
+ let result = f(display_ctx as *mut u8, image as *mut u8, 1);
428
  GfxDirStream::destroy_raw(image);
429
  result
430
  }
crates/openwa-dll/src/replacements/ddgame_init.rs CHANGED
@@ -102,6 +102,10 @@ extern "cdecl" fn impl_gfx_resource_create(
102
  name: *const c_char,
103
  output: *mut u8,
104
  ) -> u32 {
 
 
 
 
105
  let result = unsafe { gfx_resource_create(gfx_dir, name, output) };
106
  result as u32
107
  }
 
102
  name: *const c_char,
103
  output: *mut u8,
104
  ) -> u32 {
105
+ // The trampoline catches an opaque stack pointer; the underlying
106
+ // WA caller always passes a `PaletteContext*` (verified at all known
107
+ // call sites — `set_active_layer`'s return value).
108
+ let output = output as *mut openwa_core::render::palette::PaletteContext;
109
  let result = unsafe { gfx_resource_create(gfx_dir, name, output) };
110
  result as u32
111
  }