paavohtl Claude Opus 4.6 (1M context) commited on
Commit
7c2aa5e
Β·
1 Parent(s): 92780f9

refactor: use *const c_char for C string parameters

Browse files

Change string parameters from *const u8 to *const c_char in:
- gfx_dir_find_entry, gfx_resource_create, call_gfx_load_and_wrap
- call_gfx_load_image (naked asm bridge)
- DDDisplay::load_sprite, DDDisplay::load_sprite_by_layer
- DDDisplayVtable function pointer types
- fopen transmute in ddgame.rs
- ddgame_init.rs hook trampolines

Internal byte-level operations (gfx_dir_hash, buffer manipulation)
keep *const u8 with .cast() at boundaries.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

crates/openwa-core/src/display/dd_display.rs CHANGED
@@ -84,8 +84,14 @@ pub struct DDDisplayVtable {
84
  /// Slot 30
85
  pub _slot_30: usize,
86
  /// Slot 31 (0x7C): load sprite with flag β€” thiscall(this, layer, id, flag, gfx, name), RET 0x14
87
- pub load_sprite:
88
- unsafe extern "thiscall" fn(*mut DDDisplay, u32, u32, u32, *mut u8, *const u8) -> i32,
 
 
 
 
 
 
89
  /// Slot 32
90
  pub _slot_32: usize,
91
  /// Slot 33
@@ -97,8 +103,13 @@ pub struct DDDisplayVtable {
97
  /// Slot 36
98
  pub _slot_36: usize,
99
  /// Slot 37 (0x94): load sprite by layer β€” thiscall(this, layer, id, gfx, name), RET 0x10
100
- pub load_sprite_by_layer:
101
- unsafe extern "thiscall" fn(*mut DDDisplay, u32, u32, *mut u8, *const u8) -> i32,
 
 
 
 
 
102
  }
103
 
104
  const _: () = assert!(core::mem::size_of::<DDDisplayVtable>() == 38 * 4);
@@ -131,7 +142,7 @@ impl DDDisplay {
131
  layer: u32,
132
  id: u32,
133
  gfx: *mut u8,
134
- name: *const u8,
135
  ) -> i32 {
136
  ((*(*this).vtable).load_sprite_by_layer)(this, layer, id, gfx, name)
137
  }
@@ -144,7 +155,7 @@ impl DDDisplay {
144
  id: u32,
145
  flag: u32,
146
  gfx: *mut u8,
147
- name: *const u8,
148
  ) -> i32 {
149
  ((*(*this).vtable).load_sprite)(this, layer, id, flag, gfx, name)
150
  }
 
84
  /// Slot 30
85
  pub _slot_30: usize,
86
  /// Slot 31 (0x7C): load sprite with flag β€” thiscall(this, layer, id, flag, gfx, name), RET 0x14
87
+ pub load_sprite: unsafe extern "thiscall" fn(
88
+ *mut DDDisplay,
89
+ u32,
90
+ u32,
91
+ u32,
92
+ *mut u8,
93
+ *const core::ffi::c_char,
94
+ ) -> i32,
95
  /// Slot 32
96
  pub _slot_32: usize,
97
  /// Slot 33
 
103
  /// Slot 36
104
  pub _slot_36: usize,
105
  /// Slot 37 (0x94): load sprite by layer β€” thiscall(this, layer, id, gfx, name), RET 0x10
106
+ pub load_sprite_by_layer: unsafe extern "thiscall" fn(
107
+ *mut DDDisplay,
108
+ u32,
109
+ u32,
110
+ *mut u8,
111
+ *const core::ffi::c_char,
112
+ ) -> i32,
113
  }
114
 
115
  const _: () = assert!(core::mem::size_of::<DDDisplayVtable>() == 38 * 4);
 
142
  layer: u32,
143
  id: u32,
144
  gfx: *mut u8,
145
+ name: *const core::ffi::c_char,
146
  ) -> i32 {
147
  ((*(*this).vtable).load_sprite_by_layer)(this, layer, id, gfx, name)
148
  }
 
155
  id: u32,
156
  flag: u32,
157
  gfx: *mut u8,
158
+ name: *const core::ffi::c_char,
159
  ) -> i32 {
160
  ((*(*this).vtable).load_sprite)(this, layer, id, flag, gfx, name)
161
  }
crates/openwa-core/src/engine/ddgame.rs CHANGED
@@ -740,7 +740,8 @@ unsafe fn init_graphics_and_resources(
740
  is_headless: bool,
741
  ) {
742
  let ddgame = (*wrapper).ddgame;
743
- let fopen: unsafe extern "cdecl" fn(*const u8, *const u8) -> *mut u8 =
 
744
  core::mem::transmute(rb(va::WA_FOPEN) as usize);
745
  let gfx_dir_vtable = rb(va::GFX_DIR_VTABLE) as u32;
746
 
@@ -752,37 +753,37 @@ unsafe fn init_graphics_and_resources(
752
  // Build path list (order depends on headless + display_flags)
753
  let headless = (*game_info).headless_mode as i32;
754
  let display_flags = (*game_info).display_flags as i32;
755
- let paths: [&[u8]; 3] = if headless != 0 {
756
  if display_flags == 0 {
757
  [
758
- c"data\\Gfx\\Gfx.dir".to_bytes_with_nul(),
759
- c"data\\Gfx\\Gfx0.dir".to_bytes_with_nul(),
760
- c"data\\Gfx\\Gfx1.dir".to_bytes_with_nul(),
761
  ]
762
  } else {
763
  [
764
- c"data\\Gfx\\Gfx.dir".to_bytes_with_nul(),
765
- c"data\\Gfx\\Gfx1.dir".to_bytes_with_nul(),
766
- c"data\\Gfx\\Gfx0.dir".to_bytes_with_nul(),
767
  ]
768
  }
769
  } else if display_flags == 0 {
770
  [
771
- c"data\\Gfx\\Gfx0.dir".to_bytes_with_nul(),
772
- c"data\\Gfx\\Gfx1.dir".to_bytes_with_nul(),
773
- c"data\\Gfx\\Gfx.dir".to_bytes_with_nul(),
774
  ]
775
  } else {
776
  [
777
- c"data\\Gfx\\Gfx1.dir".to_bytes_with_nul(),
778
- c"data\\Gfx\\Gfx0.dir".to_bytes_with_nul(),
779
- c"data\\Gfx\\Gfx.dir".to_bytes_with_nul(),
780
  ]
781
  };
782
 
783
  let mut gfx_loaded_idx = 0u32;
784
  for (i, path) in paths.iter().enumerate() {
785
- let fp = fopen(path.as_ptr(), c"rb".as_ptr().cast());
786
  (*gfx1).file_handle = fp;
787
  if !fp.is_null()
788
  && call_gfx_load_dir(gfx1 as *mut u8, crate::render::gfx_dir::gfx_load_dir_addr()) != 0
@@ -813,11 +814,11 @@ unsafe fn init_graphics_and_resources(
813
  let gfx2 = GfxDir::alloc(gfx_dir_vtable);
814
  (*wrapper).secondary_gfx_dir = gfx2 as *mut u8;
815
 
816
- let fp = fopen(gfx_c_path.as_ptr(), c"rb".as_ptr().cast());
817
  (*gfx2).file_handle = fp;
818
  let load_addr = crate::render::gfx_dir::gfx_load_dir_addr();
819
  if fp.is_null() || call_gfx_load_dir(gfx2 as *mut u8, load_addr) == 0 {
820
- let fp2 = fopen(c"data\\Gfx\\Gfx.dir".as_ptr().cast(), c"rb".as_ptr().cast());
821
  (*gfx2).file_handle = fp2;
822
  if fp2.is_null() || call_gfx_load_dir(gfx2 as *mut u8, load_addr) == 0 {
823
  panic!("DDGame: couldn't open secondary Gfx.dir");
@@ -827,13 +828,20 @@ unsafe fn init_graphics_and_resources(
827
 
828
  // ── Display palette setup (non-headless) ──
829
  if !is_headless {
830
- if *(rb(va::G_DISPLAY_MODE_FLAG) as *const u8) == 0 {
831
  call_usercall_eax(wrapper, FUN_570A90_ADDR);
832
  }
833
  let disp = (*wrapper).display;
834
  let gfx_dir = (*wrapper).primary_gfx_dir;
835
  DDDisplay::set_layer_color(disp, 1, 0xFE);
836
- DDDisplay::load_sprite(disp, 1, 1, 0, gfx_dir, rb(va::STR_CDROM_SPR) as *const u8);
 
 
 
 
 
 
 
837
  DDDisplay::set_layer_visibility(disp, 1, -100);
838
 
839
  // Palette slot range init (raw byte offsets into DisplayBase)
@@ -866,7 +874,7 @@ unsafe fn init_graphics_and_resources(
866
  // The layer_ctx is used as the output buffer, not a plain stack alloc.
867
  let res = gfx_resource_create(
868
  (*wrapper).primary_gfx_dir,
869
- rb(va::STR_COLOURS_IMG) as *const u8,
870
  layer_ctx,
871
  );
872
  if !res.is_null() {
@@ -943,7 +951,8 @@ unsafe fn init_graphics_and_resources(
943
  let gfx_dir = (*wrapper).primary_gfx_dir;
944
  let out_buf = wa_malloc(0x900);
945
  core::ptr::write_bytes(out_buf, 0, 0x900);
946
- gfx_resource = gfx_resource_create(gfx_dir, rb(va::STR_MASKS_IMG) as *const u8, out_buf);
 
947
  }
948
 
949
  // ── PCLandscape (alloc 0xB44, stdcall 11 params) ──
@@ -1048,7 +1057,7 @@ unsafe fn init_graphics_and_resources(
1048
 
1049
  let layer_ctx = DDDisplay::set_active_layer((*ddgame).display, 1);
1050
 
1051
- let entry = gfx_dir_find_entry(name_buf.as_ptr(), gfx_dir);
1052
 
1053
  let sprite: *mut u8;
1054
  if !entry.is_null() {
@@ -1062,11 +1071,11 @@ unsafe fn init_graphics_and_resources(
1062
  sprite = wa_displaygfx_ctor(cached);
1063
  } else {
1064
  // Fallback: load from file via GfxDir__LoadImage + IMG_Decode
1065
- sprite = call_gfx_load_and_wrap(gfx_dir, name_buf.as_ptr(), layer_ctx);
1066
  }
1067
  } else {
1068
  // Entry not found β€” try direct file load
1069
- sprite = call_gfx_load_and_wrap(gfx_dir, name_buf.as_ptr(), layer_ctx);
1070
  }
1071
 
1072
  // Store arrow sprite at DDGame+0x38+i*4
@@ -1244,7 +1253,7 @@ unsafe fn init_graphics_and_resources(
1244
  land_layer,
1245
  c"back.spr".as_ptr().cast(),
1246
  );
1247
- DDDisplay::load_sprite(disp, 3, 0x26E, 0, land_layer, c"debris.spr".as_ptr().cast());
1248
  }
1249
 
1250
  DDDisplay::load_sprite_by_layer(
@@ -1322,7 +1331,7 @@ unsafe fn init_graphics_and_resources(
1322
  }
1323
 
1324
  // ── FUN_00570A90 (second call, conditional) ──
1325
- if *(rb(va::G_DISPLAY_MODE_FLAG) as *const u8) == 0 {
1326
  call_usercall_eax(wrapper, FUN_570A90_ADDR);
1327
  }
1328
 
@@ -1461,7 +1470,7 @@ pub mod offsets {
1461
  pub const TEAM_BLOCKS: usize = 0x4090;
1462
 
1463
  /// Byte offset from TeamArenaState base back to FullTeamBlock array start.
1464
- /// `blocks_ptr = (tws_base as *const u8).sub(ARENA_TO_BLOCKS) as *const FullTeamBlock`
1465
  ///
1466
  /// entry_ptr(0) = DDGame+0x4628 = TEAM_BLOCKS + 0x598.
1467
  /// 0x598 = sizeof(FullTeamBlock) + 0x7C = one block + offset into TeamBlockHeader.
 
740
  is_headless: bool,
741
  ) {
742
  let ddgame = (*wrapper).ddgame;
743
+ use core::ffi::c_char;
744
+ let fopen: unsafe extern "cdecl" fn(*const c_char, *const c_char) -> *mut u8 =
745
  core::mem::transmute(rb(va::WA_FOPEN) as usize);
746
  let gfx_dir_vtable = rb(va::GFX_DIR_VTABLE) as u32;
747
 
 
753
  // Build path list (order depends on headless + display_flags)
754
  let headless = (*game_info).headless_mode as i32;
755
  let display_flags = (*game_info).display_flags as i32;
756
+ let paths: [&core::ffi::CStr; 3] = if headless != 0 {
757
  if display_flags == 0 {
758
  [
759
+ c"data\\Gfx\\Gfx.dir",
760
+ c"data\\Gfx\\Gfx0.dir",
761
+ c"data\\Gfx\\Gfx1.dir",
762
  ]
763
  } else {
764
  [
765
+ c"data\\Gfx\\Gfx.dir",
766
+ c"data\\Gfx\\Gfx1.dir",
767
+ c"data\\Gfx\\Gfx0.dir",
768
  ]
769
  }
770
  } else if display_flags == 0 {
771
  [
772
+ c"data\\Gfx\\Gfx0.dir",
773
+ c"data\\Gfx\\Gfx1.dir",
774
+ c"data\\Gfx\\Gfx.dir",
775
  ]
776
  } else {
777
  [
778
+ c"data\\Gfx\\Gfx1.dir",
779
+ c"data\\Gfx\\Gfx0.dir",
780
+ c"data\\Gfx\\Gfx.dir",
781
  ]
782
  };
783
 
784
  let mut gfx_loaded_idx = 0u32;
785
  for (i, path) in paths.iter().enumerate() {
786
+ let fp = fopen(path.as_ptr(), c"rb".as_ptr());
787
  (*gfx1).file_handle = fp;
788
  if !fp.is_null()
789
  && call_gfx_load_dir(gfx1 as *mut u8, crate::render::gfx_dir::gfx_load_dir_addr()) != 0
 
814
  let gfx2 = GfxDir::alloc(gfx_dir_vtable);
815
  (*wrapper).secondary_gfx_dir = gfx2 as *mut u8;
816
 
817
+ let fp = fopen(gfx_c_path.as_ptr().cast(), c"rb".as_ptr());
818
  (*gfx2).file_handle = fp;
819
  let load_addr = crate::render::gfx_dir::gfx_load_dir_addr();
820
  if fp.is_null() || call_gfx_load_dir(gfx2 as *mut u8, load_addr) == 0 {
821
+ let fp2 = fopen(c"data\\Gfx\\Gfx.dir".as_ptr(), c"rb".as_ptr());
822
  (*gfx2).file_handle = fp2;
823
  if fp2.is_null() || call_gfx_load_dir(gfx2 as *mut u8, load_addr) == 0 {
824
  panic!("DDGame: couldn't open secondary Gfx.dir");
 
828
 
829
  // ── Display palette setup (non-headless) ──
830
  if !is_headless {
831
+ if *(rb(va::G_DISPLAY_MODE_FLAG) as *const c_char) == 0 {
832
  call_usercall_eax(wrapper, FUN_570A90_ADDR);
833
  }
834
  let disp = (*wrapper).display;
835
  let gfx_dir = (*wrapper).primary_gfx_dir;
836
  DDDisplay::set_layer_color(disp, 1, 0xFE);
837
+ DDDisplay::load_sprite(
838
+ disp,
839
+ 1,
840
+ 1,
841
+ 0,
842
+ gfx_dir,
843
+ rb(va::STR_CDROM_SPR) as *const c_char,
844
+ );
845
  DDDisplay::set_layer_visibility(disp, 1, -100);
846
 
847
  // Palette slot range init (raw byte offsets into DisplayBase)
 
874
  // The layer_ctx is used as the output buffer, not a plain stack alloc.
875
  let res = gfx_resource_create(
876
  (*wrapper).primary_gfx_dir,
877
+ rb(va::STR_COLOURS_IMG) as *const c_char,
878
  layer_ctx,
879
  );
880
  if !res.is_null() {
 
951
  let gfx_dir = (*wrapper).primary_gfx_dir;
952
  let out_buf = wa_malloc(0x900);
953
  core::ptr::write_bytes(out_buf, 0, 0x900);
954
+ gfx_resource =
955
+ gfx_resource_create(gfx_dir, rb(va::STR_MASKS_IMG) as *const c_char, out_buf);
956
  }
957
 
958
  // ── PCLandscape (alloc 0xB44, stdcall 11 params) ──
 
1057
 
1058
  let layer_ctx = DDDisplay::set_active_layer((*ddgame).display, 1);
1059
 
1060
+ let entry = gfx_dir_find_entry(name_buf.as_ptr().cast(), gfx_dir);
1061
 
1062
  let sprite: *mut u8;
1063
  if !entry.is_null() {
 
1071
  sprite = wa_displaygfx_ctor(cached);
1072
  } else {
1073
  // Fallback: load from file via GfxDir__LoadImage + IMG_Decode
1074
+ sprite = call_gfx_load_and_wrap(gfx_dir, name_buf.as_ptr().cast(), layer_ctx);
1075
  }
1076
  } else {
1077
  // Entry not found β€” try direct file load
1078
+ sprite = call_gfx_load_and_wrap(gfx_dir, name_buf.as_ptr().cast(), layer_ctx);
1079
  }
1080
 
1081
  // Store arrow sprite at DDGame+0x38+i*4
 
1253
  land_layer,
1254
  c"back.spr".as_ptr().cast(),
1255
  );
1256
+ DDDisplay::load_sprite(disp, 3, 0x26E, 0, land_layer, c"debris.spr".as_ptr());
1257
  }
1258
 
1259
  DDDisplay::load_sprite_by_layer(
 
1331
  }
1332
 
1333
  // ── FUN_00570A90 (second call, conditional) ──
1334
+ if *(rb(va::G_DISPLAY_MODE_FLAG) as *const c_char) == 0 {
1335
  call_usercall_eax(wrapper, FUN_570A90_ADDR);
1336
  }
1337
 
 
1470
  pub const TEAM_BLOCKS: usize = 0x4090;
1471
 
1472
  /// Byte offset from TeamArenaState base back to FullTeamBlock array start.
1473
+ /// `blocks_ptr = (tws_base as *const c_char).sub(ARENA_TO_BLOCKS) as *const FullTeamBlock`
1474
  ///
1475
  /// entry_ptr(0) = DDGame+0x4628 = TEAM_BLOCKS + 0x598.
1476
  /// 0x598 = sizeof(FullTeamBlock) + 0x7C = one block + offset into TeamBlockHeader.
crates/openwa-core/src/render/gfx_dir.rs CHANGED
@@ -104,8 +104,8 @@ unsafe fn gfx_dir_hash(name: *const u8) -> u32 {
104
  /// `gfx_dir` must be a valid GfxHandler with initialized hash table at +0x04.
105
  /// `name` must be a valid null-terminated C string.
106
  #[cfg(target_arch = "x86")]
107
- pub unsafe fn gfx_dir_find_entry(name: *const u8, gfx_dir: *mut u8) -> *mut u8 {
108
- let mut current_name = name;
109
 
110
  loop {
111
  // Copy name to stack buffer (max 0xFF chars + null)
@@ -335,7 +335,11 @@ pub unsafe fn gfx_dir_load_dir(handler: *mut u8) -> i32 {
335
  /// # Safety
336
  /// All pointers must be valid WA objects.
337
  #[cfg(target_arch = "x86")]
338
- pub unsafe fn gfx_resource_create(gfx_dir: *mut u8, name: *const u8, output: *mut u8) -> *mut u8 {
 
 
 
 
339
  // 1. Try FindEntry β†’ cached load β†’ DisplayGfx wrap
340
  let entry = gfx_dir_find_entry(name, gfx_dir);
341
  if !entry.is_null() {
@@ -382,7 +386,7 @@ pub(crate) unsafe fn call_gfx_find_and_load(
382
  display_ctx: *mut u8,
383
  ) -> *mut u8 {
384
  let name_ptr = name.as_ptr() as *const u8;
385
- let entry = gfx_dir_find_entry(name_ptr, gfx_dir);
386
 
387
  if !entry.is_null() {
388
  // Try cached load: gfx_dir->vtable[2](entry->field_4)
@@ -400,7 +404,7 @@ pub(crate) unsafe fn call_gfx_find_and_load(
400
  }
401
 
402
  // Fallback: load image directly
403
- call_gfx_load_and_wrap(gfx_dir, name_ptr, display_ctx)
404
  }
405
 
406
  /// Helper: load image via GfxDir__LoadImage + wrap as DisplayGfx.
@@ -408,7 +412,7 @@ pub(crate) unsafe fn call_gfx_find_and_load(
408
  #[cfg(target_arch = "x86")]
409
  pub(crate) unsafe fn call_gfx_load_and_wrap(
410
  gfx_dir: *mut u8,
411
- name: *const u8,
412
  display_ctx: *mut u8,
413
  ) -> *mut u8 {
414
  let image = call_gfx_load_image(gfx_dir, name);
@@ -450,7 +454,10 @@ pub(crate) unsafe fn call_gfx_load_dir(handler: *mut u8, addr: u32) -> i32 {
450
 
451
  #[cfg(target_arch = "x86")]
452
  #[unsafe(naked)]
453
- unsafe extern "C" fn call_gfx_load_image(_gfx_dir: *mut u8, _name: *const u8) -> *mut u8 {
 
 
 
454
  core::arch::naked_asm!(
455
  "pushl %esi",
456
  "movl 8(%esp), %esi", // ESI = gfx_dir
 
104
  /// `gfx_dir` must be a valid GfxHandler with initialized hash table at +0x04.
105
  /// `name` must be a valid null-terminated C string.
106
  #[cfg(target_arch = "x86")]
107
+ pub unsafe fn gfx_dir_find_entry(name: *const core::ffi::c_char, gfx_dir: *mut u8) -> *mut u8 {
108
+ let mut current_name = name as *const u8;
109
 
110
  loop {
111
  // Copy name to stack buffer (max 0xFF chars + null)
 
335
  /// # Safety
336
  /// All pointers must be valid WA objects.
337
  #[cfg(target_arch = "x86")]
338
+ pub unsafe fn gfx_resource_create(
339
+ gfx_dir: *mut u8,
340
+ name: *const core::ffi::c_char,
341
+ output: *mut u8,
342
+ ) -> *mut u8 {
343
  // 1. Try FindEntry β†’ cached load β†’ DisplayGfx wrap
344
  let entry = gfx_dir_find_entry(name, gfx_dir);
345
  if !entry.is_null() {
 
386
  display_ctx: *mut u8,
387
  ) -> *mut u8 {
388
  let name_ptr = name.as_ptr() as *const u8;
389
+ let entry = gfx_dir_find_entry(name_ptr.cast(), gfx_dir);
390
 
391
  if !entry.is_null() {
392
  // Try cached load: gfx_dir->vtable[2](entry->field_4)
 
404
  }
405
 
406
  // Fallback: load image directly
407
+ call_gfx_load_and_wrap(gfx_dir, name_ptr.cast(), display_ctx)
408
  }
409
 
410
  /// Helper: load image via GfxDir__LoadImage + wrap as DisplayGfx.
 
412
  #[cfg(target_arch = "x86")]
413
  pub(crate) unsafe fn call_gfx_load_and_wrap(
414
  gfx_dir: *mut u8,
415
+ name: *const core::ffi::c_char,
416
  display_ctx: *mut u8,
417
  ) -> *mut u8 {
418
  let image = call_gfx_load_image(gfx_dir, name);
 
454
 
455
  #[cfg(target_arch = "x86")]
456
  #[unsafe(naked)]
457
+ unsafe extern "C" fn call_gfx_load_image(
458
+ _gfx_dir: *mut u8,
459
+ _name: *const core::ffi::c_char,
460
+ ) -> *mut u8 {
461
  core::arch::naked_asm!(
462
  "pushl %esi",
463
  "movl 8(%esp), %esi", // ESI = gfx_dir
crates/openwa-wormkit/src/replacements/ddgame_init.rs CHANGED
@@ -12,6 +12,7 @@
12
  //! - `FUN_570E20` (display layer init): usercall(ESI=wrapper), plain RET
13
 
14
  use crate::hook;
 
15
  use openwa_core::address::va;
16
  use openwa_core::engine::ddgame::{
17
  bit_grid_init, ddgame_init_fields, ddgame_init_render_indices, display_layer_color_init,
@@ -84,8 +85,9 @@ extern "cdecl" fn impl_display_layer_init(wrapper: u32) -> u32 {
84
  // ─── GfxResource__Create_Maybe (0x4F6300) ───────────────────────────────────
85
 
86
  extern "cdecl" fn impl_gfx_resource_create(gfx_dir: u32, name: u32, output: u32) -> u32 {
87
- let result =
88
- unsafe { gfx_resource_create(gfx_dir as *mut u8, name as *const u8, output as *mut u8) };
 
89
  result as u32
90
  }
91
 
@@ -118,7 +120,7 @@ hook::usercall_trampoline!(
118
  static FIND_ENTRY_LOG_COUNT: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0);
119
 
120
  extern "cdecl" fn impl_find_entry(name: u32, gfx_dir: u32) -> u32 {
121
- let result = unsafe { gfx_dir_find_entry(name as *const u8, gfx_dir as *mut u8) };
122
 
123
  // Log first 20 lookups for debugging
124
  let count = FIND_ENTRY_LOG_COUNT.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
 
12
  //! - `FUN_570E20` (display layer init): usercall(ESI=wrapper), plain RET
13
 
14
  use crate::hook;
15
+ use core::ffi::c_char;
16
  use openwa_core::address::va;
17
  use openwa_core::engine::ddgame::{
18
  bit_grid_init, ddgame_init_fields, ddgame_init_render_indices, display_layer_color_init,
 
85
  // ─── GfxResource__Create_Maybe (0x4F6300) ───────────────────────────────────
86
 
87
  extern "cdecl" fn impl_gfx_resource_create(gfx_dir: u32, name: u32, output: u32) -> u32 {
88
+ let result = unsafe {
89
+ gfx_resource_create(gfx_dir as *mut u8, name as *const c_char, output as *mut u8)
90
+ };
91
  result as u32
92
  }
93
 
 
120
  static FIND_ENTRY_LOG_COUNT: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0);
121
 
122
  extern "cdecl" fn impl_find_entry(name: u32, gfx_dir: u32) -> u32 {
123
+ let result = unsafe { gfx_dir_find_entry(name as *const c_char, gfx_dir as *mut u8) };
124
 
125
  // Log first 20 lookups for debugging
126
  let count = FIND_ENTRY_LOG_COUNT.fetch_add(1, core::sync::atomic::Ordering::Relaxed);