feat: type DDDisplayWrapper and CompatRenderer structs and vtables
Browse filesAdd two new typed display subsystem structs:
- DDDisplayWrapper (vtable 0x662EC8, 25 slots): CWormsApp rendering
interface subobject that manages the software framebuffer and
dispatches to renderer backends. All 25 slots mapped.
- CompatRenderer (vtable 0x676A90, 37 slots): DirectDraw/D3D rendering
backend wrapping IDirectDraw2/IDirectDrawSurface. Two-section vtable
for primary display (0-24) and offscreen surface ops (25-36).
Struct fields mapped including DDraw interfaces and surface pointers.
Update DDDisplay docs with corrected dispatch chain:
DDDisplay β DDDisplayWrapper β RendererBackend
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
crates/openwa-core/src/address.rs
CHANGED
|
@@ -71,7 +71,11 @@ pub mod va {
|
|
| 71 |
STREAMING_AUDIO_RESET, STREAMING_AUDIO_STOP, STREAMING_AUDIO_TIMER_CALLBACK,
|
| 72 |
};
|
| 73 |
pub use crate::display::base::DISPLAY_BASE_VTABLE;
|
|
|
|
|
|
|
|
|
|
| 74 |
pub use crate::display::dd_display::DD_DISPLAY_VTABLE;
|
|
|
|
| 75 |
pub use crate::display::palette::PALETTE_VTABLE;
|
| 76 |
pub use crate::frontend::map_view::MAP_VIEW_VTABLE;
|
| 77 |
pub use crate::input::controller::INPUT_CTRL_VTABLE;
|
|
|
|
| 71 |
STREAMING_AUDIO_RESET, STREAMING_AUDIO_STOP, STREAMING_AUDIO_TIMER_CALLBACK,
|
| 72 |
};
|
| 73 |
pub use crate::display::base::DISPLAY_BASE_VTABLE;
|
| 74 |
+
pub use crate::display::compat_renderer::{
|
| 75 |
+
CompatRendererVtable, COMPAT_RENDERER_VTABLE, DDRAW8_RENDERER_VTABLE,
|
| 76 |
+
};
|
| 77 |
pub use crate::display::dd_display::DD_DISPLAY_VTABLE;
|
| 78 |
+
pub use crate::display::display_wrapper::{DDDisplayWrapperVtable, DD_DISPLAY_WRAPPER_VTABLE};
|
| 79 |
pub use crate::display::palette::PALETTE_VTABLE;
|
| 80 |
pub use crate::frontend::map_view::MAP_VIEW_VTABLE;
|
| 81 |
pub use crate::input::controller::INPUT_CTRL_VTABLE;
|
crates/openwa-core/src/display/compat_renderer.rs
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
use core::ffi::c_void;
|
| 2 |
+
|
| 3 |
+
// CompatRenderer β DirectDraw/D3D rendering backend.
|
| 4 |
+
// See CompatRenderer struct and CompatRendererVtable below for full docs.
|
| 5 |
+
|
| 6 |
+
crate::define_addresses! {
|
| 7 |
+
class "DDraw8Renderer" {
|
| 8 |
+
vtable DDRAW8_RENDERER_VTABLE = 0x0067_67F8;
|
| 9 |
+
}
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
#[openwa_core::vtable(size = 37, va = 0x0067_6A90, class = "CompatRenderer")]
|
| 13 |
+
pub struct CompatRendererVtable {
|
| 14 |
+
// =====================================================================
|
| 15 |
+
// Primary display management (slots 0-24)
|
| 16 |
+
// =====================================================================
|
| 17 |
+
/// init / DirectDrawCreate + QueryInterface(IDirectDraw2) (0x59D430)
|
| 18 |
+
#[slot(0)]
|
| 19 |
+
pub init: fn(this: *mut CompatRenderer, p2: u32, p3: u32),
|
| 20 |
+
/// set cooperative level β fullscreen exclusive or windowed (0x59D5F0)
|
| 21 |
+
#[slot(1)]
|
| 22 |
+
pub set_cooperative_level: fn(this: *mut CompatRenderer),
|
| 23 |
+
/// reset state β calls teardown, clears initialized flag (0x59D480)
|
| 24 |
+
#[slot(2)]
|
| 25 |
+
pub reset_state: fn(this: *mut CompatRenderer),
|
| 26 |
+
/// get display size β returns stored width/height from +0x3C/+0x40 (0x59D510)
|
| 27 |
+
#[slot(3)]
|
| 28 |
+
pub get_display_size: fn(this: *mut CompatRenderer, out_w: *mut u32, out_h: *mut u32),
|
| 29 |
+
/// enum display modes β IDirectDraw2::EnumDisplayModes (0x59D560)
|
| 30 |
+
#[slot(4)]
|
| 31 |
+
pub enum_display_modes: fn(this: *mut CompatRenderer, p2: u32, p3: u32),
|
| 32 |
+
// Slot 5: stub (CGameTask__vt19)
|
| 33 |
+
/// set display mode + create surfaces β the main initialization (0x59D6D0)
|
| 34 |
+
///
|
| 35 |
+
/// Calls IDirectDraw2::SetDisplayMode, creates primary surface with back buffer
|
| 36 |
+
/// (fullscreen) or with clipper (windowed). ~0x3F2 bytes.
|
| 37 |
+
#[slot(6)]
|
| 38 |
+
pub set_display_mode: fn(this: *mut CompatRenderer, width: i32, height: i32),
|
| 39 |
+
/// teardown β release surfaces, restore display mode (0x59DAD0)
|
| 40 |
+
///
|
| 41 |
+
/// Calls timeEndPeriod, releases primary/back/clipper surfaces,
|
| 42 |
+
/// calls IDirectDraw2::RestoreDisplayMode, LockWindowUpdate(NULL).
|
| 43 |
+
#[slot(7)]
|
| 44 |
+
pub teardown: fn(this: *mut CompatRenderer, p2: i32),
|
| 45 |
+
/// vsync stub β calls teardown with 0, effectively a no-op (0x59DCB0)
|
| 46 |
+
#[slot(8)]
|
| 47 |
+
pub vsync_stub: fn(this: *mut CompatRenderer),
|
| 48 |
+
/// set display dimensions β thin wrapper to slot 6 (0x59DCE0)
|
| 49 |
+
#[slot(9)]
|
| 50 |
+
pub set_display_dims: fn(this: *mut CompatRenderer, width: i32, height: i32),
|
| 51 |
+
/// restore display dimensions β calls slot 6 with stored w/h (0x59DCC0)
|
| 52 |
+
#[slot(10)]
|
| 53 |
+
pub restore_display_dims: fn(this: *mut CompatRenderer),
|
| 54 |
+
/// restore lost surface β IDirectDrawSurface::Restore on primary (0x59D4B0)
|
| 55 |
+
#[slot(11)]
|
| 56 |
+
pub restore_surface: fn(this: *mut CompatRenderer) -> u32,
|
| 57 |
+
// Slot 12: stub
|
| 58 |
+
/// flip / present β end-of-frame IDirectDrawSurface::Flip (0x59DB70)
|
| 59 |
+
///
|
| 60 |
+
/// Handles DDERR_SURFACELOST by calling RestoreSurface and retrying.
|
| 61 |
+
#[slot(13)]
|
| 62 |
+
pub flip: fn(this: *mut CompatRenderer),
|
| 63 |
+
/// get hardware caps β IDirectDraw2::GetCaps for HAL and HEL (0x59DC80)
|
| 64 |
+
#[slot(14)]
|
| 65 |
+
pub get_caps: fn(this: *mut CompatRenderer, out: *mut u8),
|
| 66 |
+
/// lock primary surface (read, 16bpp flags) (0x59D370)
|
| 67 |
+
///
|
| 68 |
+
/// Returns pitch and pixel pointer through output params.
|
| 69 |
+
#[slot(15)]
|
| 70 |
+
pub lock_primary_read:
|
| 71 |
+
fn(this: *mut CompatRenderer, out_pitch: *mut u32, out_ptr: *mut *mut u8),
|
| 72 |
+
/// unlock primary surface (0x59D3B0)
|
| 73 |
+
#[slot(16)]
|
| 74 |
+
pub unlock_primary_read: fn(this: *mut CompatRenderer),
|
| 75 |
+
/// lock primary surface (write, 32bpp flags) (0x59D390)
|
| 76 |
+
#[slot(17)]
|
| 77 |
+
pub lock_primary_write:
|
| 78 |
+
fn(this: *mut CompatRenderer, out_pitch: *mut u32, out_ptr: *mut *mut u8),
|
| 79 |
+
/// unlock primary surface β same fn as slot 16 (0x59D3B0)
|
| 80 |
+
#[slot(18)]
|
| 81 |
+
pub unlock_primary_write: fn(this: *mut CompatRenderer),
|
| 82 |
+
/// blt filled rect to screen β IDirectDrawSurface::Blt with DDBLT_COLORFILL (0x59DDD0)
|
| 83 |
+
#[slot(19)]
|
| 84 |
+
pub blt_fill_rect:
|
| 85 |
+
fn(this: *mut CompatRenderer, x: i32, y: i32, width: i32, height: i32, color: u32),
|
| 86 |
+
/// blt clear both surfaces β clears front and back buffer (0x59DD00)
|
| 87 |
+
#[slot(20)]
|
| 88 |
+
pub blt_clear_both: fn(this: *mut CompatRenderer),
|
| 89 |
+
/// blt clear current surface β clears active drawing surface (0x59DD70)
|
| 90 |
+
#[slot(21)]
|
| 91 |
+
pub blt_clear_current: fn(this: *mut CompatRenderer),
|
| 92 |
+
// Slots 22-23: stubs
|
| 93 |
+
/// striped blt helper β breaks area into horizontal bands (0x5A2080)
|
| 94 |
+
#[slot(24)]
|
| 95 |
+
pub blt_striped: fn(this: *mut CompatRenderer, surface: *mut u8, y_offset: i32),
|
| 96 |
+
|
| 97 |
+
// =====================================================================
|
| 98 |
+
// Offscreen surface sub-object (slots 25-36, via second vtable at +0x04)
|
| 99 |
+
// =====================================================================
|
| 100 |
+
/// sub-object destructor β releases offscreen surface (0x59E7B0)
|
| 101 |
+
#[slot(25)]
|
| 102 |
+
pub offscreen_destructor: fn(this: *mut CompatRenderer, flags: u8) -> *mut CompatRenderer,
|
| 103 |
+
/// lock offscreen surface (0x59DF10)
|
| 104 |
+
///
|
| 105 |
+
/// Handles DDERR_SURFACELOST with restore+retry.
|
| 106 |
+
/// Returns pitch and pixel pointer (via ESI β usercall).
|
| 107 |
+
#[slot(26)]
|
| 108 |
+
pub lock_offscreen: fn(this: *mut CompatRenderer, out_pitch: *mut u32, out_ptr: *mut *mut u8),
|
| 109 |
+
/// unlock offscreen surface β IDirectDrawSurface::Unlock on +0x10 (0x59E020)
|
| 110 |
+
#[slot(27)]
|
| 111 |
+
pub unlock_offscreen: fn(this: *mut CompatRenderer),
|
| 112 |
+
/// lock offscreen surface variant (0x59E090)
|
| 113 |
+
#[slot(28)]
|
| 114 |
+
pub lock_offscreen_alt:
|
| 115 |
+
fn(this: *mut CompatRenderer, out_pitch: *mut u32, out_ptr: *mut *mut u8),
|
| 116 |
+
/// unlock offscreen surface β same fn as slot 27 (0x59E020)
|
| 117 |
+
#[slot(29)]
|
| 118 |
+
pub unlock_offscreen_alt: fn(this: *mut CompatRenderer),
|
| 119 |
+
/// create offscreen plain surface β IDirectDraw2::CreateSurface (0x59E1D0)
|
| 120 |
+
///
|
| 121 |
+
/// Creates DDSCAPS_OFFSCREENPLAIN surface, width 4-byte aligned,
|
| 122 |
+
/// 8bpp or 32bpp. Falls back to system memory if VRAM alloc fails.
|
| 123 |
+
#[slot(30)]
|
| 124 |
+
pub create_offscreen_surface:
|
| 125 |
+
fn(this: *mut CompatRenderer, width: i32, height: i32, bpp: i32) -> u32,
|
| 126 |
+
/// release offscreen surface β IDirectDrawSurface::Release on +0x10 (0x59E3B0)
|
| 127 |
+
#[slot(31)]
|
| 128 |
+
pub release_offscreen_surface: fn(this: *mut CompatRenderer),
|
| 129 |
+
/// set color key on offscreen surface (0x59E3F0)
|
| 130 |
+
#[slot(32)]
|
| 131 |
+
pub set_color_key: fn(this: *mut CompatRenderer, color: u32),
|
| 132 |
+
/// get color key from offscreen surface (0x59E480)
|
| 133 |
+
#[slot(33)]
|
| 134 |
+
pub get_color_key: fn(this: *mut CompatRenderer, out_color: *mut u32),
|
| 135 |
+
/// is offscreen surface lost β restore if DDERR_SURFACELOST (0x59E780)
|
| 136 |
+
#[slot(34)]
|
| 137 |
+
pub is_lost: fn(this: *mut CompatRenderer) -> u32,
|
| 138 |
+
/// blt offscreen β IDirectDrawSurface::Blt with source/dest rects (0x59E4D0)
|
| 139 |
+
#[slot(35)]
|
| 140 |
+
pub blt_offscreen: fn(
|
| 141 |
+
this: *mut CompatRenderer,
|
| 142 |
+
dst_x: i32,
|
| 143 |
+
dst_y: i32,
|
| 144 |
+
dst_w: i32,
|
| 145 |
+
dst_h: i32,
|
| 146 |
+
src: *mut c_void,
|
| 147 |
+
),
|
| 148 |
+
/// blt fast offscreen β IDirectDrawSurface::BltFast with mirror/colorkey (0x59E5F0)
|
| 149 |
+
#[slot(36)]
|
| 150 |
+
pub blt_fast_offscreen:
|
| 151 |
+
fn(this: *mut CompatRenderer, dst_x: i32, dst_y: i32, src: *mut c_void, flags: u32),
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
/// CompatRenderer struct β DirectDraw/D3D rendering backend.
|
| 155 |
+
///
|
| 156 |
+
/// Wraps IDirectDraw2 and IDirectDrawSurface interfaces for screen presentation.
|
| 157 |
+
/// Selected for DIRECTDRAW8, DIRECTDRAW32, DIRECT3D_* display modes.
|
| 158 |
+
#[repr(C)]
|
| 159 |
+
pub struct CompatRenderer {
|
| 160 |
+
/// 0x00: Primary vtable pointer (0x676A90)
|
| 161 |
+
pub vtable: *const CompatRendererVtable,
|
| 162 |
+
/// 0x04: Sub-object vtable pointer (offscreen surface ops, slots 25-36)
|
| 163 |
+
pub offscreen_vtable: *const c_void,
|
| 164 |
+
/// 0x08: Unknown
|
| 165 |
+
pub _unknown_08: u32,
|
| 166 |
+
/// 0x0C: IDirectDraw2 interface (used for offscreen surface creation)
|
| 167 |
+
pub ddraw2_offscreen: *mut c_void,
|
| 168 |
+
/// 0x10: IDirectDrawSurface (current offscreen surface)
|
| 169 |
+
pub offscreen_surface: *mut c_void,
|
| 170 |
+
/// 0x14: Timer period flag
|
| 171 |
+
pub timer_period: u32,
|
| 172 |
+
/// 0x18: Initialized flag (1 = DirectDraw created)
|
| 173 |
+
pub initialized: u32,
|
| 174 |
+
/// 0x1C: Unknown
|
| 175 |
+
pub _unknown_1c: u32,
|
| 176 |
+
/// 0x20: Windowed mode flag (0 = fullscreen exclusive, nonzero = windowed)
|
| 177 |
+
pub windowed: u32,
|
| 178 |
+
/// 0x24: Display mode field
|
| 179 |
+
pub display_mode: u32,
|
| 180 |
+
/// 0x28: IDirectDraw2 main interface
|
| 181 |
+
pub ddraw2_main: *mut c_void,
|
| 182 |
+
/// 0x2C: IDirectDrawSurface β primary/front surface
|
| 183 |
+
pub primary_surface: *mut c_void,
|
| 184 |
+
/// 0x30: IDirectDrawSurface β back buffer (windowed mode)
|
| 185 |
+
pub back_buffer: *mut c_void,
|
| 186 |
+
/// 0x34: Unknown
|
| 187 |
+
pub _unknown_34: u32,
|
| 188 |
+
/// 0x38: IDirectDrawClipper (windowed mode only)
|
| 189 |
+
pub clipper: *mut c_void,
|
| 190 |
+
/// 0x3C: Stored width
|
| 191 |
+
pub width: u32,
|
| 192 |
+
/// 0x40: Stored height
|
| 193 |
+
pub height: u32,
|
| 194 |
+
}
|
| 195 |
+
|
| 196 |
+
const _: () = assert!(core::mem::size_of::<CompatRenderer>() == 0x44);
|
| 197 |
+
|
| 198 |
+
// Generate calling wrappers: CompatRenderer::flip(), etc.
|
| 199 |
+
bind_CompatRendererVtable!(CompatRenderer, vtable);
|
crates/openwa-core/src/display/dd_display.rs
CHANGED
|
@@ -7,15 +7,29 @@ use crate::fixed::Fixed;
|
|
| 7 |
/// Destructor: 0x569CE0.
|
| 8 |
///
|
| 9 |
/// Actual runtime type is DisplayGfx (0x24E28 bytes), which extends DisplayBase.
|
| 10 |
-
/// Manages layers, sprites, fonts, palettes, and delegates
|
| 11 |
-
/// (
|
|
|
|
| 12 |
///
|
| 13 |
-
///
|
| 14 |
-
///
|
| 15 |
-
///
|
| 16 |
-
///
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
/// - 0x3580-0x3584: bitmap vector (ptr, end)
|
| 18 |
-
/// -
|
|
|
|
| 19 |
///
|
| 20 |
/// OPAQUE: Full struct layout not yet mapped (see DisplayGfx for size).
|
| 21 |
#[repr(C)]
|
|
|
|
| 7 |
/// Destructor: 0x569CE0.
|
| 8 |
///
|
| 9 |
/// Actual runtime type is DisplayGfx (0x24E28 bytes), which extends DisplayBase.
|
| 10 |
+
/// Manages layers, sprites, fonts, palettes, and delegates rendering through
|
| 11 |
+
/// DDDisplayWrapper (g_DDDisplayWrapper at 0x79D6D4), which in turn dispatches
|
| 12 |
+
/// to a renderer backend (CompatRenderer for D3D/DDraw, OpenGLCPU for OpenGL).
|
| 13 |
///
|
| 14 |
+
/// ## Dispatch chain
|
| 15 |
+
///
|
| 16 |
+
/// ```text
|
| 17 |
+
/// DDDisplay β DDDisplayWrapper β RendererBackend
|
| 18 |
+
/// vtable (CWormsApp sub- (CompatRenderer/
|
| 19 |
+
/// 0x66A218 object, vtable OpenGLCPU/DDraw)
|
| 20 |
+
/// 0x662EC8)
|
| 21 |
+
/// ```
|
| 22 |
+
///
|
| 23 |
+
/// DDDisplay methods apply camera offset and clipping, then call through
|
| 24 |
+
/// `g_DDDisplayWrapper->vtable[N]` for the actual rendering operation.
|
| 25 |
+
///
|
| 26 |
+
/// Key internal fields (offsets from start of DisplayGfx/DisplayBase):
|
| 27 |
+
/// - 0x3548/0x354C: display width/height (pixels)
|
| 28 |
+
/// - 0x3550-0x355C: clip rect (x1, y1, x2, y2, pixels)
|
| 29 |
+
/// - 0x3560/0x3564: camera offset (x, y, pixels)
|
| 30 |
/// - 0x3580-0x3584: bitmap vector (ptr, end)
|
| 31 |
+
/// - 0x3D98: render lock flag (cleared by FlushRender)
|
| 32 |
+
/// - 0x3D9C: display context pointer (read during FlushRender)
|
| 33 |
///
|
| 34 |
/// OPAQUE: Full struct layout not yet mapped (see DisplayGfx for size).
|
| 35 |
#[repr(C)]
|
crates/openwa-core/src/display/display_wrapper.rs
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// DDDisplayWrapper β CWormsApp rendering interface subobject.
|
| 2 |
+
// See DDDisplayWrapper struct and DDDisplayWrapperVtable below for full docs.
|
| 3 |
+
|
| 4 |
+
crate::define_addresses! {
|
| 5 |
+
class "CWormsApp" {
|
| 6 |
+
/// CWormsApp__FlipSurface β dispatches to renderer backend vtable[1]
|
| 7 |
+
fn/Thiscall CWORMSAPP_FLIP_SURFACE = 0x005A_2700;
|
| 8 |
+
/// ConstructFrameBuffer β allocates software framebuffer, inits renderer
|
| 9 |
+
fn/Thiscall CONSTRUCT_FRAME_BUFFER_THISCALL = 0x005A_2430;
|
| 10 |
+
/// CWormsApp__ReleaseFrameBuffer
|
| 11 |
+
fn/Thiscall CWORMSAPP_RELEASE_FRAME_BUFFER = 0x005A_24A0;
|
| 12 |
+
/// CWormsApp__FillRect β lock surface, memset rows, unlock
|
| 13 |
+
fn/Thiscall CWORMSAPP_FILL_RECT = 0x005A_25C0;
|
| 14 |
+
/// CWormsApp__BlitToFrameBuffer β optimized blit from surface to framebuffer
|
| 15 |
+
fn/Thiscall CWORMSAPP_BLIT_TO_FRAME_BUFFER = 0x005A_2A40;
|
| 16 |
+
/// CWormsApp__DrawLandscape β blit with clipping and transparency
|
| 17 |
+
fn/Thiscall CWORMSAPP_DRAW_LANDSCAPE = 0x005A_2790;
|
| 18 |
+
/// ClearFrameBuffer β memset(framebuffer, 0, w*h)
|
| 19 |
+
fn CWORMSAPP_CLEAR_FRAME_BUFFER = 0x005A_23F0;
|
| 20 |
+
}
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
/// DDDisplayWrapper vtable (0x662EC8, 25 slots).
|
| 24 |
+
///
|
| 25 |
+
/// Many slots are thin thunks that forward to the renderer backend
|
| 26 |
+
/// via `*(this+0x18)->vtable[N]`. Others manage the software framebuffer
|
| 27 |
+
/// or perform blitting directly.
|
| 28 |
+
///
|
| 29 |
+
/// ## Slot categories
|
| 30 |
+
///
|
| 31 |
+
/// - **Renderer thunks** (0, 2, 4, 5, 8, 10, 11): Forward to backend
|
| 32 |
+
/// - **Framebuffer management** (3, 6, 7, 9, 15/17, 16/18, 20): Manage G_FRAME_BUFFER_*
|
| 33 |
+
/// - **Blitting** (19, 23, 24): FillRect, DrawLandscape, BlitToFrameBuffer
|
| 34 |
+
/// - **Surface management** (12, 13, 22): Renderer queries and surface allocation
|
| 35 |
+
/// - **Stub** (14): Returns 0
|
| 36 |
+
#[openwa_core::vtable(size = 25, va = 0x0066_2EC8, class = "DDDisplayWrapper")]
|
| 37 |
+
pub struct DDDisplayWrapperVtable {
|
| 38 |
+
/// renderer thunk -> backend vtable[0] (init/create) (0x4E3420, RET 0x8)
|
| 39 |
+
#[slot(0)]
|
| 40 |
+
pub renderer_init: fn(this: *mut DDDisplayWrapper, p2: u32, p3: u32),
|
| 41 |
+
/// flip/present β dispatches to renderer backend vtable[1] (0x5A2700)
|
| 42 |
+
#[slot(1)]
|
| 43 |
+
pub flip_surface: fn(this: *mut DDDisplayWrapper),
|
| 44 |
+
/// renderer thunk -> backend vtable[2] (reset state) (0x4E3440)
|
| 45 |
+
#[slot(2)]
|
| 46 |
+
pub renderer_reset: fn(this: *mut DDDisplayWrapper),
|
| 47 |
+
/// get framebuffer dimensions β reads G_FRAME_BUFFER_WIDTH/HEIGHT (0x5A2660, RET 0x4)
|
| 48 |
+
#[slot(3)]
|
| 49 |
+
pub get_framebuffer_dims: fn(this: *mut DDDisplayWrapper, out: *mut u32) -> u32,
|
| 50 |
+
/// renderer thunk -> backend vtable[4] (enum display modes) (0x4E3460, RET 0x8)
|
| 51 |
+
#[slot(4)]
|
| 52 |
+
pub renderer_enum_modes: fn(this: *mut DDDisplayWrapper, p2: u32, p3: u32),
|
| 53 |
+
/// renderer thunk -> backend vtable[5] (tail jump) (0x4E3480)
|
| 54 |
+
#[slot(5)]
|
| 55 |
+
pub renderer_slot5: fn(this: *mut DDDisplayWrapper),
|
| 56 |
+
/// construct framebuffer β wa_malloc(w*h), init renderer (0x5A2430, RET 0x8)
|
| 57 |
+
#[slot(6)]
|
| 58 |
+
pub construct_frame_buffer: fn(this: *mut DDDisplayWrapper, width: i32, height: i32) -> i32,
|
| 59 |
+
/// release framebuffer β calls renderer teardown, frees buffer (0x5A24A0)
|
| 60 |
+
#[slot(7)]
|
| 61 |
+
pub release_frame_buffer: fn(this: *mut DDDisplayWrapper, p2: i32),
|
| 62 |
+
/// renderer thunk -> backend vtable[8] (0x5A24F0)
|
| 63 |
+
#[slot(8)]
|
| 64 |
+
pub renderer_slot8: fn(this: *mut DDDisplayWrapper),
|
| 65 |
+
/// lock framebuffer for pixel access (0x5A2530)
|
| 66 |
+
///
|
| 67 |
+
/// Returns framebuffer pointer and stride for direct pixel manipulation.
|
| 68 |
+
#[slot(9)]
|
| 69 |
+
pub lock_framebuffer:
|
| 70 |
+
fn(this: *mut DDDisplayWrapper, p2: u32, p3: u32, p4: u32, p5: u32) -> u32,
|
| 71 |
+
/// renderer thunk -> backend vtable[10] (0x5A2510)
|
| 72 |
+
#[slot(10)]
|
| 73 |
+
pub renderer_restore_dims: fn(this: *mut DDDisplayWrapper),
|
| 74 |
+
/// renderer thunk -> backend vtable[11] (restore surface) (0x5A25A0)
|
| 75 |
+
#[slot(11)]
|
| 76 |
+
pub renderer_restore_surface: fn(this: *mut DDDisplayWrapper),
|
| 77 |
+
/// allocate error/result object (0x5A2720, RET 0x4)
|
| 78 |
+
#[slot(12)]
|
| 79 |
+
pub alloc_error_result: fn(this: *mut DDDisplayWrapper, p2: u32) -> u32,
|
| 80 |
+
/// get renderer surface pointer (0x5A26C0)
|
| 81 |
+
///
|
| 82 |
+
/// Queries `renderer->vtable[12]` with G_FRAME_BUFFER_PTR.
|
| 83 |
+
#[slot(13)]
|
| 84 |
+
pub get_renderer_surface: fn(this: *mut DDDisplayWrapper),
|
| 85 |
+
/// stub β returns 0 (CGameTask__vt18, 0x545780)
|
| 86 |
+
#[slot(14)]
|
| 87 |
+
pub stub_ret_zero: fn(this: *mut DDDisplayWrapper) -> u32,
|
| 88 |
+
/// lock surface for reading β returns framebuffer ptr + width (0x5A2690, RET 0x8)
|
| 89 |
+
#[slot(15)]
|
| 90 |
+
pub lock_surface_read: fn(this: *mut DDDisplayWrapper, p2: u32, p3: u32),
|
| 91 |
+
/// unlock surface (0x5A2C10, RET 0x4)
|
| 92 |
+
///
|
| 93 |
+
/// No-op for software framebuffer β just returns success code.
|
| 94 |
+
#[slot(16)]
|
| 95 |
+
pub unlock_surface_read: fn(this: *mut DDDisplayWrapper, p2: u32),
|
| 96 |
+
/// lock surface for writing (0x5A2690 β same fn as slot 15, RET 0x8)
|
| 97 |
+
#[slot(17)]
|
| 98 |
+
pub lock_surface_write: fn(this: *mut DDDisplayWrapper, p2: u32, p3: u32),
|
| 99 |
+
/// unlock surface after writing (0x5A2C10 β same fn as slot 16, RET 0x4)
|
| 100 |
+
#[slot(18)]
|
| 101 |
+
pub unlock_surface_write: fn(this: *mut DDDisplayWrapper, p2: u32),
|
| 102 |
+
/// fill rectangle β lock, memset rows, unlock (0x5A25C0)
|
| 103 |
+
///
|
| 104 |
+
/// Params: x, y, width, height, fill_value.
|
| 105 |
+
#[slot(19)]
|
| 106 |
+
pub fill_rect:
|
| 107 |
+
fn(this: *mut DDDisplayWrapper, x: i32, y: i32, width: i32, height: i32, fill_value: u32),
|
| 108 |
+
/// clear framebuffer β memset(ptr, 0, w*h) (0x5A23F0)
|
| 109 |
+
#[slot(20)]
|
| 110 |
+
pub clear_frame_buffer: fn(this: *mut DDDisplayWrapper),
|
| 111 |
+
/// trampoline to slot 20 via vtable dispatch (0x5A2420)
|
| 112 |
+
#[slot(21)]
|
| 113 |
+
pub clear_frame_buffer_indirect: fn(this: *mut DDDisplayWrapper),
|
| 114 |
+
/// allocate surface object β wa_malloc(0x14) (0x5A2760)
|
| 115 |
+
#[slot(22)]
|
| 116 |
+
pub alloc_surface: fn(this: *mut DDDisplayWrapper) -> *mut u8,
|
| 117 |
+
/// draw landscape β blit with clipping and optional color-key transparency (0x5A2790)
|
| 118 |
+
#[slot(23)]
|
| 119 |
+
pub draw_landscape:
|
| 120 |
+
fn(this: *mut DDDisplayWrapper, surface: *mut u8, y_offset: i32, flags: u32),
|
| 121 |
+
/// blit surface to framebuffer β optimized copy with stride alignment (0x5A2A40)
|
| 122 |
+
#[slot(24)]
|
| 123 |
+
pub blit_to_frame_buffer: fn(this: *mut DDDisplayWrapper, surface: *mut u8, y_offset: i32),
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
/// DDDisplayWrapper struct β CWormsApp rendering dispatch subobject.
|
| 127 |
+
///
|
| 128 |
+
/// Stored as a global pointer at 0x79D6D4 (g_DDDisplayWrapper).
|
| 129 |
+
/// The full object layout is part of CWormsApp; only key fields are mapped here.
|
| 130 |
+
#[repr(C)]
|
| 131 |
+
pub struct DDDisplayWrapper {
|
| 132 |
+
/// 0x00: Vtable pointer (0x662EC8)
|
| 133 |
+
pub vtable: *const DDDisplayWrapperVtable,
|
| 134 |
+
/// 0x04-0x17: Unknown (part of CWormsApp layout)
|
| 135 |
+
pub _unknown_04: [u8; 0x14],
|
| 136 |
+
/// 0x18: Pointer to renderer backend (CompatRenderer, OpenGLCPU, or DDraw object)
|
| 137 |
+
pub renderer_backend: *mut u8,
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
const _: () = assert!(core::mem::size_of::<DDDisplayWrapper>() == 0x1C);
|
| 141 |
+
|
| 142 |
+
// Generate calling wrappers: DDDisplayWrapper::flip_surface(), etc.
|
| 143 |
+
bind_DDDisplayWrapperVtable!(DDDisplayWrapper, vtable);
|
crates/openwa-core/src/display/mod.rs
CHANGED
|
@@ -1,12 +1,16 @@
|
|
| 1 |
pub mod base;
|
|
|
|
| 2 |
pub mod dd_display;
|
|
|
|
| 3 |
pub mod gfx;
|
| 4 |
pub mod gradient;
|
| 5 |
pub mod opengl;
|
| 6 |
pub mod palette;
|
| 7 |
|
| 8 |
pub use base::{DisplayBase, DisplayBaseVtable, SpriteBufferCtrl, SpriteCacheWrapper};
|
|
|
|
| 9 |
pub use dd_display::DDDisplay;
|
|
|
|
| 10 |
pub use gfx::DisplayGfx;
|
| 11 |
pub use opengl::OpenGLState;
|
| 12 |
pub use palette::{Palette, PaletteVtable};
|
|
|
|
| 1 |
pub mod base;
|
| 2 |
+
pub mod compat_renderer;
|
| 3 |
pub mod dd_display;
|
| 4 |
+
pub mod display_wrapper;
|
| 5 |
pub mod gfx;
|
| 6 |
pub mod gradient;
|
| 7 |
pub mod opengl;
|
| 8 |
pub mod palette;
|
| 9 |
|
| 10 |
pub use base::{DisplayBase, DisplayBaseVtable, SpriteBufferCtrl, SpriteCacheWrapper};
|
| 11 |
+
pub use compat_renderer::CompatRenderer;
|
| 12 |
pub use dd_display::DDDisplay;
|
| 13 |
+
pub use display_wrapper::DDDisplayWrapper;
|
| 14 |
pub use gfx::DisplayGfx;
|
| 15 |
pub use opengl::OpenGLState;
|
| 16 |
pub use palette::{Palette, PaletteVtable};
|