feat: port DisplayGfx::SetFontPalette (slot 36) to pure Rust
Browse filesSlot 36 was bridging via a naked-asm trampoline to Font__SetPalette
(0x4F9F20). Replace it with a native Rust port and delete the trampoline.
The original function name is wildly misleading. Despite "SetPalette",
it actually extends the font with two new derived glyphs: it generates
'.' (0x2E) and ';' (0x3B) at runtime by copying the existing ':' (0x3A)
glyph, fills the top half of '.' with `palette_value as u8`, and copies
':' into ';' substituting any pixel matching the '8' glyph's foreground
color with the '-' glyph's foreground color. Called exactly once during
DDGame::LoadFonts for `digiwht.fnt` (slot 28, the digital seven-segment
font), which doesn't ship with those two codepoints. The full step list
is in the new docstring on `font_set_palette_impl`.
While in the area, rename `FontObject::_unknown_18` to `aux_alloc` —
both `font_extend` (the .fex loader) and the new `font_set_palette_impl`
write the address of an auxiliary glyph+pixel buffer there for the font
destructor to free, so the field has a clear semantic role now.
All 15 headless replay tests pass. Headless can't see whether the new
glyphs render correctly though — slot 36 only writes data that text
rendering reads back, so wrong byte offsets in the new buffer would
silently corrupt the digital-font glyph table without crashing the sim.
The digital font shows up in HUD elements like the turn timer; needs
visual verification that '.' and ';' look right before trusting the
port.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@@ -261,7 +261,10 @@ pub mod va {
|
|
| 261 |
/// Font object: get info — usercall(EAX=font_obj, EDX=out2, EDI=out1), plain RET.
|
| 262 |
/// Ported as `display::vtable::font_get_info_impl`; address kept for registry.
|
| 263 |
fn/Usercall FONT_OBJ_GET_INFO = 0x004F_A7D0;
|
| 264 |
-
/// Font object: set palette — usercall(ESI=font_obj) + 1 stack(palette_value), RET 0x4
|
|
|
|
|
|
|
|
|
|
| 265 |
fn/Usercall FONT_OBJ_SET_PALETTE = 0x004F_9F20;
|
| 266 |
}
|
| 267 |
|
|
|
|
| 261 |
/// Font object: get info — usercall(EAX=font_obj, EDX=out2, EDI=out1), plain RET.
|
| 262 |
/// Ported as `display::vtable::font_get_info_impl`; address kept for registry.
|
| 263 |
fn/Usercall FONT_OBJ_GET_INFO = 0x004F_A7D0;
|
| 264 |
+
/// Font object: "set palette" — usercall(ESI=font_obj) + 1 stack(palette_value), RET 0x4.
|
| 265 |
+
/// Misnamed in the original — actually extends `digiwht.fnt` with
|
| 266 |
+
/// derived `'.'` and `';'` glyphs at runtime. Ported as
|
| 267 |
+
/// `display::vtable::font_set_palette_impl`; address kept for registry.
|
| 268 |
fn/Usercall FONT_OBJ_SET_PALETTE = 0x004F_9F20;
|
| 269 |
}
|
| 270 |
|
|
@@ -2119,8 +2119,14 @@ pub struct FontObject {
|
|
| 2119 |
pub pixel_data: *mut u8,
|
| 2120 |
/// 0x14: Zeroed by `load_font`; purpose unknown.
|
| 2121 |
pub _unknown_14: u32,
|
| 2122 |
-
/// 0x18:
|
| 2123 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2124 |
}
|
| 2125 |
|
| 2126 |
const _: () = assert!(core::mem::size_of::<FontObject>() == 0x1C);
|
|
@@ -2434,7 +2440,7 @@ pub unsafe fn load_font(
|
|
| 2434 |
/// - computes a tight bounding box per new glyph and writes it as a new entry
|
| 2435 |
/// - remaps every new pixel byte through the LUT
|
| 2436 |
/// - swaps `font_obj.glyph_table` to the new buffer and bumps `font_obj.height`
|
| 2437 |
-
/// - records the allocation in `font_obj.
|
| 2438 |
///
|
| 2439 |
/// The `pixel_offset` field in each new glyph entry stores
|
| 2440 |
/// `(absolute_pixel_addr - font_obj.pixel_data)` so the existing
|
|
@@ -2507,7 +2513,7 @@ pub unsafe fn font_extend(
|
|
| 2507 |
let new_pixels = alloc.add(glyph_entries_bytes as usize);
|
| 2508 |
|
| 2509 |
// Record the allocation so font cleanup paths can free it.
|
| 2510 |
-
(*font_obj).
|
| 2511 |
|
| 2512 |
// ── Copy existing glyph entries verbatim into the new buffer ──
|
| 2513 |
let old_glyphs = (*font_obj).glyph_table as *const u8;
|
|
@@ -2928,3 +2934,217 @@ pub unsafe extern "thiscall" fn set_font_param(
|
|
| 2928 |
font_set_param_impl(font_obj, p3 as *const u8, p4 as *mut i32, p5 as *mut i32);
|
| 2929 |
1
|
| 2930 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2119 |
pub pixel_data: *mut u8,
|
| 2120 |
/// 0x14: Zeroed by `load_font`; purpose unknown.
|
| 2121 |
pub _unknown_14: u32,
|
| 2122 |
+
/// 0x18: When non-null, holds the address of an auxiliary allocation
|
| 2123 |
+
/// owned by this font (a separate buffer of glyph entries + pixel data
|
| 2124 |
+
/// pointed at by individual `GlyphEntry::pixel_offset` deltas). Zeroed
|
| 2125 |
+
/// by `load_font`; written by `font_extend` (which appends new glyphs
|
| 2126 |
+
/// from a `.fex` file) and `font_set_palette_impl` (which derives the
|
| 2127 |
+
/// `.`/`;` glyphs for the digital font). The cleanup path frees this
|
| 2128 |
+
/// when the FontObject is destroyed.
|
| 2129 |
+
pub aux_alloc: u32,
|
| 2130 |
}
|
| 2131 |
|
| 2132 |
const _: () = assert!(core::mem::size_of::<FontObject>() == 0x1C);
|
|
|
|
| 2440 |
/// - computes a tight bounding box per new glyph and writes it as a new entry
|
| 2441 |
/// - remaps every new pixel byte through the LUT
|
| 2442 |
/// - swaps `font_obj.glyph_table` to the new buffer and bumps `font_obj.height`
|
| 2443 |
+
/// - records the allocation in `font_obj.aux_alloc`
|
| 2444 |
///
|
| 2445 |
/// The `pixel_offset` field in each new glyph entry stores
|
| 2446 |
/// `(absolute_pixel_addr - font_obj.pixel_data)` so the existing
|
|
|
|
| 2513 |
let new_pixels = alloc.add(glyph_entries_bytes as usize);
|
| 2514 |
|
| 2515 |
// Record the allocation so font cleanup paths can free it.
|
| 2516 |
+
(*font_obj).aux_alloc = alloc as u32;
|
| 2517 |
|
| 2518 |
// ── Copy existing glyph entries verbatim into the new buffer ──
|
| 2519 |
let old_glyphs = (*font_obj).glyph_table as *const u8;
|
|
|
|
| 2934 |
font_set_param_impl(font_obj, p3 as *const u8, p4 as *mut i32, p5 as *mut i32);
|
| 2935 |
1
|
| 2936 |
}
|
| 2937 |
+
|
| 2938 |
+
/// Pure-Rust port of `Font__SetPalette` (0x4F9F20).
|
| 2939 |
+
///
|
| 2940 |
+
/// **The function name is misleading** — despite "SetPalette", this routine
|
| 2941 |
+
/// extends the font with two new derived glyphs rather than recoloring an
|
| 2942 |
+
/// existing palette. It is called once during `DDGame__LoadFonts` for the
|
| 2943 |
+
/// digital seven-segment font (`digiwht.fnt`, slot 28), which doesn't ship
|
| 2944 |
+
/// with `'.'` or `';'` glyphs and needs them generated at runtime.
|
| 2945 |
+
///
|
| 2946 |
+
/// What it does, in order:
|
| 2947 |
+
///
|
| 2948 |
+
/// 1. Look up the **`'-'`** (0x2D), **`'8'`** (0x38) and **`':'`** (0x3A)
|
| 2949 |
+
/// glyph indices via `char_to_glyph_idx`. If any is missing, return 0.
|
| 2950 |
+
/// 2. Sample the foreground-color palette indices of `'-'` and `'8'` by
|
| 2951 |
+
/// reading byte +5 within each glyph's pixel data. Save them as
|
| 2952 |
+
/// `minus_fg` and `eight_fg`.
|
| 2953 |
+
/// 3. Allocate a new buffer sized for `(old_height + 2)` glyph entries
|
| 2954 |
+
/// plus enough pixel area for **two** glyphs the size of `':'`.
|
| 2955 |
+
/// 4. Copy all existing glyph entries verbatim into the start of the
|
| 2956 |
+
/// buffer.
|
| 2957 |
+
/// 5. Add two new glyph entries:
|
| 2958 |
+
/// - `char_to_glyph_idx[0x2E]` (= `'.'`) → 1-based index `old_height + 1`
|
| 2959 |
+
/// - `char_to_glyph_idx[0x3B]` (= `';'`) → 1-based index `old_height + 2`
|
| 2960 |
+
///
|
| 2961 |
+
/// Both new entries copy `start_x`/`start_y`/`width`/`height` from the
|
| 2962 |
+
/// `':'` glyph. Their `pixel_offset` fields point at consecutive
|
| 2963 |
+
/// `colon_height * font_width`-byte regions inside the new buffer.
|
| 2964 |
+
/// 6. Initialize the **first** new glyph (`'.'`)'s pixel area:
|
| 2965 |
+
/// - `memset(area, palette_value as u8, colon_height * font_width / 2)`
|
| 2966 |
+
/// — fills approximately the top half with a uniform palette index.
|
| 2967 |
+
/// - For rows `colon_height/2 .. colon_height-1`, copy `colon.width`
|
| 2968 |
+
/// bytes per row from `':'`'s pixel data into the new buffer at
|
| 2969 |
+
/// `font_width`-strided rows.
|
| 2970 |
+
/// 7. Initialize the **second** new glyph (`';'`)'s pixel area: for every
|
| 2971 |
+
/// `(row, col)` in `(0..colon.height, 0..colon.width)`, copy the
|
| 2972 |
+
/// `':'` source pixel; if it equals `eight_fg`, replace it with
|
| 2973 |
+
/// `minus_fg` instead.
|
| 2974 |
+
/// 8. Update `font_obj.glyph_table` to point at the new buffer, store the
|
| 2975 |
+
/// new buffer in `aux_alloc` (so destructors can free it), and bump
|
| 2976 |
+
/// `font_obj.height` by 2.
|
| 2977 |
+
///
|
| 2978 |
+
/// The original uses `wa_malloc(round_up_to_4(total_size) + 0x20)` and
|
| 2979 |
+
/// zero-initializes the body up to `total_size` (the trailing 0x20 padding
|
| 2980 |
+
/// is left uninitialized).
|
| 2981 |
+
///
|
| 2982 |
+
/// # Safety
|
| 2983 |
+
/// `font_obj` must be a valid mutable `FontObject`. `palette_value`'s low
|
| 2984 |
+
/// byte is used as a single-byte memset filler. The original's
|
| 2985 |
+
/// allocate/copy/update sequence is preserved verbatim.
|
| 2986 |
+
pub unsafe fn font_set_palette_impl(font_obj: *mut FontObject, palette_value: u32) -> u32 {
|
| 2987 |
+
use crate::wa_alloc::wa_malloc;
|
| 2988 |
+
|
| 2989 |
+
let char_to_glyph = (*font_obj).char_to_glyph_idx;
|
| 2990 |
+
if char_to_glyph.is_null() {
|
| 2991 |
+
return 0;
|
| 2992 |
+
}
|
| 2993 |
+
|
| 2994 |
+
// Step 1: '-' (0x2D) glyph index.
|
| 2995 |
+
let minus_idx = *char_to_glyph.add(0x2D);
|
| 2996 |
+
if minus_idx == 0 {
|
| 2997 |
+
return 0;
|
| 2998 |
+
}
|
| 2999 |
+
|
| 3000 |
+
// Step 2a: read byte +5 of '-' glyph's pixel data.
|
| 3001 |
+
let glyph_table = (*font_obj).glyph_table;
|
| 3002 |
+
let pixel_data = (*font_obj).pixel_data;
|
| 3003 |
+
let minus_glyph = glyph_table.add(minus_idx as usize - 1);
|
| 3004 |
+
let minus_fg = *pixel_data.add((*minus_glyph).pixel_offset as usize + 5);
|
| 3005 |
+
|
| 3006 |
+
// Step 2b: '8' (0x38) glyph index + byte +5.
|
| 3007 |
+
let eight_idx = *char_to_glyph.add(0x38);
|
| 3008 |
+
if eight_idx == 0 {
|
| 3009 |
+
return 0;
|
| 3010 |
+
}
|
| 3011 |
+
let eight_glyph = glyph_table.add(eight_idx as usize - 1);
|
| 3012 |
+
let eight_fg = *pixel_data.add((*eight_glyph).pixel_offset as usize + 5);
|
| 3013 |
+
|
| 3014 |
+
// Step 1c: ':' (0x3A) — required for the template.
|
| 3015 |
+
let colon_idx = *char_to_glyph.add(0x3A);
|
| 3016 |
+
if colon_idx == 0 {
|
| 3017 |
+
return 0;
|
| 3018 |
+
}
|
| 3019 |
+
|
| 3020 |
+
let old_height = (*font_obj).height as i32; // signed via MOVSX in the original
|
| 3021 |
+
let new_height = old_height + 2;
|
| 3022 |
+
let font_width = (*font_obj).width as i16 as i32;
|
| 3023 |
+
|
| 3024 |
+
// Step 3: compute total size and allocate.
|
| 3025 |
+
// total_size = (colon.height * font_width + new_height * 6) * 2
|
| 3026 |
+
// = colon_height * font_width * 2 + new_height * 12
|
| 3027 |
+
// alloc = round_up_to_dword(total_size) + 0x20
|
| 3028 |
+
let colon_glyph = glyph_table.add(colon_idx as usize - 1);
|
| 3029 |
+
let colon_height = (*colon_glyph).height as i32;
|
| 3030 |
+
let colon_width = (*colon_glyph).width as i32;
|
| 3031 |
+
let colon_pixel_offset = (*colon_glyph).pixel_offset as usize;
|
| 3032 |
+
|
| 3033 |
+
let total_size = (colon_height * font_width + new_height * 6) * 2;
|
| 3034 |
+
let alloc_size = ((total_size as u32 + 3) & !3u32) + 0x20;
|
| 3035 |
+
let new_buffer = wa_malloc(alloc_size);
|
| 3036 |
+
if new_buffer.is_null() {
|
| 3037 |
+
return 0;
|
| 3038 |
+
}
|
| 3039 |
+
// Zero-init the body (not the trailing 0x20 padding).
|
| 3040 |
+
core::ptr::write_bytes(new_buffer, 0, total_size as usize);
|
| 3041 |
+
|
| 3042 |
+
// _Dst = new_buffer + new_height*12 = where pixel data starts in the new buffer.
|
| 3043 |
+
let new_glyph_table = new_buffer as *mut GlyphEntry;
|
| 3044 |
+
let new_pixel_area = new_buffer.add((new_height as usize) * 12);
|
| 3045 |
+
|
| 3046 |
+
// Save the allocation in aux_alloc so cleanup paths can free it
|
| 3047 |
+
// (the original writes this *before* the copy loop).
|
| 3048 |
+
(*font_obj).aux_alloc = new_buffer as u32;
|
| 3049 |
+
|
| 3050 |
+
// Step 4: copy existing glyph entries.
|
| 3051 |
+
if old_height > 0 {
|
| 3052 |
+
core::ptr::copy_nonoverlapping(
|
| 3053 |
+
glyph_table as *const u8,
|
| 3054 |
+
new_buffer,
|
| 3055 |
+
(old_height as usize) * 12,
|
| 3056 |
+
);
|
| 3057 |
+
}
|
| 3058 |
+
|
| 3059 |
+
// Step 5: write new char_to_glyph_idx entries for '.' and ';'.
|
| 3060 |
+
*char_to_glyph.add(0x2E) = (old_height as u8).wrapping_add(1);
|
| 3061 |
+
*char_to_glyph.add(0x3B) = (old_height as u8).wrapping_add(2);
|
| 3062 |
+
|
| 3063 |
+
// Step 5b: first new glyph (= colon copy with adjusted pixel_offset).
|
| 3064 |
+
// pixel_offset = (_Dst - pixel_data)
|
| 3065 |
+
let new_first = new_glyph_table.add(old_height as usize);
|
| 3066 |
+
(*new_first).start_x = (*colon_glyph).start_x;
|
| 3067 |
+
(*new_first).start_y = (*colon_glyph).start_y;
|
| 3068 |
+
(*new_first).width = (*colon_glyph).width;
|
| 3069 |
+
(*new_first).height = (*colon_glyph).height;
|
| 3070 |
+
(*new_first).pixel_offset = (new_pixel_area as u32).wrapping_sub(pixel_data as u32);
|
| 3071 |
+
|
| 3072 |
+
// Step 5c: second new glyph (= duplicate of first new glyph, but its
|
| 3073 |
+
// pixel_offset is bumped by colon_height * font_width so it points to
|
| 3074 |
+
// the *next* chunk of new pixel data).
|
| 3075 |
+
let new_second = new_first.add(1);
|
| 3076 |
+
(*new_second).start_x = (*new_first).start_x;
|
| 3077 |
+
(*new_second).start_y = (*new_first).start_y;
|
| 3078 |
+
(*new_second).width = (*new_first).width;
|
| 3079 |
+
(*new_second).height = (*new_first).height;
|
| 3080 |
+
(*new_second).pixel_offset = (*new_first)
|
| 3081 |
+
.pixel_offset
|
| 3082 |
+
.wrapping_add((colon_height * font_width) as u32);
|
| 3083 |
+
|
| 3084 |
+
// Step 6a: memset top portion of FIRST new glyph with palette_value's
|
| 3085 |
+
// low byte. Length = (colon_height * font_width) with sign-correct /2.
|
| 3086 |
+
let memset_len = {
|
| 3087 |
+
let v = colon_height.wrapping_mul(font_width);
|
| 3088 |
+
// CDQ + SUB EAX,EDX + SAR EAX,1 = signed div by 2 with rounding toward zero
|
| 3089 |
+
let v_signed = v;
|
| 3090 |
+
let cdq = v_signed >> 31;
|
| 3091 |
+
((v_signed - cdq) >> 1) as usize
|
| 3092 |
+
};
|
| 3093 |
+
core::ptr::write_bytes(new_pixel_area, palette_value as u8, memset_len);
|
| 3094 |
+
|
| 3095 |
+
// Step 6b: copy bottom half rows of ':' into FIRST new glyph at
|
| 3096 |
+
// font-width row stride.
|
| 3097 |
+
let half = (colon_height as u32 >> 1) as i32;
|
| 3098 |
+
if half < colon_height {
|
| 3099 |
+
for row in half..colon_height {
|
| 3100 |
+
let src = pixel_data.add(colon_pixel_offset + (row * colon_width) as usize);
|
| 3101 |
+
let dst = new_pixel_area.add((row * font_width) as usize);
|
| 3102 |
+
core::ptr::copy_nonoverlapping(src, dst, colon_width as usize);
|
| 3103 |
+
}
|
| 3104 |
+
}
|
| 3105 |
+
|
| 3106 |
+
// Step 7: pixel-by-pixel copy for SECOND new glyph with eight→minus
|
| 3107 |
+
// foreground substitution. The destination is offset by
|
| 3108 |
+
// colon_height * font_width within new_pixel_area.
|
| 3109 |
+
if colon_height > 0 {
|
| 3110 |
+
for row in 0..colon_height {
|
| 3111 |
+
for col in 0..colon_width {
|
| 3112 |
+
let src_addr =
|
| 3113 |
+
pixel_data.add(colon_pixel_offset + (row * colon_width + col) as usize);
|
| 3114 |
+
let dst_addr =
|
| 3115 |
+
new_pixel_area.add(((colon_height + row) * font_width + col) as usize);
|
| 3116 |
+
let src_byte = *src_addr;
|
| 3117 |
+
if src_byte == eight_fg {
|
| 3118 |
+
*dst_addr = minus_fg;
|
| 3119 |
+
} else {
|
| 3120 |
+
*dst_addr = src_byte;
|
| 3121 |
+
}
|
| 3122 |
+
}
|
| 3123 |
+
}
|
| 3124 |
+
}
|
| 3125 |
+
|
| 3126 |
+
// Step 8: update font_obj fields.
|
| 3127 |
+
(*font_obj).glyph_table = new_glyph_table;
|
| 3128 |
+
(*font_obj).height = new_height as u16;
|
| 3129 |
+
1
|
| 3130 |
+
}
|
| 3131 |
+
|
| 3132 |
+
/// Port of `DisplayGfx::SetFontPalette` (vtable slot 36, 0x523690).
|
| 3133 |
+
///
|
| 3134 |
+
/// Despite the name, this is the entry point for `font_set_palette_impl` —
|
| 3135 |
+
/// see that function's doc for what it actually does (it extends the
|
| 3136 |
+
/// digital font with derived `'.'` and `';'` glyphs). The wrapper is just
|
| 3137 |
+
/// a thin index lookup into `font_table`; the original has no bounds or
|
| 3138 |
+
/// null check on the index, so we mirror that.
|
| 3139 |
+
///
|
| 3140 |
+
/// # Safety
|
| 3141 |
+
/// `this` must be a valid `*mut DisplayGfx` and `font_index` must be a
|
| 3142 |
+
/// valid index into `font_table` whose entry is a non-null `FontObject`.
|
| 3143 |
+
pub unsafe extern "thiscall" fn set_font_palette(
|
| 3144 |
+
this: *mut DisplayGfx,
|
| 3145 |
+
font_index: u32,
|
| 3146 |
+
palette_value: u32,
|
| 3147 |
+
) {
|
| 3148 |
+
let font_obj = (*this).base.font_table[font_index as usize] as *mut FontObject;
|
| 3149 |
+
let _ = font_set_palette_impl(font_obj, palette_value);
|
| 3150 |
+
}
|
|
@@ -1296,39 +1296,10 @@ unsafe extern "thiscall" fn draw_scaled_sprite(
|
|
| 1296 |
// Font vtable method bridges and implementations
|
| 1297 |
// =========================================================================
|
| 1298 |
//
|
| 1299 |
-
// Font
|
| 1300 |
-
//
|
| 1301 |
-
//
|
| 1302 |
-
|
| 1303 |
-
/// Port of DisplayGfx::SetFontPalette (vtable slot 36, 0x523690).
|
| 1304 |
-
///
|
| 1305 |
-
/// Loads font object from font_table[font_count], then calls
|
| 1306 |
-
/// Font__SetPalette (0x4f9f20): usercall(ESI=font_obj) + stack(palette_value), RET 0x4.
|
| 1307 |
-
///
|
| 1308 |
-
/// The original has NO bounds check on font_count — it trusts the caller.
|
| 1309 |
-
unsafe extern "thiscall" fn set_font_palette(
|
| 1310 |
-
this: *mut DisplayGfx,
|
| 1311 |
-
font_count: u32,
|
| 1312 |
-
palette_value: u32,
|
| 1313 |
-
) {
|
| 1314 |
-
let font_obj = (*this).base.font_table[font_count as usize];
|
| 1315 |
-
wa_font_set_palette(font_obj, palette_value, rb(va::FONT_OBJ_SET_PALETTE));
|
| 1316 |
-
}
|
| 1317 |
-
|
| 1318 |
-
/// Bridge to Font__SetPalette (0x4f9f20).
|
| 1319 |
-
/// Usercall: ESI=font_obj, stack(palette_value), RET 0x4.
|
| 1320 |
-
#[unsafe(naked)]
|
| 1321 |
-
unsafe extern "cdecl" fn wa_font_set_palette(_font_obj: u32, _palette_value: u32, _target: u32) {
|
| 1322 |
-
core::arch::naked_asm!(
|
| 1323 |
-
"push esi",
|
| 1324 |
-
"mov esi, [esp+8]", // font_obj
|
| 1325 |
-
"mov ecx, [esp+16]", // target
|
| 1326 |
-
"push dword ptr [esp+12]", // palette_value
|
| 1327 |
-
"call ecx", // RET 0x4 cleans 1 param
|
| 1328 |
-
"pop esi",
|
| 1329 |
-
"ret",
|
| 1330 |
-
);
|
| 1331 |
-
}
|
| 1332 |
|
| 1333 |
/// Port of DisplayGfx::DrawTextOnBitmap (vtable slot 7, 0x5236B0).
|
| 1334 |
///
|
|
@@ -1552,7 +1523,7 @@ fn install_display() -> Result<(), String> {
|
|
| 1552 |
draw_scaled_sprite => draw_scaled_sprite,
|
| 1553 |
set_layer_visibility => display_vtable::set_layer_visibility,
|
| 1554 |
update_palette => display_vtable::update_palette,
|
| 1555 |
-
set_font_palette => set_font_palette,
|
| 1556 |
slot 19 => blit_sprite,
|
| 1557 |
load_sprite_by_layer => load_sprite_by_layer,
|
| 1558 |
load_font => load_font,
|
|
|
|
| 1296 |
// Font vtable method bridges and implementations
|
| 1297 |
// =========================================================================
|
| 1298 |
//
|
| 1299 |
+
// Font slot wrappers (slots 7/8/9/10/34/35/36) all live in openwa-core's
|
| 1300 |
+
// `display::vtable` module. The wrappers below for slots 7/31/34/35/37 are
|
| 1301 |
+
// thin forwarders only because they need to capture a bridge function
|
| 1302 |
+
// pointer (`wa_load_sprite_from_vfs` etc.) at install time.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1303 |
|
| 1304 |
/// Port of DisplayGfx::DrawTextOnBitmap (vtable slot 7, 0x5236B0).
|
| 1305 |
///
|
|
|
|
| 1523 |
draw_scaled_sprite => draw_scaled_sprite,
|
| 1524 |
set_layer_visibility => display_vtable::set_layer_visibility,
|
| 1525 |
update_palette => display_vtable::update_palette,
|
| 1526 |
+
set_font_palette => display_vtable::set_font_palette,
|
| 1527 |
slot 19 => blit_sprite,
|
| 1528 |
load_sprite_by_layer => load_sprite_by_layer,
|
| 1529 |
load_font => load_font,
|