refactor: typed BitGrid variants with alloc constructors
Browse filesMake BitGrid<V> generic over a typed vtable pointer (default =
*const BitGridBaseVtable), removing the unsafe impl Vtable for u32.
Three typed variants, each with its own vtable and alloc constructor:
- BitGrid (base, 0x6640EC) β passive data container, gradient images
- CollisionBitGrid (0x664118) β DDGame+0x380 terrain collision grid
- DisplayBitGrid (0x664144) β rendering layers, sprite pixel buffers
Convenience constructors handle malloc + init + vtable override:
CollisionBitGrid::alloc(1, width, height)
DisplayBitGrid::alloc(8, 0x100, 0x1E0)
Move all BitGrid vtable addresses from address.rs into bitgrid.rs.
Update DDGame fields to use typed pointers (collision_grid, display_bitgrid).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- crates/openwa-core/src/address.rs +5 -12
- crates/openwa-core/src/display/bitgrid.rs +226 -46
- crates/openwa-core/src/display/gfx.rs +4 -4
- crates/openwa-core/src/display/gradient.rs +2 -2
- crates/openwa-core/src/display/mod.rs +4 -1
- crates/openwa-core/src/engine/ddgame.rs +5 -4
- crates/openwa-core/src/engine/ddgame_constructor.rs +10 -24
|
@@ -71,7 +71,10 @@ 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::bitgrid::{
|
|
|
|
|
|
|
|
|
|
| 75 |
pub use crate::display::compat_renderer::{
|
| 76 |
CompatRendererVtable, COMPAT_RENDERER_VTABLE, DDRAW8_RENDERER_VTABLE,
|
| 77 |
};
|
|
@@ -182,8 +185,7 @@ pub mod va {
|
|
| 182 |
fn/Usercall INPUT_CTRL_INIT = 0x0058_C0D0;
|
| 183 |
}
|
| 184 |
|
| 185 |
-
//
|
| 186 |
-
// Vtable 0x664118 is now BIT_GRID_VARIANT_VTABLE in the BitGrid class block.
|
| 187 |
|
| 188 |
class "OpenGLCPU" {
|
| 189 |
/// OpenGLCPU vtable (0x48-byte object)
|
|
@@ -225,15 +227,6 @@ pub mod va {
|
|
| 225 |
fn GFX_DIR_LOAD_IMAGE = 0x0056_66D0;
|
| 226 |
}
|
| 227 |
|
| 228 |
-
class "BitGrid" {
|
| 229 |
-
/// BitGrid base vtable
|
| 230 |
-
vtable BIT_GRID_VTABLE = 0x0066_40EC;
|
| 231 |
-
/// BitGrid variant vtable (used for DDGame+0x380 collision grid)
|
| 232 |
-
vtable BIT_GRID_VARIANT_VTABLE = 0x0066_4118;
|
| 233 |
-
/// BitGrid init
|
| 234 |
-
fn BIT_GRID_INIT = 0x004F_6370;
|
| 235 |
-
}
|
| 236 |
-
|
| 237 |
class "DisplayGfx" {
|
| 238 |
/// DisplayGfx constructor
|
| 239 |
ctor/Stdcall DISPLAYGFX_CTOR = 0x0056_9C10;
|
|
|
|
| 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::bitgrid::{
|
| 75 |
+
BitGridBaseVtable, BitGridCollisionVtable, BitGridDisplayVtable, BIT_GRID_BASE_VTABLE,
|
| 76 |
+
BIT_GRID_COLLISION_VTABLE, BIT_GRID_DISPLAY_VTABLE, BIT_GRID_INIT,
|
| 77 |
+
};
|
| 78 |
pub use crate::display::compat_renderer::{
|
| 79 |
CompatRendererVtable, COMPAT_RENDERER_VTABLE, DDRAW8_RENDERER_VTABLE,
|
| 80 |
};
|
|
|
|
| 185 |
fn/Usercall INPUT_CTRL_INIT = 0x0058_C0D0;
|
| 186 |
}
|
| 187 |
|
| 188 |
+
// BitGrid vtables and init are now in display::bitgrid via define_addresses! + #[vtable].
|
|
|
|
| 189 |
|
| 190 |
class "OpenGLCPU" {
|
| 191 |
/// OpenGLCPU vtable (0x48-byte object)
|
|
|
|
| 227 |
fn GFX_DIR_LOAD_IMAGE = 0x0056_66D0;
|
| 228 |
}
|
| 229 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 230 |
class "DisplayGfx" {
|
| 231 |
/// DisplayGfx constructor
|
| 232 |
ctor/Stdcall DISPLAYGFX_CTOR = 0x0056_9C10;
|
|
@@ -1,40 +1,73 @@
|
|
| 1 |
-
//! BitGrid β 2D
|
| 2 |
//!
|
| 3 |
-
//!
|
| 4 |
-
//!
|
| 5 |
-
//! Initialized by `BitGrid::init` (0x4F6370). Size: 0x2C bytes.
|
| 6 |
-
//! - **Display layer** (0x664144, 8 slots): Pixel buffer with drawing primitives.
|
| 7 |
-
//! Used as rendering layers in DisplayGfx (+0x3D9C/+0x3DA0/+0x3DA4).
|
| 8 |
-
//! Allocated at 0x4C bytes; first 0x2C bytes share the base layout.
|
| 9 |
//!
|
| 10 |
-
//!
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
//!
|
| 12 |
-
//!
|
| 13 |
-
//!
|
| 14 |
-
//!
|
| 15 |
-
//! -
|
| 16 |
-
//!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
|
| 18 |
-
use crate::address::va;
|
| 19 |
use crate::rebase::rb;
|
| 20 |
-
use crate::
|
|
|
|
| 21 |
use crate::FieldRegistry;
|
| 22 |
|
| 23 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
///
|
| 25 |
-
///
|
| 26 |
-
///
|
| 27 |
-
/// Size: 0x2C bytes (base), 0x4C bytes (display layer).
|
| 28 |
#[derive(FieldRegistry)]
|
| 29 |
#[repr(C)]
|
| 30 |
-
pub struct BitGrid {
|
| 31 |
-
|
|
|
|
|
|
|
| 32 |
/// 0x04: External buffer flag. 0 = BitGrid owns data (frees on destroy),
|
| 33 |
/// nonzero = external ownership.
|
| 34 |
pub external_buffer: u32,
|
| 35 |
-
/// 0x08: Pixel/bit data pointer
|
| 36 |
pub data: *mut u8,
|
| 37 |
-
/// 0x0C: Cells per unit
|
| 38 |
pub cells_per_unit: u32,
|
| 39 |
/// 0x10: Row stride in bytes
|
| 40 |
pub row_stride: u32,
|
|
@@ -42,13 +75,13 @@ pub struct BitGrid {
|
|
| 42 |
pub width: u32,
|
| 43 |
/// 0x18: Height in pixels/cells
|
| 44 |
pub height: u32,
|
| 45 |
-
/// 0x1C: Clip left
|
| 46 |
pub clip_left: u32,
|
| 47 |
-
/// 0x20: Clip top
|
| 48 |
pub clip_top: u32,
|
| 49 |
-
/// 0x24: Clip right
|
| 50 |
pub clip_right: u32,
|
| 51 |
-
/// 0x28: Clip bottom
|
| 52 |
pub clip_bottom: u32,
|
| 53 |
}
|
| 54 |
|
|
@@ -57,9 +90,11 @@ const _: () = assert!(core::mem::size_of::<BitGrid>() == 0x2C);
|
|
| 57 |
impl BitGrid {
|
| 58 |
/// Pure Rust implementation of BitGrid__Init (0x4F6370).
|
| 59 |
///
|
| 60 |
-
/// Allocates a
|
| 61 |
-
///
|
| 62 |
-
///
|
|
|
|
|
|
|
| 63 |
///
|
| 64 |
/// # Safety
|
| 65 |
/// `this` must point to a zero-filled allocation of at least 0x2C bytes.
|
|
@@ -83,7 +118,7 @@ impl BitGrid {
|
|
| 83 |
// second write is a no-op that modern compilers would eliminate anyway.
|
| 84 |
core::ptr::write_bytes(buffer, 0, total_size as usize);
|
| 85 |
|
| 86 |
-
(*this).vtable = rb(
|
| 87 |
(*this).external_buffer = 0;
|
| 88 |
(*this).data = buffer;
|
| 89 |
(*this).cells_per_unit = cells_per_unit;
|
|
@@ -97,45 +132,190 @@ impl BitGrid {
|
|
| 97 |
}
|
| 98 |
}
|
| 99 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 100 |
/// BitGrid display-layer vtable (0x664144, 8 slots).
|
| 101 |
///
|
| 102 |
-
///
|
| 103 |
/// All pixel addressing uses: `data[y * row_stride + x]`
|
| 104 |
///
|
| 105 |
/// DDDisplay creates 3 layer objects in DDDisplay__Init:
|
| 106 |
/// - Layer 0 at DisplayGfx+0x3D9C
|
| 107 |
/// - Layer 1 at DisplayGfx+0x3DA0
|
| 108 |
-
/// - Layer 2 at DisplayGfx+0x3DA4
|
| 109 |
#[openwa_core::vtable(size = 8, va = 0x0066_4144, class = "BitGridDisplay")]
|
| 110 |
pub struct BitGridDisplayVtable {
|
| 111 |
/// fill rectangle β memset rows [y1..y2) from x1 to x2 with color (0x4F9090, RET 0x14)
|
| 112 |
#[slot(0)]
|
| 113 |
-
pub fill_rect: fn(this: *mut
|
| 114 |
/// fill horizontal line β memset row y from x1 to x2 with color (0x4F90E0, RET 0x10)
|
| 115 |
#[slot(1)]
|
| 116 |
-
pub fill_hline: fn(this: *mut
|
| 117 |
/// fill vertical line β set pixels in column x from y1 to y2 (0x4F9110, RET 0x10)
|
| 118 |
#[slot(2)]
|
| 119 |
-
pub fill_vline: fn(this: *mut
|
| 120 |
-
/// destructor β
|
| 121 |
#[slot(3)]
|
| 122 |
-
pub destructor: fn(this: *mut
|
| 123 |
-
/// get pixel (clipped) β returns 0 if
|
| 124 |
#[slot(4)]
|
| 125 |
-
pub get_pixel_clipped: fn(this: *mut
|
| 126 |
-
/// put pixel (clipped) β no-op if
|
| 127 |
///
|
| 128 |
/// This is the main rendering primitive β DDDisplay dispatches drawing
|
| 129 |
/// operations through these layer objects.
|
| 130 |
#[slot(5)]
|
| 131 |
-
pub put_pixel_clipped: fn(this: *mut
|
| 132 |
/// get pixel (unchecked) β direct read, no bounds checking (0x4F5E20, RET 0x8)
|
| 133 |
#[slot(6)]
|
| 134 |
-
pub get_pixel: fn(this: *mut
|
| 135 |
/// put pixel (unchecked) β direct write, no bounds checking (0x4F5E40, RET 0xC)
|
| 136 |
#[slot(7)]
|
| 137 |
-
pub put_pixel: fn(this: *mut
|
| 138 |
}
|
| 139 |
|
| 140 |
-
|
| 141 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//! BitGrid β general-purpose 2D grid buffer.
|
| 2 |
//!
|
| 3 |
+
//! A polymorphic pixel/bit buffer used across WA's rendering and physics systems.
|
| 4 |
+
//! The same struct layout serves multiple roles, distinguished by vtable:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
//!
|
| 6 |
+
//! | Vtable | Type | Role |
|
| 7 |
+
//! |------------|---------------------|------------------------------|
|
| 8 |
+
//! | 0x6640EC | `BitGrid` | Base β set by `init`, passive data container |
|
| 9 |
+
//! | 0x664118 | `CollisionBitGrid` | Collision grid (DDGame+0x380), bit-level spatial queries |
|
| 10 |
+
//! | 0x664144 | `DisplayBitGrid` | Display layers and sprite pixel buffers, 8bpp byte-level ops |
|
| 11 |
//!
|
| 12 |
+
//! All three vtables share the same 8-slot interface:
|
| 13 |
+
//!
|
| 14 |
+
//! | Slot | Method | Base | Collision | Display |
|
| 15 |
+
//! |------|------------------|---------------|---------------|---------------|
|
| 16 |
+
//! | 0 | fill_rect | bit-level | bit-level | byte-level |
|
| 17 |
+
//! | 1 | fill_hline | bit-level * | bit-level * | byte-level |
|
| 18 |
+
//! | 2 | fill_vline | bit-level * | bit-level * | byte-level |
|
| 19 |
+
//! | 3 | destructor | shared * | shared * | shared * |
|
| 20 |
+
//! | 4 | get_clipped | bit-level | bit-level | byte-level |
|
| 21 |
+
//! | 5 | put_clipped | bit-level | bit-level | byte-level |
|
| 22 |
+
//! | 6 | get | stub | bit-level | byte-level |
|
| 23 |
+
//! | 7 | put | stub | bit-level | byte-level |
|
| 24 |
+
//!
|
| 25 |
+
//! * = same function pointer shared between variants.
|
| 26 |
+
//!
|
| 27 |
+
//! ## Initialization pattern
|
| 28 |
+
//!
|
| 29 |
+
//! `BitGrid::init` allocates the data buffer, fills in all fields, and sets
|
| 30 |
+
//! the base vtable (0x6640EC). Callers then cast and override the vtable:
|
| 31 |
+
//!
|
| 32 |
+
//! ```text
|
| 33 |
+
//! BitGrid::init(grid, cells_per_unit, width, height);
|
| 34 |
+
//! let display_grid = grid as *mut DisplayBitGrid;
|
| 35 |
+
//! (*display_grid).vtable = rb_ptr(BIT_GRID_DISPLAY_VTABLE);
|
| 36 |
+
//! ```
|
| 37 |
|
|
|
|
| 38 |
use crate::rebase::rb;
|
| 39 |
+
use crate::task::base::Vtable;
|
| 40 |
+
use crate::wa_alloc::{wa_malloc, wa_malloc_struct_zeroed};
|
| 41 |
use crate::FieldRegistry;
|
| 42 |
|
| 43 |
+
crate::define_addresses! {
|
| 44 |
+
class "BitGrid" {
|
| 45 |
+
/// BitGrid::init (0x4F6370) β allocates buffer, sets base vtable
|
| 46 |
+
fn BIT_GRID_INIT = 0x004F_6370;
|
| 47 |
+
}
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
/// BitGrid β general-purpose 2D grid buffer.
|
| 51 |
+
///
|
| 52 |
+
/// Generic over vtable pointer type `V`:
|
| 53 |
+
/// - `BitGrid` (default): base form with passive data vtable (0x6640EC).
|
| 54 |
+
/// - `CollisionBitGrid`: collision variant for spatial queries (0x664118).
|
| 55 |
+
/// - `DisplayBitGrid`: display variant for 8bpp pixel rendering (0x664144).
|
| 56 |
///
|
| 57 |
+
/// Size: 0x2C bytes (base). Display layers are allocated at 0x4C bytes, with
|
| 58 |
+
/// the extra 0x20 bytes holding layer-specific state beyond this struct.
|
|
|
|
| 59 |
#[derive(FieldRegistry)]
|
| 60 |
#[repr(C)]
|
| 61 |
+
pub struct BitGrid<V: Vtable = *const BitGridBaseVtable> {
|
| 62 |
+
/// 0x00: Vtable pointer. Set by `init` to base (0x6640EC),
|
| 63 |
+
/// then overridden to collision (0x664118) or display (0x664144).
|
| 64 |
+
pub vtable: V,
|
| 65 |
/// 0x04: External buffer flag. 0 = BitGrid owns data (frees on destroy),
|
| 66 |
/// nonzero = external ownership.
|
| 67 |
pub external_buffer: u32,
|
| 68 |
+
/// 0x08: Pixel/bit data pointer (row-major, row-aligned to 4 bytes)
|
| 69 |
pub data: *mut u8,
|
| 70 |
+
/// 0x0C: Cells per unit β 1 for bit grids, 8 for 8bpp pixel buffers
|
| 71 |
pub cells_per_unit: u32,
|
| 72 |
/// 0x10: Row stride in bytes
|
| 73 |
pub row_stride: u32,
|
|
|
|
| 75 |
pub width: u32,
|
| 76 |
/// 0x18: Height in pixels/cells
|
| 77 |
pub height: u32,
|
| 78 |
+
/// 0x1C: Clip/bounds left (x minimum)
|
| 79 |
pub clip_left: u32,
|
| 80 |
+
/// 0x20: Clip/bounds top (y minimum)
|
| 81 |
pub clip_top: u32,
|
| 82 |
+
/// 0x24: Clip/bounds right (x maximum)
|
| 83 |
pub clip_right: u32,
|
| 84 |
+
/// 0x28: Clip/bounds bottom (y maximum)
|
| 85 |
pub clip_bottom: u32,
|
| 86 |
}
|
| 87 |
|
|
|
|
| 90 |
impl BitGrid {
|
| 91 |
/// Pure Rust implementation of BitGrid__Init (0x4F6370).
|
| 92 |
///
|
| 93 |
+
/// Allocates a row-aligned data buffer and initializes all fields.
|
| 94 |
+
/// Sets the base vtable (0x6640EC); callers cast and override to specialize.
|
| 95 |
+
///
|
| 96 |
+
/// `cells_per_unit`: 1 for bit grids (collision), 8 for 8bpp pixel buffers.
|
| 97 |
+
/// `width` and `height`: dimensions in pixels/cells.
|
| 98 |
///
|
| 99 |
/// # Safety
|
| 100 |
/// `this` must point to a zero-filled allocation of at least 0x2C bytes.
|
|
|
|
| 118 |
// second write is a no-op that modern compilers would eliminate anyway.
|
| 119 |
core::ptr::write_bytes(buffer, 0, total_size as usize);
|
| 120 |
|
| 121 |
+
(*this).vtable = rb(BIT_GRID_BASE_VTABLE) as *const BitGridBaseVtable;
|
| 122 |
(*this).external_buffer = 0;
|
| 123 |
(*this).data = buffer;
|
| 124 |
(*this).cells_per_unit = cells_per_unit;
|
|
|
|
| 132 |
}
|
| 133 |
}
|
| 134 |
|
| 135 |
+
// =========================================================================
|
| 136 |
+
// Base variant (vtable 0x6640EC)
|
| 137 |
+
// =========================================================================
|
| 138 |
+
|
| 139 |
+
/// BitGrid base vtable (0x6640EC, 8 slots).
|
| 140 |
+
///
|
| 141 |
+
/// Bit-level operations. Used as a passive data container (gradient images)
|
| 142 |
+
/// and as the initial vtable set by `BitGrid::init` before callers specialize.
|
| 143 |
+
/// Slots 6-7 are stubs (get/put pixel not supported in base form).
|
| 144 |
+
#[openwa_core::vtable(size = 8, va = 0x0066_40EC, class = "BitGridBase")]
|
| 145 |
+
pub struct BitGridBaseVtable {
|
| 146 |
+
/// fill rectangle β bit-level fill (0x4F6760, RET 0x14)
|
| 147 |
+
#[slot(0)]
|
| 148 |
+
pub fill_rect: fn(this: *mut BitGrid, x1: i32, y1: i32, x2: i32, y2: i32, color: u8),
|
| 149 |
+
/// fill horizontal line β bit-level, shared with collision (0x4F67B0, RET 0x10)
|
| 150 |
+
#[slot(1)]
|
| 151 |
+
pub fill_hline: fn(this: *mut BitGrid, x1: i32, x2: i32, y: i32, color: u8),
|
| 152 |
+
/// fill vertical line β bit-level, shared with collision (0x4F6860, RET 0x10)
|
| 153 |
+
#[slot(2)]
|
| 154 |
+
pub fill_vline: fn(this: *mut BitGrid, x: i32, y1: i32, y2: i32, color: u8),
|
| 155 |
+
/// destructor β shared across all variants (0x4F5DE0, RET 0x4)
|
| 156 |
+
#[slot(3)]
|
| 157 |
+
pub destructor: fn(this: *mut BitGrid, flags: u8) -> *mut BitGrid,
|
| 158 |
+
/// get bit (clipped) β bit-level read (0x505430, RET 0x8)
|
| 159 |
+
#[slot(4)]
|
| 160 |
+
pub get_clipped: fn(this: *mut BitGrid, x: i32, y: i32) -> u8,
|
| 161 |
+
/// set bit (clipped) β bit-level write (0x482860, RET 0xC)
|
| 162 |
+
#[slot(5)]
|
| 163 |
+
pub put_clipped: fn(this: *mut BitGrid, x: i32, y: i32, value: u8),
|
| 164 |
+
// Slots 6-7: stubs (0x5D4E16) β get/put pixel not supported in base form
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
bind_BitGridBaseVtable!(BitGrid, vtable);
|
| 168 |
+
|
| 169 |
+
impl BitGrid {
|
| 170 |
+
/// Allocate and initialize a base BitGrid on WA's heap.
|
| 171 |
+
///
|
| 172 |
+
/// Used internally by variant `alloc` methods. For external use,
|
| 173 |
+
/// prefer `CollisionBitGrid::alloc` or `DisplayBitGrid::alloc`.
|
| 174 |
+
/// Returns null if allocation fails.
|
| 175 |
+
///
|
| 176 |
+
/// # Safety
|
| 177 |
+
/// Must be called from within the WA.exe process.
|
| 178 |
+
pub(crate) unsafe fn alloc_base(cells_per_unit: u32, width: u32, height: u32) -> *mut BitGrid {
|
| 179 |
+
let grid = wa_malloc_struct_zeroed::<BitGrid>();
|
| 180 |
+
if !grid.is_null() {
|
| 181 |
+
BitGrid::init(grid, cells_per_unit, width, height);
|
| 182 |
+
}
|
| 183 |
+
grid
|
| 184 |
+
}
|
| 185 |
+
}
|
| 186 |
+
|
| 187 |
+
// =========================================================================
|
| 188 |
+
// Collision variant (vtable 0x664118)
|
| 189 |
+
// =========================================================================
|
| 190 |
+
|
| 191 |
+
/// Typed alias for collision BitGrids (vtable 0x664118).
|
| 192 |
+
///
|
| 193 |
+
/// Used at DDGame+0x380 for terrain collision/spatial queries.
|
| 194 |
+
/// Bit-level operations β one bit per cell.
|
| 195 |
+
pub type CollisionBitGrid = BitGrid<*const BitGridCollisionVtable>;
|
| 196 |
+
|
| 197 |
+
/// BitGrid collision vtable (0x664118, 8 slots).
|
| 198 |
+
///
|
| 199 |
+
/// Bit-level spatial query operations. Shares fill_hline/fill_vline
|
| 200 |
+
/// implementations with the base vtable, but has distinct get/put methods
|
| 201 |
+
/// for bit-level access including unchecked variants.
|
| 202 |
+
#[openwa_core::vtable(size = 8, va = 0x0066_4118, class = "BitGridCollision")]
|
| 203 |
+
pub struct BitGridCollisionVtable {
|
| 204 |
+
/// fill rectangle β bit-level fill (0x4F8F90, RET 0x14)
|
| 205 |
+
#[slot(0)]
|
| 206 |
+
pub fill_rect: fn(this: *mut CollisionBitGrid, x1: i32, y1: i32, x2: i32, y2: i32, color: u8),
|
| 207 |
+
/// fill horizontal line β bit-level, shared with base (0x4F67B0, RET 0x10)
|
| 208 |
+
#[slot(1)]
|
| 209 |
+
pub fill_hline: fn(this: *mut CollisionBitGrid, x1: i32, x2: i32, y: i32, color: u8),
|
| 210 |
+
/// fill vertical line β bit-level, shared with base (0x4F6860, RET 0x10)
|
| 211 |
+
#[slot(2)]
|
| 212 |
+
pub fill_vline: fn(this: *mut CollisionBitGrid, x: i32, y1: i32, y2: i32, color: u8),
|
| 213 |
+
/// destructor β shared across all variants (0x4F5DE0, RET 0x4)
|
| 214 |
+
#[slot(3)]
|
| 215 |
+
pub destructor: fn(this: *mut CollisionBitGrid, flags: u8) -> *mut CollisionBitGrid,
|
| 216 |
+
/// get bit (clipped) β bit-level read with bounds check (0x4F9020, RET 0x8)
|
| 217 |
+
#[slot(4)]
|
| 218 |
+
pub get_clipped: fn(this: *mut CollisionBitGrid, x: i32, y: i32) -> u8,
|
| 219 |
+
/// set bit (clipped) β bit-level write with bounds check (0x4F9050, RET 0xC)
|
| 220 |
+
#[slot(5)]
|
| 221 |
+
pub put_clipped: fn(this: *mut CollisionBitGrid, x: i32, y: i32, value: u8),
|
| 222 |
+
/// get bit (unchecked) β direct bit read (0x4F5D70, RET 0x8)
|
| 223 |
+
#[slot(6)]
|
| 224 |
+
pub get: fn(this: *mut CollisionBitGrid, x: i32, y: i32) -> u8,
|
| 225 |
+
/// set bit (unchecked) β direct bit write (0x4F5DA0, RET 0xC)
|
| 226 |
+
#[slot(7)]
|
| 227 |
+
pub put: fn(this: *mut CollisionBitGrid, x: i32, y: i32, value: u8),
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
bind_BitGridCollisionVtable!(CollisionBitGrid, vtable);
|
| 231 |
+
|
| 232 |
+
impl CollisionBitGrid {
|
| 233 |
+
/// Allocate and initialize a collision BitGrid on WA's heap.
|
| 234 |
+
///
|
| 235 |
+
/// Calls `BitGrid::init` then overrides the vtable to 0x664118.
|
| 236 |
+
/// Returns null if allocation fails.
|
| 237 |
+
///
|
| 238 |
+
/// # Safety
|
| 239 |
+
/// Must be called from within the WA.exe process.
|
| 240 |
+
pub unsafe fn alloc(cells_per_unit: u32, width: u32, height: u32) -> *mut CollisionBitGrid {
|
| 241 |
+
let grid = BitGrid::alloc_base(cells_per_unit, width, height);
|
| 242 |
+
if !grid.is_null() {
|
| 243 |
+
let collision = grid as *mut CollisionBitGrid;
|
| 244 |
+
(*collision).vtable = rb(BIT_GRID_COLLISION_VTABLE) as *const BitGridCollisionVtable;
|
| 245 |
+
return collision;
|
| 246 |
+
}
|
| 247 |
+
core::ptr::null_mut()
|
| 248 |
+
}
|
| 249 |
+
}
|
| 250 |
+
|
| 251 |
+
// =========================================================================
|
| 252 |
+
// Display layer variant (vtable 0x664144)
|
| 253 |
+
// =========================================================================
|
| 254 |
+
|
| 255 |
+
/// Typed alias for display-layer BitGrids (vtable 0x664144).
|
| 256 |
+
///
|
| 257 |
+
/// Used as rendering layers in DisplayGfx (+0x3D9C, +0x3DA0, +0x3DA4)
|
| 258 |
+
/// and as sprite pixel buffers (Sprite+0x34). Provides typed vtable
|
| 259 |
+
/// access and bind wrappers for 8bpp pixel drawing operations.
|
| 260 |
+
pub type DisplayBitGrid = BitGrid<*const BitGridDisplayVtable>;
|
| 261 |
+
|
| 262 |
/// BitGrid display-layer vtable (0x664144, 8 slots).
|
| 263 |
///
|
| 264 |
+
/// Byte-level (8bpp) pixel buffer operations for rendering layers.
|
| 265 |
/// All pixel addressing uses: `data[y * row_stride + x]`
|
| 266 |
///
|
| 267 |
/// DDDisplay creates 3 layer objects in DDDisplay__Init:
|
| 268 |
/// - Layer 0 at DisplayGfx+0x3D9C
|
| 269 |
/// - Layer 1 at DisplayGfx+0x3DA0
|
| 270 |
+
/// - Layer 2 at DisplayGfx+0x3DA4
|
| 271 |
#[openwa_core::vtable(size = 8, va = 0x0066_4144, class = "BitGridDisplay")]
|
| 272 |
pub struct BitGridDisplayVtable {
|
| 273 |
/// fill rectangle β memset rows [y1..y2) from x1 to x2 with color (0x4F9090, RET 0x14)
|
| 274 |
#[slot(0)]
|
| 275 |
+
pub fill_rect: fn(this: *mut DisplayBitGrid, x1: i32, y1: i32, x2: i32, y2: i32, color: u8),
|
| 276 |
/// fill horizontal line β memset row y from x1 to x2 with color (0x4F90E0, RET 0x10)
|
| 277 |
#[slot(1)]
|
| 278 |
+
pub fill_hline: fn(this: *mut DisplayBitGrid, x1: i32, x2: i32, y: i32, color: u8),
|
| 279 |
/// fill vertical line β set pixels in column x from y1 to y2 (0x4F9110, RET 0x10)
|
| 280 |
#[slot(2)]
|
| 281 |
+
pub fill_vline: fn(this: *mut DisplayBitGrid, x: i32, y1: i32, y2: i32, color: u8),
|
| 282 |
+
/// destructor β shared across all variants (0x4F5DE0, RET 0x4)
|
| 283 |
#[slot(3)]
|
| 284 |
+
pub destructor: fn(this: *mut DisplayBitGrid, flags: u8) -> *mut DisplayBitGrid,
|
| 285 |
+
/// get pixel (clipped) β returns 0 if outside clip rect (0x4F9140, RET 0x8)
|
| 286 |
#[slot(4)]
|
| 287 |
+
pub get_pixel_clipped: fn(this: *mut DisplayBitGrid, x: i32, y: i32) -> u8,
|
| 288 |
+
/// put pixel (clipped) β no-op if outside clip rect (0x4F9180, RET 0xC)
|
| 289 |
///
|
| 290 |
/// This is the main rendering primitive β DDDisplay dispatches drawing
|
| 291 |
/// operations through these layer objects.
|
| 292 |
#[slot(5)]
|
| 293 |
+
pub put_pixel_clipped: fn(this: *mut DisplayBitGrid, x: i32, y: i32, color: u8),
|
| 294 |
/// get pixel (unchecked) β direct read, no bounds checking (0x4F5E20, RET 0x8)
|
| 295 |
#[slot(6)]
|
| 296 |
+
pub get_pixel: fn(this: *mut DisplayBitGrid, x: i32, y: i32) -> u8,
|
| 297 |
/// put pixel (unchecked) β direct write, no bounds checking (0x4F5E40, RET 0xC)
|
| 298 |
#[slot(7)]
|
| 299 |
+
pub put_pixel: fn(this: *mut DisplayBitGrid, x: i32, y: i32, color: u8),
|
| 300 |
}
|
| 301 |
|
| 302 |
+
bind_BitGridDisplayVtable!(DisplayBitGrid, vtable);
|
| 303 |
+
|
| 304 |
+
impl DisplayBitGrid {
|
| 305 |
+
/// Allocate and initialize a display BitGrid on WA's heap.
|
| 306 |
+
///
|
| 307 |
+
/// Calls `BitGrid::init` then overrides the vtable to 0x664144.
|
| 308 |
+
/// Returns null if allocation fails.
|
| 309 |
+
///
|
| 310 |
+
/// # Safety
|
| 311 |
+
/// Must be called from within the WA.exe process.
|
| 312 |
+
pub unsafe fn alloc(cells_per_unit: u32, width: u32, height: u32) -> *mut DisplayBitGrid {
|
| 313 |
+
let grid = BitGrid::alloc_base(cells_per_unit, width, height);
|
| 314 |
+
if !grid.is_null() {
|
| 315 |
+
let display = grid as *mut DisplayBitGrid;
|
| 316 |
+
(*display).vtable = rb(BIT_GRID_DISPLAY_VTABLE) as *const BitGridDisplayVtable;
|
| 317 |
+
return display;
|
| 318 |
+
}
|
| 319 |
+
core::ptr::null_mut()
|
| 320 |
+
}
|
| 321 |
+
}
|
|
@@ -1,5 +1,5 @@
|
|
| 1 |
use super::base::DisplayBase;
|
| 2 |
-
use super::bitgrid::
|
| 3 |
use core::ffi::c_void;
|
| 4 |
|
| 5 |
/// DisplayGfx β full display/graphics subsystem (derived from DisplayBase).
|
|
@@ -99,11 +99,11 @@ pub struct DisplayGfx {
|
|
| 99 |
pub render_lock: u32,
|
| 100 |
/// 0x3D9C: Layer 0 β BitGrid pixel buffer (0x4C bytes, vtable 0x664144).
|
| 101 |
/// Allocated and initialized in DDDisplay__Init.
|
| 102 |
-
pub layer_0: *mut
|
| 103 |
/// 0x3DA0: Layer 1 β BitGrid pixel buffer (same type as layer_0)
|
| 104 |
-
pub layer_1: *mut
|
| 105 |
/// 0x3DA4: Layer 2 β BitGrid pixel buffer (uses BitGrid__Init for extended setup)
|
| 106 |
-
pub layer_2: *mut
|
| 107 |
/// 0x3DA8: BitGrid vtable pointer (0x664144). Set in constructor.
|
| 108 |
pub bitgrid_vtable: *const c_void,
|
| 109 |
/// 0x3DAC: Layer active flag (init 1)
|
|
|
|
| 1 |
use super::base::DisplayBase;
|
| 2 |
+
use super::bitgrid::DisplayBitGrid;
|
| 3 |
use core::ffi::c_void;
|
| 4 |
|
| 5 |
/// DisplayGfx β full display/graphics subsystem (derived from DisplayBase).
|
|
|
|
| 99 |
pub render_lock: u32,
|
| 100 |
/// 0x3D9C: Layer 0 β BitGrid pixel buffer (0x4C bytes, vtable 0x664144).
|
| 101 |
/// Allocated and initialized in DDDisplay__Init.
|
| 102 |
+
pub layer_0: *mut DisplayBitGrid,
|
| 103 |
/// 0x3DA0: Layer 1 β BitGrid pixel buffer (same type as layer_0)
|
| 104 |
+
pub layer_1: *mut DisplayBitGrid,
|
| 105 |
/// 0x3DA4: Layer 2 β BitGrid pixel buffer (uses BitGrid__Init for extended setup)
|
| 106 |
+
pub layer_2: *mut DisplayBitGrid,
|
| 107 |
/// 0x3DA8: BitGrid vtable pointer (0x664144). Set in constructor.
|
| 108 |
pub bitgrid_vtable: *const c_void,
|
| 109 |
/// 0x3DAC: Layer active flag (init 1)
|
|
@@ -6,7 +6,7 @@
|
|
| 6 |
//! may have subtle color differences due to the tangled decompiler output.
|
| 7 |
|
| 8 |
use crate::address::va;
|
| 9 |
-
use crate::display::bitgrid::BitGrid;
|
| 10 |
use crate::engine::ddgame::DDGame;
|
| 11 |
use crate::rebase::rb;
|
| 12 |
use crate::render::gfx_dir::call_gfx_find_and_load;
|
|
@@ -248,7 +248,7 @@ pub(crate) unsafe fn compute_complex_gradient(
|
|
| 248 |
return;
|
| 249 |
}
|
| 250 |
core::ptr::write_bytes(gfx_obj as *mut u8, 0, core::mem::size_of::<BitGrid>());
|
| 251 |
-
(*gfx_obj).vtable = rb(va::
|
| 252 |
(*gfx_obj).data = data;
|
| 253 |
(*gfx_obj).row_stride = stride;
|
| 254 |
(*gfx_obj).width = 0;
|
|
|
|
| 6 |
//! may have subtle color differences due to the tangled decompiler output.
|
| 7 |
|
| 8 |
use crate::address::va;
|
| 9 |
+
use crate::display::bitgrid::{BitGrid, BitGridBaseVtable};
|
| 10 |
use crate::engine::ddgame::DDGame;
|
| 11 |
use crate::rebase::rb;
|
| 12 |
use crate::render::gfx_dir::call_gfx_find_and_load;
|
|
|
|
| 248 |
return;
|
| 249 |
}
|
| 250 |
core::ptr::write_bytes(gfx_obj as *mut u8, 0, core::mem::size_of::<BitGrid>());
|
| 251 |
+
(*gfx_obj).vtable = rb(va::BIT_GRID_BASE_VTABLE) as *const BitGridBaseVtable;
|
| 252 |
(*gfx_obj).data = data;
|
| 253 |
(*gfx_obj).row_stride = stride;
|
| 254 |
(*gfx_obj).width = 0;
|
|
@@ -9,7 +9,10 @@ pub mod opengl;
|
|
| 9 |
pub mod palette;
|
| 10 |
|
| 11 |
pub use base::{DisplayBase, DisplayBaseVtable, SpriteBufferCtrl, SpriteCacheWrapper};
|
| 12 |
-
pub use bitgrid::{
|
|
|
|
|
|
|
|
|
|
| 13 |
pub use compat_renderer::CompatRenderer;
|
| 14 |
pub use dd_display::DDDisplay;
|
| 15 |
pub use display_wrapper::DDDisplayWrapper;
|
|
|
|
| 9 |
pub mod palette;
|
| 10 |
|
| 11 |
pub use base::{DisplayBase, DisplayBaseVtable, SpriteBufferCtrl, SpriteCacheWrapper};
|
| 12 |
+
pub use bitgrid::{
|
| 13 |
+
BitGrid, BitGridBaseVtable, BitGridCollisionVtable, BitGridDisplayVtable, CollisionBitGrid,
|
| 14 |
+
DisplayBitGrid,
|
| 15 |
+
};
|
| 16 |
pub use compat_renderer::CompatRenderer;
|
| 17 |
pub use dd_display::DDDisplay;
|
| 18 |
pub use display_wrapper::DDDisplayWrapper;
|
|
@@ -4,7 +4,7 @@ use crate::audio::music::Music;
|
|
| 4 |
use crate::audio::speech::SpeechSlotTable;
|
| 5 |
use crate::display::dd_display::DDDisplay;
|
| 6 |
use crate::display::palette::Palette;
|
| 7 |
-
use crate::display::
|
| 8 |
use crate::engine::game_info::GameInfo;
|
| 9 |
use crate::engine::{
|
| 10 |
CoordEntry, CoordList, RenderEntry, SoundQueueEntry, TeamArenaState, TeamIndexMap,
|
|
@@ -71,14 +71,15 @@ pub struct DDGame {
|
|
| 71 |
pub arrow_gfxdirs: [*mut u8; 32],
|
| 72 |
/// 0x138: Primary display BitGrid (vtable 0x664144, 8bpp pixel buffer).
|
| 73 |
/// Allocated as 0x4C bytes, initialized with BitGrid::init(8, 0x100, 0x1E0).
|
| 74 |
-
pub display_bitgrid: *mut
|
| 75 |
/// 0x13C-0x37F: Sprite/image BitGrid cache (145 pointer slots).
|
| 76 |
/// All populated entries have vtable 0x664144 (same class as `display_bitgrid`).
|
| 77 |
/// Not initialized in DDGame__Constructor β filled during gameplay with
|
| 78 |
/// weapon sprites, effect images, cursor graphics, etc.
|
| 79 |
pub sprite_cache: [*mut u8; 145],
|
| 80 |
-
/// 0x380: BitGrid pointer (vtable 0x664118, 0x2C bytes)
|
| 81 |
-
|
|
|
|
| 82 |
/// 0x384-0x467: Additional sprite/image object slots.
|
| 83 |
/// Same vtable 0x664144 as sprite_cache. ~20 entries populated at runtime.
|
| 84 |
pub sprite_cache_2: [*mut u8; 57],
|
|
|
|
| 4 |
use crate::audio::speech::SpeechSlotTable;
|
| 5 |
use crate::display::dd_display::DDDisplay;
|
| 6 |
use crate::display::palette::Palette;
|
| 7 |
+
use crate::display::{CollisionBitGrid, DisplayBitGrid};
|
| 8 |
use crate::engine::game_info::GameInfo;
|
| 9 |
use crate::engine::{
|
| 10 |
CoordEntry, CoordList, RenderEntry, SoundQueueEntry, TeamArenaState, TeamIndexMap,
|
|
|
|
| 71 |
pub arrow_gfxdirs: [*mut u8; 32],
|
| 72 |
/// 0x138: Primary display BitGrid (vtable 0x664144, 8bpp pixel buffer).
|
| 73 |
/// Allocated as 0x4C bytes, initialized with BitGrid::init(8, 0x100, 0x1E0).
|
| 74 |
+
pub display_bitgrid: *mut DisplayBitGrid,
|
| 75 |
/// 0x13C-0x37F: Sprite/image BitGrid cache (145 pointer slots).
|
| 76 |
/// All populated entries have vtable 0x664144 (same class as `display_bitgrid`).
|
| 77 |
/// Not initialized in DDGame__Constructor β filled during gameplay with
|
| 78 |
/// weapon sprites, effect images, cursor graphics, etc.
|
| 79 |
pub sprite_cache: [*mut u8; 145],
|
| 80 |
+
/// 0x380: Collision BitGrid pointer (vtable 0x664118, 0x2C bytes).
|
| 81 |
+
/// Used for terrain collision/spatial queries.
|
| 82 |
+
pub collision_grid: *mut CollisionBitGrid,
|
| 83 |
/// 0x384-0x467: Additional sprite/image object slots.
|
| 84 |
/// Same vtable 0x664144 as sprite_cache. ~20 entries populated at runtime.
|
| 85 |
pub sprite_cache_2: [*mut u8; 57],
|
|
@@ -12,7 +12,7 @@ use crate::address::va;
|
|
| 12 |
use crate::audio::active_sound::ActiveSoundTable;
|
| 13 |
use crate::audio::dssound::DSSound;
|
| 14 |
use crate::audio::music::Music;
|
| 15 |
-
use crate::display::bitgrid::BitGrid;
|
| 16 |
use crate::display::dd_display::DDDisplay;
|
| 17 |
use crate::display::gradient::compute_complex_gradient;
|
| 18 |
use crate::display::palette::Palette;
|
|
@@ -705,18 +705,11 @@ unsafe fn init_graphics_and_resources(
|
|
| 705 |
}
|
| 706 |
};
|
| 707 |
|
| 708 |
-
// ββ BitGrid at DDGame+0x380 ββ
|
| 709 |
{
|
| 710 |
-
|
| 711 |
-
|
| 712 |
-
|
| 713 |
-
if !bit_grid.is_null() {
|
| 714 |
-
let width = (*ddgame).level_width;
|
| 715 |
-
let height = (*ddgame).level_height;
|
| 716 |
-
BitGrid::init(bit_grid as *mut BitGrid, 1, width, height);
|
| 717 |
-
(*bit_grid).vtable = rb(va::BIT_GRID_VARIANT_VTABLE);
|
| 718 |
-
}
|
| 719 |
-
(*ddgame).bit_grid = bit_grid;
|
| 720 |
}
|
| 721 |
|
| 722 |
// ββ 8Γ SpriteRegion at DDGame+0x46C..0x488 ββ
|
|
@@ -844,16 +837,7 @@ unsafe fn init_graphics_and_resources(
|
|
| 844 |
}
|
| 845 |
|
| 846 |
// ββ Display BitGrid at DDGame+0x138 ββ
|
| 847 |
-
|
| 848 |
-
use crate::wa_alloc::wa_malloc_struct_zeroed;
|
| 849 |
-
|
| 850 |
-
let grid = wa_malloc_struct_zeroed::<BitGrid>();
|
| 851 |
-
if !grid.is_null() {
|
| 852 |
-
BitGrid::init(grid, 8, 0x100, 0x1E0);
|
| 853 |
-
*(grid as *mut u32) = rb(va::BIT_GRID_DISPLAY_VTABLE);
|
| 854 |
-
}
|
| 855 |
-
(*ddgame).display_bitgrid = grid as *mut BitGrid;
|
| 856 |
-
}
|
| 857 |
|
| 858 |
// ββ CoordList at DDGame+0x50C (capacity 600, 0x12C0 buffer) ββ
|
| 859 |
{
|
|
@@ -1025,9 +1009,11 @@ unsafe fn init_graphics_and_resources(
|
|
| 1025 |
// ββ Gradient image stub (DDGame+0x30) ββ
|
| 1026 |
// Minimal stub: [6]=0 (zero-width) so CTaskLand skips the gradient column loop.
|
| 1027 |
if (*ddgame).gradient_image.is_null() {
|
| 1028 |
-
|
|
|
|
|
|
|
| 1029 |
if !obj.is_null() {
|
| 1030 |
-
(*obj).vtable = rb(va::
|
| 1031 |
// height = 0 β CTaskLand skips the gradient column loop
|
| 1032 |
(*ddgame).gradient_image = obj as *mut u8;
|
| 1033 |
}
|
|
|
|
| 12 |
use crate::audio::active_sound::ActiveSoundTable;
|
| 13 |
use crate::audio::dssound::DSSound;
|
| 14 |
use crate::audio::music::Music;
|
| 15 |
+
use crate::display::bitgrid::{BitGrid, BitGridBaseVtable, CollisionBitGrid, DisplayBitGrid};
|
| 16 |
use crate::display::dd_display::DDDisplay;
|
| 17 |
use crate::display::gradient::compute_complex_gradient;
|
| 18 |
use crate::display::palette::Palette;
|
|
|
|
| 705 |
}
|
| 706 |
};
|
| 707 |
|
| 708 |
+
// ββ Collision BitGrid at DDGame+0x380 ββ
|
| 709 |
{
|
| 710 |
+
let width = (*ddgame).level_width;
|
| 711 |
+
let height = (*ddgame).level_height;
|
| 712 |
+
(*ddgame).collision_grid = CollisionBitGrid::alloc(1, width, height);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 713 |
}
|
| 714 |
|
| 715 |
// ββ 8Γ SpriteRegion at DDGame+0x46C..0x488 ββ
|
|
|
|
| 837 |
}
|
| 838 |
|
| 839 |
// ββ Display BitGrid at DDGame+0x138 ββ
|
| 840 |
+
(*ddgame).display_bitgrid = DisplayBitGrid::alloc(8, 0x100, 0x1E0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 841 |
|
| 842 |
// ββ CoordList at DDGame+0x50C (capacity 600, 0x12C0 buffer) ββ
|
| 843 |
{
|
|
|
|
| 1009 |
// ββ Gradient image stub (DDGame+0x30) ββ
|
| 1010 |
// Minimal stub: [6]=0 (zero-width) so CTaskLand skips the gradient column loop.
|
| 1011 |
if (*ddgame).gradient_image.is_null() {
|
| 1012 |
+
use crate::wa_alloc::wa_malloc_struct_zeroed;
|
| 1013 |
+
|
| 1014 |
+
let obj = wa_malloc_struct_zeroed::<BitGrid>();
|
| 1015 |
if !obj.is_null() {
|
| 1016 |
+
(*obj).vtable = rb(va::BIT_GRID_BASE_VTABLE) as *const BitGridBaseVtable;
|
| 1017 |
// height = 0 β CTaskLand skips the gradient column loop
|
| 1018 |
(*ddgame).gradient_image = obj as *mut u8;
|
| 1019 |
}
|