Download crates/openwa-core/src/bitgrid/mod.rs from nmarshall/wormz-a: direct link, hf CLI and curl.
- Browser
- Download file 15.1 kB
-
https://huggingface.co/nmarshall/wormz-a/resolve/main/crates/openwa-core/src/bitgrid/mod.rs
- Command line
-
hf download hf://nmarshall/wormz-a/crates/openwa-core/src/bitgrid/mod.rs
-
curl -L -o mod.rs https://huggingface.co/nmarshall/wormz-a/resolve/main/crates/openwa-core/src/bitgrid/mod.rs
15.1 kB
| //! BitGrid β general-purpose 2D grid buffer. | |
| //! | |
| //! A polymorphic pixel/bit buffer used across WA's rendering and physics systems. | |
| //! The same struct layout serves multiple roles, distinguished by vtable: | |
| //! | |
| //! | Vtable | Type | Role | | |
| //! |------------|---------------------|------------------------------| | |
| //! | 0x6640EC | `BitGrid` | Base β set by `init`, passive data container | | |
| //! | 0x664118 | `CollisionBitGrid` | Collision grid (DDGame+0x380), bit-level spatial queries | | |
| //! | 0x664144 | `DisplayBitGrid` | Display layers and sprite pixel buffers, 8bpp byte-level ops | | |
| //! | |
| //! All three vtables share the same 8-slot interface: | |
| //! | |
| //! | Slot | Method | Base | Collision | Display | | |
| //! |------|------------------|---------------|---------------|---------------| | |
| //! | 0 | fill_rect | bit-level | bit-level | byte-level | | |
| //! | 1 | fill_hline | bit-level * | bit-level * | byte-level | | |
| //! | 2 | fill_vline | bit-level * | bit-level * | byte-level | | |
| //! | 3 | destructor | shared * | shared * | shared * | | |
| //! | 4 | get_clipped | bit-level | bit-level | byte-level | | |
| //! | 5 | put_clipped | bit-level | bit-level | byte-level | | |
| //! | 6 | get | stub | bit-level | byte-level | | |
| //! | 7 | put | stub | bit-level | byte-level | | |
| //! | |
| //! * = same function pointer shared between variants. | |
| //! | |
| //! ## Initialization pattern | |
| //! | |
| //! `BitGrid::init` allocates the data buffer, fills in all fields, and sets | |
| //! the base vtable (0x6640EC). Callers then cast and override the vtable: | |
| //! | |
| //! ```text | |
| //! BitGrid::init(grid, cells_per_unit, width, height); | |
| //! let display_grid = grid as *mut DisplayBitGrid; | |
| //! (*display_grid).vtable = rb_ptr(BIT_GRID_DISPLAY_VTABLE); | |
| //! ``` | |
| pub mod blit; | |
| use crate::rebase::rb; | |
| use crate::task::base::Vtable; | |
| use crate::wa_alloc::{wa_malloc, wa_malloc_struct_zeroed}; | |
| use crate::FieldRegistry; | |
| crate::define_addresses! { | |
| class "BitGrid" { | |
| /// BitGrid::init (0x4F6370) β allocates buffer, sets base vtable | |
| fn BIT_GRID_INIT = 0x004F_6370; | |
| /// Core sprite blit (0x4F6910) β ESI=dst BitGrid, 9 stack params | |
| fn/Usercall BLIT_SPRITE_RECT = 0x004F_6910; | |
| /// Clipped line draw on 8bpp BitGrid (0x4F7500) | |
| fn DRAW_LINE_CLIPPED = 0x004F_7500; | |
| /// Two-color line draw on 8bpp BitGrid (0x4F7A60) | |
| fn DRAW_LINE_TWO_COLOR = 0x004F_7A60; | |
| /// `DisplayBitGrid::SetExternalBuffer` (FUN_004F6470) β fastcall | |
| /// `(ECX=height, EDX=width, stack=(bitgrid, data, row_stride))`. | |
| /// Updates an external-buffer bitgrid's data pointer + dimensions | |
| /// + clip rect. Only known caller is `SpriteBank__GetFrameForBlit`, | |
| /// which is itself unreachable in shipping WA β see slot 33. | |
| fn/Fastcall DISPLAY_BIT_GRID_SET_EXTERNAL_BUFFER = 0x004F_6470; | |
| } | |
| } | |
| /// BitGrid β general-purpose 2D grid buffer. | |
| /// | |
| /// Generic over vtable pointer type `V`: | |
| /// - `BitGrid` (default): base form with passive data vtable (0x6640EC). | |
| /// - `CollisionBitGrid`: collision variant for spatial queries (0x664118). | |
| /// - `DisplayBitGrid`: display variant for 8bpp pixel rendering (0x664144). | |
| /// | |
| /// Size: 0x2C bytes (base). Display layers are allocated at 0x4C bytes, with | |
| /// the extra 0x20 bytes holding layer-specific state beyond this struct. | |
| pub struct BitGrid<V: Vtable = *const BitGridBaseVtable> { | |
| /// 0x00: Vtable pointer. Set by `init` to base (0x6640EC), | |
| /// then overridden to collision (0x664118) or display (0x664144). | |
| pub vtable: V, | |
| /// 0x04: External buffer flag. 0 = BitGrid owns data (frees on destroy), | |
| /// nonzero = external ownership. | |
| pub external_buffer: u32, | |
| /// 0x08: Pixel/bit data pointer (row-major, row-aligned to 4 bytes) | |
| pub data: *mut u8, | |
| /// 0x0C: Cells per unit β 1 for bit grids, 8 for 8bpp pixel buffers | |
| pub cells_per_unit: u32, | |
| /// 0x10: Row stride in bytes | |
| pub row_stride: u32, | |
| /// 0x14: Width in pixels/cells | |
| pub width: u32, | |
| /// 0x18: Height in pixels/cells | |
| pub height: u32, | |
| /// 0x1C: Clip/bounds left (x minimum) | |
| pub clip_left: u32, | |
| /// 0x20: Clip/bounds top (y minimum) | |
| pub clip_top: u32, | |
| /// 0x24: Clip/bounds right (x maximum) | |
| pub clip_right: u32, | |
| /// 0x28: Clip/bounds bottom (y maximum) | |
| pub clip_bottom: u32, | |
| } | |
| const _: () = assert!(core::mem::size_of::<BitGrid>() == 0x2C); | |
| impl BitGrid { | |
| /// Pure Rust implementation of BitGrid__Init (0x4F6370). | |
| /// | |
| /// Allocates a row-aligned data buffer and initializes all fields. | |
| /// Sets the base vtable (0x6640EC); callers cast and override to specialize. | |
| /// | |
| /// `cells_per_unit`: 1 for bit grids (collision), 8 for 8bpp pixel buffers. | |
| /// `width` and `height`: dimensions in pixels/cells. | |
| /// | |
| /// # Safety | |
| /// `this` must point to a zero-filled allocation of at least 0x2C bytes. | |
| pub unsafe fn init(this: *mut BitGrid, cells_per_unit: u32, width: u32, height: u32) { | |
| let bits = cells_per_unit.wrapping_mul(width).wrapping_add(7) as i32; | |
| let row_stride = ((bits >> 3) + 3) & !3; | |
| let total_size = row_stride as u32 * height; | |
| let alloc_size = ((total_size + 3) & !3) + 0x20; | |
| let buffer = wa_malloc(alloc_size); | |
| if buffer.is_null() { | |
| return; | |
| } | |
| if total_size as usize > alloc_size as usize { | |
| return; | |
| } | |
| // Note: the original calls memset twice on the same buffer (possibly a | |
| // debug/paranoia pattern from MSVC 2005). We only do it once since the | |
| // second write is a no-op that modern compilers would eliminate anyway. | |
| core::ptr::write_bytes(buffer, 0, total_size as usize); | |
| (*this).vtable = rb(BIT_GRID_BASE_VTABLE) as *const BitGridBaseVtable; | |
| (*this).external_buffer = 0; | |
| (*this).data = buffer; | |
| (*this).cells_per_unit = cells_per_unit; | |
| (*this).row_stride = row_stride as u32; | |
| (*this).width = width; | |
| (*this).height = height; | |
| (*this).clip_left = 0; | |
| (*this).clip_top = 0; | |
| (*this).clip_right = width; | |
| (*this).clip_bottom = height; | |
| } | |
| } | |
| // ========================================================================= | |
| // Base variant (vtable 0x6640EC) | |
| // ========================================================================= | |
| /// BitGrid base vtable (0x6640EC, 8 slots). | |
| /// | |
| /// Bit-level operations. Used as a passive data container (gradient images) | |
| /// and as the initial vtable set by `BitGrid::init` before callers specialize. | |
| /// Slots 6-7 are stubs (get/put pixel not supported in base form). | |
| pub struct BitGridBaseVtable { | |
| /// fill rectangle β bit-level fill (0x4F6760, RET 0x14) | |
| pub fill_rect: fn(this: *mut BitGrid, x1: i32, y1: i32, x2: i32, y2: i32, color: u8), | |
| /// fill horizontal line β bit-level, shared with collision (0x4F67B0, RET 0x10) | |
| pub fill_hline: fn(this: *mut BitGrid, x1: i32, x2: i32, y: i32, color: u8), | |
| /// fill vertical line β bit-level, shared with collision (0x4F6860, RET 0x10) | |
| pub fill_vline: fn(this: *mut BitGrid, x: i32, y1: i32, y2: i32, color: u8), | |
| /// destructor β shared across all variants (0x4F5DE0, RET 0x4) | |
| pub destructor: fn(this: *mut BitGrid, flags: u8) -> *mut BitGrid, | |
| /// get bit (clipped) β bit-level read (0x505430, RET 0x8) | |
| pub get_clipped: fn(this: *mut BitGrid, x: i32, y: i32) -> u8, | |
| /// set bit (clipped) β bit-level write (0x482860, RET 0xC) | |
| pub put_clipped: fn(this: *mut BitGrid, x: i32, y: i32, value: u8), | |
| // Slots 6-7: stubs (0x5D4E16) β get/put pixel not supported in base form | |
| } | |
| bind_BitGridBaseVtable!(BitGrid, vtable); | |
| impl BitGrid { | |
| /// Allocate and initialize a base BitGrid on WA's heap. | |
| /// | |
| /// Used internally by variant `alloc` methods. For external use, | |
| /// prefer `CollisionBitGrid::alloc` or `DisplayBitGrid::alloc`. | |
| /// Returns null if allocation fails. | |
| /// | |
| /// # Safety | |
| /// Must be called from within the WA.exe process. | |
| pub(crate) unsafe fn alloc_base(cells_per_unit: u32, width: u32, height: u32) -> *mut BitGrid { | |
| let grid = wa_malloc_struct_zeroed::<BitGrid>(); | |
| if !grid.is_null() { | |
| BitGrid::init(grid, cells_per_unit, width, height); | |
| } | |
| grid | |
| } | |
| } | |
| // ========================================================================= | |
| // Collision variant (vtable 0x664118) | |
| // ========================================================================= | |
| /// Typed alias for collision BitGrids (vtable 0x664118). | |
| /// | |
| /// Used at DDGame+0x380 for terrain collision/spatial queries. | |
| /// Bit-level operations β one bit per cell. | |
| pub type CollisionBitGrid = BitGrid<*const BitGridCollisionVtable>; | |
| /// BitGrid collision vtable (0x664118, 8 slots). | |
| /// | |
| /// Bit-level spatial query operations. Shares fill_hline/fill_vline | |
| /// implementations with the base vtable, but has distinct get/put methods | |
| /// for bit-level access including unchecked variants. | |
| pub struct BitGridCollisionVtable { | |
| /// fill rectangle β bit-level fill (0x4F8F90, RET 0x14) | |
| pub fill_rect: fn(this: *mut CollisionBitGrid, x1: i32, y1: i32, x2: i32, y2: i32, color: u8), | |
| /// fill horizontal line β bit-level, shared with base (0x4F67B0, RET 0x10) | |
| pub fill_hline: fn(this: *mut CollisionBitGrid, x1: i32, x2: i32, y: i32, color: u8), | |
| /// fill vertical line β bit-level, shared with base (0x4F6860, RET 0x10) | |
| pub fill_vline: fn(this: *mut CollisionBitGrid, x: i32, y1: i32, y2: i32, color: u8), | |
| /// destructor β shared across all variants (0x4F5DE0, RET 0x4) | |
| pub destructor: fn(this: *mut CollisionBitGrid, flags: u8) -> *mut CollisionBitGrid, | |
| /// get bit (clipped) β bit-level read with bounds check (0x4F9020, RET 0x8) | |
| pub get_clipped: fn(this: *mut CollisionBitGrid, x: i32, y: i32) -> u8, | |
| /// set bit (clipped) β bit-level write with bounds check (0x4F9050, RET 0xC) | |
| pub put_clipped: fn(this: *mut CollisionBitGrid, x: i32, y: i32, value: u8), | |
| /// get bit (unchecked) β direct bit read (0x4F5D70, RET 0x8) | |
| pub get: fn(this: *mut CollisionBitGrid, x: i32, y: i32) -> u8, | |
| /// set bit (unchecked) β direct bit write (0x4F5DA0, RET 0xC) | |
| pub put: fn(this: *mut CollisionBitGrid, x: i32, y: i32, value: u8), | |
| } | |
| bind_BitGridCollisionVtable!(CollisionBitGrid, vtable); | |
| impl CollisionBitGrid { | |
| /// Allocate and initialize a collision BitGrid on WA's heap. | |
| /// | |
| /// Calls `BitGrid::init` then overrides the vtable to 0x664118. | |
| /// Returns null if allocation fails. | |
| /// | |
| /// # Safety | |
| /// Must be called from within the WA.exe process. | |
| pub unsafe fn alloc(cells_per_unit: u32, width: u32, height: u32) -> *mut CollisionBitGrid { | |
| let grid = BitGrid::alloc_base(cells_per_unit, width, height); | |
| if !grid.is_null() { | |
| let collision = grid as *mut CollisionBitGrid; | |
| (*collision).vtable = rb(BIT_GRID_COLLISION_VTABLE) as *const BitGridCollisionVtable; | |
| return collision; | |
| } | |
| core::ptr::null_mut() | |
| } | |
| } | |
| // ========================================================================= | |
| // Display layer variant (vtable 0x664144) | |
| // ========================================================================= | |
| /// Typed alias for display-layer BitGrids (vtable 0x664144). | |
| /// | |
| /// Used as rendering layers in DisplayGfx (+0x3D9C, +0x3DA0, +0x3DA4) | |
| /// and as sprite pixel buffers (Sprite+0x34). Provides typed vtable | |
| /// access and bind wrappers for 8bpp pixel drawing operations. | |
| pub type DisplayBitGrid = BitGrid<*const BitGridDisplayVtable>; | |
| /// BitGrid display-layer vtable (0x664144, 8 slots). | |
| /// | |
| /// Byte-level (8bpp) pixel buffer operations for rendering layers. | |
| /// All pixel addressing uses: `data[y * row_stride + x]` | |
| /// | |
| /// DisplayGfx creates 3 layer objects in DisplayGfx__Init: | |
| /// - Layer 0 at DisplayGfx+0x3D9C | |
| /// - Layer 1 at DisplayGfx+0x3DA0 | |
| /// - Layer 2 at DisplayGfx+0x3DA4 | |
| pub struct BitGridDisplayVtable { | |
| /// fill rectangle β memset rows [y1..y2) from x1 to x2 with color (0x4F9090, RET 0x14) | |
| pub fill_rect: fn(this: *mut DisplayBitGrid, x1: i32, y1: i32, x2: i32, y2: i32, color: u8), | |
| /// fill horizontal line β memset row y from x1 to x2 with color (0x4F90E0, RET 0x10) | |
| pub fill_hline: fn(this: *mut DisplayBitGrid, x1: i32, x2: i32, y: i32, color: u8), | |
| /// fill vertical line β set pixels in column x from y1 to y2 (0x4F9110, RET 0x10) | |
| pub fill_vline: fn(this: *mut DisplayBitGrid, x: i32, y1: i32, y2: i32, color: u8), | |
| /// destructor β shared across all variants (0x4F5DE0, RET 0x4) | |
| pub destructor: fn(this: *mut DisplayBitGrid, flags: u8) -> *mut DisplayBitGrid, | |
| /// get pixel (clipped) β returns 0 if outside clip rect (0x4F9140, RET 0x8) | |
| pub get_pixel_clipped: fn(this: *mut DisplayBitGrid, x: i32, y: i32) -> u8, | |
| /// put pixel (clipped) β no-op if outside clip rect (0x4F9180, RET 0xC) | |
| /// | |
| /// This is the main rendering primitive β DisplayGfx dispatches drawing | |
| /// operations through these layer objects. | |
| pub put_pixel_clipped: fn(this: *mut DisplayBitGrid, x: i32, y: i32, color: u8), | |
| /// get pixel (unchecked) β direct read, no bounds checking (0x4F5E20, RET 0x8) | |
| pub get_pixel: fn(this: *mut DisplayBitGrid, x: i32, y: i32) -> u8, | |
| /// put pixel (unchecked) β direct write, no bounds checking (0x4F5E40, RET 0xC) | |
| pub put_pixel: fn(this: *mut DisplayBitGrid, x: i32, y: i32, color: u8), | |
| } | |
| bind_BitGridDisplayVtable!(DisplayBitGrid, vtable); | |
| impl DisplayBitGrid { | |
| /// Allocate and initialize a display BitGrid on WA's heap. | |
| /// | |
| /// Calls `BitGrid::init` then overrides the vtable to 0x664144. | |
| /// Returns null if allocation fails. | |
| /// | |
| /// # Safety | |
| /// Must be called from within the WA.exe process. | |
| pub unsafe fn alloc(cells_per_unit: u32, width: u32, height: u32) -> *mut DisplayBitGrid { | |
| let grid = BitGrid::alloc_base(cells_per_unit, width, height); | |
| if !grid.is_null() { | |
| let display = grid as *mut DisplayBitGrid; | |
| (*display).vtable = rb(BIT_GRID_DISPLAY_VTABLE) as *const BitGridDisplayVtable; | |
| return display; | |
| } | |
| core::ptr::null_mut() | |
| } | |
| } | |