feat: port DisplayGfx font vtable methods (slots 7-10, 36) to Rust
Browse filesPort 5 font-related DisplayGfx vtable methods as thin wrappers that
validate font_id bounds, look up the font object, then delegate to
the internal WA font functions via naked asm bridges.
- Slot 7: draw_text_on_bitmap (usercall EAX=bitmap, EDX=a8, ESI=font)
- Slot 8: get_font_info (usercall EAX=font, EDX=out2, EDI=out1)
- Slot 9: get_font_metric (usercall AL=char, EDX=out1, EDI=out2)
- Slot 10: set_font_param (usercall ECX=p4, EDX=font)
- Slot 36: set_font_palette (usercall ESI=font)
Also fixes vtable param counts for slots 8 and 9, adds 0x3C (CMP AL)
to valid startup check prologues, and adds FONT_OBJ_* address constants.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
crates/openwa-core/src/address.rs
CHANGED
|
@@ -241,6 +241,19 @@ pub mod va {
|
|
| 241 |
fn/Thiscall DISPLAY_GFX_LOAD_SPRITE_EX = 0x0052_3310;
|
| 242 |
}
|
| 243 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 244 |
/// "sprite" type-tag string in .rdata β returned by Sprite/SpriteBank GetInfo
|
| 245 |
global STR_SPRITE = 0x0066_4170;
|
| 246 |
|
|
|
|
| 241 |
fn/Thiscall DISPLAY_GFX_LOAD_SPRITE_EX = 0x0052_3310;
|
| 242 |
}
|
| 243 |
|
| 244 |
+
class "Font" {
|
| 245 |
+
/// Font object: draw text β usercall(EAX=h_align, EDX=bitmap, ESI=font_obj) + 5 stack, RET 0x14
|
| 246 |
+
fn/Usercall FONT_OBJ_DRAW_TEXT = 0x004F_A4E0;
|
| 247 |
+
/// Font object: set param β usercall(ECX=p4, EDX=font_obj) + 2 stack(p3, p5), RET 0x8
|
| 248 |
+
fn/Usercall FONT_OBJ_SET_PARAM = 0x004F_A720;
|
| 249 |
+
/// Font object: get metric β usercall(AL=char, EDX=out1, EDI=out2) + 1 stack(font_obj), RET 0x4
|
| 250 |
+
fn/Usercall FONT_OBJ_GET_METRIC = 0x004F_A780;
|
| 251 |
+
/// Font object: get info β usercall(EAX=font_obj, EDX=out2, EDI=out1), plain RET
|
| 252 |
+
fn/Usercall FONT_OBJ_GET_INFO = 0x004F_A7D0;
|
| 253 |
+
/// Font object: set palette β usercall(ESI=font_obj) + 1 stack(palette_value), RET 0x4
|
| 254 |
+
fn/Usercall FONT_OBJ_SET_PALETTE = 0x004F_9F20;
|
| 255 |
+
}
|
| 256 |
+
|
| 257 |
/// "sprite" type-tag string in .rdata β returned by Sprite/SpriteBank GetInfo
|
| 258 |
global STR_SPRITE = 0x0066_4170;
|
| 259 |
|
crates/openwa-core/src/render/display/vtable.rs
CHANGED
|
@@ -75,11 +75,25 @@ pub struct DisplayVtable {
|
|
| 75 |
a8: i32,
|
| 76 |
) -> i32,
|
| 77 |
/// get font info for a font slot (0x523790, RET 0xC)
|
|
|
|
|
|
|
|
|
|
| 78 |
#[slot(8)]
|
| 79 |
-
pub get_font_info:
|
| 80 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
#[slot(9)]
|
| 82 |
-
pub get_font_metric: fn(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 83 |
/// set font rendering parameter (0x523710, RET 0x10)
|
| 84 |
#[slot(10)]
|
| 85 |
pub set_font_param: fn(this: *mut DisplayGfx, font_id: i32, p3: u32, p4: u32, p5: u32) -> u32,
|
|
|
|
| 75 |
a8: i32,
|
| 76 |
) -> i32,
|
| 77 |
/// get font info for a font slot (0x523790, RET 0xC)
|
| 78 |
+
///
|
| 79 |
+
/// Reads two signed shorts from the font object and writes them to output pointers.
|
| 80 |
+
/// Returns 1 on success, 0 if font_id is out of range or font slot is empty.
|
| 81 |
#[slot(8)]
|
| 82 |
+
pub get_font_info:
|
| 83 |
+
fn(this: *mut DisplayGfx, font_id: i32, out_1: *mut u32, out_2: *mut u32) -> u32,
|
| 84 |
+
/// get font metric for a character (0x523750, RET 0x10)
|
| 85 |
+
///
|
| 86 |
+
/// Queries character metrics from the font object. `char_code` is passed
|
| 87 |
+
/// as a byte (low 8 bits). Returns result via two output pointers.
|
| 88 |
+
/// Returns 1 on success, 0 if font_id is out of range or font slot is empty.
|
| 89 |
#[slot(9)]
|
| 90 |
+
pub get_font_metric: fn(
|
| 91 |
+
this: *mut DisplayGfx,
|
| 92 |
+
font_id: i32,
|
| 93 |
+
char_code: u32,
|
| 94 |
+
out_1: *mut u32,
|
| 95 |
+
out_2: *mut u32,
|
| 96 |
+
) -> u32,
|
| 97 |
/// set font rendering parameter (0x523710, RET 0x10)
|
| 98 |
#[slot(10)]
|
| 99 |
pub set_font_param: fn(this: *mut DisplayGfx, font_id: i32, p3: u32, p4: u32, p5: u32) -> u32,
|
crates/openwa-dll/src/replacements/render.rs
CHANGED
|
@@ -1306,6 +1306,259 @@ unsafe extern "thiscall" fn draw_scaled_sprite(
|
|
| 1306 |
}
|
| 1307 |
}
|
| 1308 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1309 |
// ---------------------------------------------------------------------------
|
| 1310 |
// Display installation
|
| 1311 |
// ---------------------------------------------------------------------------
|
|
@@ -1347,6 +1600,10 @@ fn install_display() -> Result<(), String> {
|
|
| 1347 |
set_layer_color => display_vtable::set_layer_color,
|
| 1348 |
set_active_layer => display_vtable::set_active_layer,
|
| 1349 |
get_sprite_info => display_vtable::get_sprite_info,
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1350 |
draw_polyline => display_vtable::draw_polyline,
|
| 1351 |
draw_line => display_vtable::draw_line,
|
| 1352 |
draw_line_clipped => display_vtable::draw_line_clipped,
|
|
@@ -1363,9 +1620,10 @@ fn install_display() -> Result<(), String> {
|
|
| 1363 |
draw_scaled_sprite => draw_scaled_sprite,
|
| 1364 |
set_layer_visibility => display_vtable::set_layer_visibility,
|
| 1365 |
update_palette => display_vtable::update_palette,
|
|
|
|
| 1366 |
slot 19 => blit_sprite,
|
| 1367 |
})?;
|
| 1368 |
-
let _ = log_line("[Display] DisplayGfx: patched
|
| 1369 |
}
|
| 1370 |
|
| 1371 |
Ok(())
|
|
|
|
| 1306 |
}
|
| 1307 |
}
|
| 1308 |
|
| 1309 |
+
// =========================================================================
|
| 1310 |
+
// Font vtable method bridges and implementations
|
| 1311 |
+
// =========================================================================
|
| 1312 |
+
//
|
| 1313 |
+
// Font methods are thin wrappers: validate font_id (1..31), check font slot
|
| 1314 |
+
// is populated, then delegate to an internal usercall function on the font
|
| 1315 |
+
// object. The font object pointer is stored at DisplayBase+0x309C[font_id].
|
| 1316 |
+
|
| 1317 |
+
/// Port of DisplayGfx::SetFontPalette (vtable slot 36, 0x523690).
|
| 1318 |
+
///
|
| 1319 |
+
/// Loads font object from font_table[font_count], then calls
|
| 1320 |
+
/// Font__SetPalette (0x4f9f20): usercall(ESI=font_obj) + stack(palette_value), RET 0x4.
|
| 1321 |
+
///
|
| 1322 |
+
/// The original has NO bounds check on font_count β it trusts the caller.
|
| 1323 |
+
unsafe extern "thiscall" fn set_font_palette(
|
| 1324 |
+
this: *mut DisplayGfx,
|
| 1325 |
+
font_count: u32,
|
| 1326 |
+
palette_value: u32,
|
| 1327 |
+
) {
|
| 1328 |
+
let font_obj = (*this).base.font_table[font_count as usize];
|
| 1329 |
+
wa_font_set_palette(font_obj, palette_value, rb(va::FONT_OBJ_SET_PALETTE));
|
| 1330 |
+
}
|
| 1331 |
+
|
| 1332 |
+
/// Bridge to Font__SetPalette (0x4f9f20).
|
| 1333 |
+
/// Usercall: ESI=font_obj, stack(palette_value), RET 0x4.
|
| 1334 |
+
#[unsafe(naked)]
|
| 1335 |
+
unsafe extern "cdecl" fn wa_font_set_palette(_font_obj: u32, _palette_value: u32, _target: u32) {
|
| 1336 |
+
core::arch::naked_asm!(
|
| 1337 |
+
"push esi",
|
| 1338 |
+
"mov esi, [esp+8]", // font_obj
|
| 1339 |
+
"mov ecx, [esp+16]", // target
|
| 1340 |
+
"push dword ptr [esp+12]", // palette_value
|
| 1341 |
+
"call ecx", // RET 0x4 cleans 1 param
|
| 1342 |
+
"pop esi",
|
| 1343 |
+
"ret",
|
| 1344 |
+
);
|
| 1345 |
+
}
|
| 1346 |
+
|
| 1347 |
+
/// Port of DisplayGfx::SetFontParam (vtable slot 10, 0x523710).
|
| 1348 |
+
///
|
| 1349 |
+
/// Validates font_id, then calls Font__SetParam (0x4fa720):
|
| 1350 |
+
/// usercall(ECX=p4, EDX=font_obj) + stack(p3, p5), RET 0x8.
|
| 1351 |
+
unsafe extern "thiscall" fn set_font_param(
|
| 1352 |
+
this: *mut DisplayGfx,
|
| 1353 |
+
font_id: i32,
|
| 1354 |
+
p3: u32,
|
| 1355 |
+
p4: u32,
|
| 1356 |
+
p5: u32,
|
| 1357 |
+
) -> u32 {
|
| 1358 |
+
if !(1..=31).contains(&font_id) {
|
| 1359 |
+
return 0;
|
| 1360 |
+
}
|
| 1361 |
+
let font_obj = (*this).base.font_table[font_id as usize];
|
| 1362 |
+
if font_obj == 0 {
|
| 1363 |
+
return 0;
|
| 1364 |
+
}
|
| 1365 |
+
wa_font_set_param(font_obj, p3, p4, p5, rb(va::FONT_OBJ_SET_PARAM));
|
| 1366 |
+
1
|
| 1367 |
+
}
|
| 1368 |
+
|
| 1369 |
+
/// Bridge to Font__SetParam (0x4fa720).
|
| 1370 |
+
/// Usercall: ECX=p4, EDX=font_obj, stack(p3, p5), RET 0x8.
|
| 1371 |
+
#[unsafe(naked)]
|
| 1372 |
+
unsafe extern "cdecl" fn wa_font_set_param(
|
| 1373 |
+
_font_obj: u32,
|
| 1374 |
+
_p3: u32,
|
| 1375 |
+
_p4: u32,
|
| 1376 |
+
_p5: u32,
|
| 1377 |
+
_target: u32,
|
| 1378 |
+
) {
|
| 1379 |
+
core::arch::naked_asm!(
|
| 1380 |
+
"mov edx, [esp+4]", // font_obj β EDX
|
| 1381 |
+
"mov ecx, [esp+12]", // p4 β ECX
|
| 1382 |
+
"mov eax, [esp+20]", // target
|
| 1383 |
+
"push dword ptr [esp+16]", // p5
|
| 1384 |
+
"push dword ptr [esp+12]", // p3 (shifted +4 by push)
|
| 1385 |
+
"call eax", // RET 0x8 cleans 2 params
|
| 1386 |
+
"ret",
|
| 1387 |
+
);
|
| 1388 |
+
}
|
| 1389 |
+
|
| 1390 |
+
/// Port of DisplayGfx::GetFontInfo (vtable slot 8, 0x523790).
|
| 1391 |
+
///
|
| 1392 |
+
/// Validates font_id, then calls Font__GetInfo (0x4fa7d0):
|
| 1393 |
+
/// usercall(EAX=font_obj, EDX=out_1, EDI=out_2), plain RET.
|
| 1394 |
+
unsafe extern "thiscall" fn get_font_info(
|
| 1395 |
+
this: *mut DisplayGfx,
|
| 1396 |
+
font_id: i32,
|
| 1397 |
+
out_1: *mut u32,
|
| 1398 |
+
out_2: *mut u32,
|
| 1399 |
+
) -> u32 {
|
| 1400 |
+
if !(1..=31).contains(&font_id) {
|
| 1401 |
+
return 0;
|
| 1402 |
+
}
|
| 1403 |
+
let font_obj = (*this).base.font_table[font_id as usize];
|
| 1404 |
+
if font_obj == 0 {
|
| 1405 |
+
return 0;
|
| 1406 |
+
}
|
| 1407 |
+
wa_font_get_info(font_obj, out_1, out_2, rb(va::FONT_OBJ_GET_INFO))
|
| 1408 |
+
}
|
| 1409 |
+
|
| 1410 |
+
/// Bridge to Font__GetInfo (0x4fa7d0).
|
| 1411 |
+
/// Usercall: EAX=font_obj, EDX=out_2, EDI=out_1, no stack params, plain RET.
|
| 1412 |
+
///
|
| 1413 |
+
/// Register mapping verified from caller at 0x523790:
|
| 1414 |
+
/// EDX β [ESP+0xC] = out_2 (3rd vtable param)
|
| 1415 |
+
/// EDI β [ESP+0x8] after PUSH EDI = out_1 (2nd vtable param)
|
| 1416 |
+
#[unsafe(naked)]
|
| 1417 |
+
unsafe extern "cdecl" fn wa_font_get_info(
|
| 1418 |
+
_font_obj: u32,
|
| 1419 |
+
_out_1: *mut u32,
|
| 1420 |
+
_out_2: *mut u32,
|
| 1421 |
+
_target: u32,
|
| 1422 |
+
) -> u32 {
|
| 1423 |
+
core::arch::naked_asm!(
|
| 1424 |
+
"push edi",
|
| 1425 |
+
"mov eax, [esp+8]", // font_obj β EAX
|
| 1426 |
+
"mov edx, [esp+16]", // out_2 β EDX
|
| 1427 |
+
"mov edi, [esp+12]", // out_1 β EDI
|
| 1428 |
+
"mov ecx, [esp+20]", // target
|
| 1429 |
+
"call ecx", // plain RET
|
| 1430 |
+
"pop edi",
|
| 1431 |
+
"ret",
|
| 1432 |
+
);
|
| 1433 |
+
}
|
| 1434 |
+
|
| 1435 |
+
/// Port of DisplayGfx::GetFontMetric (vtable slot 9, 0x523750).
|
| 1436 |
+
///
|
| 1437 |
+
/// Validates font_id, then calls Font__GetMetric (0x4fa780):
|
| 1438 |
+
/// usercall(AL=char_code, EDX=out_1, EDI=out_2) + stack(font_obj), RET 0x4.
|
| 1439 |
+
unsafe extern "thiscall" fn get_font_metric(
|
| 1440 |
+
this: *mut DisplayGfx,
|
| 1441 |
+
font_id: i32,
|
| 1442 |
+
char_code: u32,
|
| 1443 |
+
out_1: *mut u32,
|
| 1444 |
+
out_2: *mut u32,
|
| 1445 |
+
) -> u32 {
|
| 1446 |
+
if !(1..=31).contains(&font_id) {
|
| 1447 |
+
return 0;
|
| 1448 |
+
}
|
| 1449 |
+
let font_obj = (*this).base.font_table[font_id as usize];
|
| 1450 |
+
if font_obj == 0 {
|
| 1451 |
+
return 0;
|
| 1452 |
+
}
|
| 1453 |
+
wa_font_get_metric(
|
| 1454 |
+
font_obj,
|
| 1455 |
+
char_code,
|
| 1456 |
+
out_1,
|
| 1457 |
+
out_2,
|
| 1458 |
+
rb(va::FONT_OBJ_GET_METRIC),
|
| 1459 |
+
)
|
| 1460 |
+
}
|
| 1461 |
+
|
| 1462 |
+
/// Bridge to Font__GetMetric (0x4fa780).
|
| 1463 |
+
/// Usercall: AL=char_code, EDX=out_1, EDI=out_2, stack(font_obj), RET 0x4.
|
| 1464 |
+
#[unsafe(naked)]
|
| 1465 |
+
unsafe extern "cdecl" fn wa_font_get_metric(
|
| 1466 |
+
_font_obj: u32,
|
| 1467 |
+
_char_code: u32,
|
| 1468 |
+
_out_1: *mut u32,
|
| 1469 |
+
_out_2: *mut u32,
|
| 1470 |
+
_target: u32,
|
| 1471 |
+
) -> u32 {
|
| 1472 |
+
core::arch::naked_asm!(
|
| 1473 |
+
"push edi",
|
| 1474 |
+
"mov al, [esp+12]", // char_code (byte) β AL
|
| 1475 |
+
"mov edx, [esp+16]", // out_1 β EDX
|
| 1476 |
+
"mov edi, [esp+20]", // out_2 β EDI
|
| 1477 |
+
"mov ecx, [esp+24]", // target
|
| 1478 |
+
"push dword ptr [esp+8]", // font_obj β stack (shifted +4 by push edi)
|
| 1479 |
+
"call ecx", // RET 0x4 cleans 1 param
|
| 1480 |
+
"pop edi",
|
| 1481 |
+
"ret",
|
| 1482 |
+
);
|
| 1483 |
+
}
|
| 1484 |
+
|
| 1485 |
+
/// Port of DisplayGfx::DrawTextOnBitmap (vtable slot 7, 0x5236B0).
|
| 1486 |
+
///
|
| 1487 |
+
/// Extracts font_id from low 16 bits, extra flags from high 16 bits.
|
| 1488 |
+
/// Validates font_id, then calls Font__DrawText (0x4fa4e0):
|
| 1489 |
+
/// usercall(EAX=bitmap, EDX=a8, ESI=font_obj) + stack(h_align, v_align, msg, a7, high_bits), RET 0x14.
|
| 1490 |
+
///
|
| 1491 |
+
/// Calling convention verified by tracing the wrapper at 0x5236B0:
|
| 1492 |
+
/// EAX receives bitmap (loaded last via [ESP+0x20] after 5 pushes)
|
| 1493 |
+
/// EDX receives a8 (loaded via [ESP+0x30] after 4 pushes)
|
| 1494 |
+
/// Stack params pushed: h_align, v_align, msg, a7, high_bits
|
| 1495 |
+
unsafe extern "thiscall" fn draw_text_on_bitmap(
|
| 1496 |
+
this: *mut DisplayGfx,
|
| 1497 |
+
font_id: i32,
|
| 1498 |
+
bitmap: i32,
|
| 1499 |
+
h_align: i32,
|
| 1500 |
+
v_align: i32,
|
| 1501 |
+
msg: *const core::ffi::c_char,
|
| 1502 |
+
a7: i32,
|
| 1503 |
+
a8: i32,
|
| 1504 |
+
) -> i32 {
|
| 1505 |
+
let font_id_low = (font_id as u32) & 0xFFFF;
|
| 1506 |
+
if !(1..=31).contains(&font_id_low) {
|
| 1507 |
+
return 0;
|
| 1508 |
+
}
|
| 1509 |
+
let font_obj = (*this).base.font_table[font_id_low as usize];
|
| 1510 |
+
if font_obj == 0 {
|
| 1511 |
+
return 0;
|
| 1512 |
+
}
|
| 1513 |
+
let font_id_high = ((font_id as u32) >> 16) as i32;
|
| 1514 |
+
wa_font_draw_text(
|
| 1515 |
+
font_obj,
|
| 1516 |
+
bitmap,
|
| 1517 |
+
a8,
|
| 1518 |
+
h_align,
|
| 1519 |
+
v_align,
|
| 1520 |
+
msg,
|
| 1521 |
+
a7,
|
| 1522 |
+
font_id_high,
|
| 1523 |
+
rb(va::FONT_OBJ_DRAW_TEXT),
|
| 1524 |
+
)
|
| 1525 |
+
}
|
| 1526 |
+
|
| 1527 |
+
/// Bridge to Font__DrawText (0x4fa4e0).
|
| 1528 |
+
/// Usercall: EAX=bitmap, EDX=a8, ESI=font_obj, stack(h_align, v_align, msg, a7, high_bits), RET 0x14.
|
| 1529 |
+
#[unsafe(naked)]
|
| 1530 |
+
unsafe extern "cdecl" fn wa_font_draw_text(
|
| 1531 |
+
_font_obj: u32,
|
| 1532 |
+
_bitmap: i32,
|
| 1533 |
+
_a8: i32,
|
| 1534 |
+
_h_align: i32,
|
| 1535 |
+
_v_align: i32,
|
| 1536 |
+
_msg: *const core::ffi::c_char,
|
| 1537 |
+
_a7: i32,
|
| 1538 |
+
_high_bits: i32,
|
| 1539 |
+
_target: u32,
|
| 1540 |
+
) -> i32 {
|
| 1541 |
+
core::arch::naked_asm!(
|
| 1542 |
+
"push esi",
|
| 1543 |
+
// After push esi: +8=font_obj, +12=bitmap, +16=a8, +20=h_align,
|
| 1544 |
+
// +24=v_align, +28=msg, +32=a7, +36=high_bits, +40=target
|
| 1545 |
+
"mov esi, [esp+8]", // font_obj β ESI
|
| 1546 |
+
"mov eax, [esp+12]", // bitmap β EAX
|
| 1547 |
+
"mov edx, [esp+16]", // a8 β EDX
|
| 1548 |
+
"mov ecx, [esp+40]", // target
|
| 1549 |
+
// Push 5 stack params in reverse order. Each push shifts ESP by -4,
|
| 1550 |
+
// and the next param is 4 bytes lower, so the offset stays constant.
|
| 1551 |
+
"push dword ptr [esp+36]", // high_bits
|
| 1552 |
+
"push dword ptr [esp+36]", // a7
|
| 1553 |
+
"push dword ptr [esp+36]", // msg
|
| 1554 |
+
"push dword ptr [esp+36]", // v_align
|
| 1555 |
+
"push dword ptr [esp+36]", // h_align
|
| 1556 |
+
"call ecx", // RET 0x14 cleans 5 params
|
| 1557 |
+
"pop esi",
|
| 1558 |
+
"ret",
|
| 1559 |
+
);
|
| 1560 |
+
}
|
| 1561 |
+
|
| 1562 |
// ---------------------------------------------------------------------------
|
| 1563 |
// Display installation
|
| 1564 |
// ---------------------------------------------------------------------------
|
|
|
|
| 1600 |
set_layer_color => display_vtable::set_layer_color,
|
| 1601 |
set_active_layer => display_vtable::set_active_layer,
|
| 1602 |
get_sprite_info => display_vtable::get_sprite_info,
|
| 1603 |
+
draw_text_on_bitmap => draw_text_on_bitmap,
|
| 1604 |
+
get_font_info => get_font_info,
|
| 1605 |
+
get_font_metric => get_font_metric,
|
| 1606 |
+
set_font_param => set_font_param,
|
| 1607 |
draw_polyline => display_vtable::draw_polyline,
|
| 1608 |
draw_line => display_vtable::draw_line,
|
| 1609 |
draw_line_clipped => display_vtable::draw_line_clipped,
|
|
|
|
| 1620 |
draw_scaled_sprite => draw_scaled_sprite,
|
| 1621 |
set_layer_visibility => display_vtable::set_layer_visibility,
|
| 1622 |
update_palette => display_vtable::update_palette,
|
| 1623 |
+
set_font_palette => set_font_palette,
|
| 1624 |
slot 19 => blit_sprite,
|
| 1625 |
})?;
|
| 1626 |
+
let _ = log_line("[Display] DisplayGfx: patched 26 methods -> Rust");
|
| 1627 |
}
|
| 1628 |
|
| 1629 |
Ok(())
|
crates/openwa-dll/src/startup_checks.rs
CHANGED
|
@@ -15,6 +15,7 @@ use openwa_core::registry::{self, AddrKind};
|
|
| 15 |
const VALID_PROLOGUES: &[u8] = &[
|
| 16 |
0x2B, // sub reg, r/m32 (e.g. SpriteBank__GetInfo starts with SUB EAX, [ECX+8])
|
| 17 |
0x33, // xor reg, reg
|
|
|
|
| 18 |
0x51, // push ecx
|
| 19 |
0x52, // push edx
|
| 20 |
0x53, // push ebx
|
|
|
|
| 15 |
const VALID_PROLOGUES: &[u8] = &[
|
| 16 |
0x2B, // sub reg, r/m32 (e.g. SpriteBank__GetInfo starts with SUB EAX, [ECX+8])
|
| 17 |
0x33, // xor reg, reg
|
| 18 |
+
0x3C, // cmp al, imm8 (usercall with AL input, e.g. Font__GetMetric)
|
| 19 |
0x51, // push ecx
|
| 20 |
0x52, // push edx
|
| 21 |
0x53, // push ebx
|