paavohtl Claude Opus 4.6 (1M context) commited on
Commit
bdd7b6b
·
1 Parent(s): 3cf736c

feat: port DDDisplay draw_crosshair, draw_outlined_pixel, acquire_render_lock

Browse files

Port the render lock acquisition helper (0x56A370) which queries
DDDisplayWrapper for framebuffer dimensions and surface lock, then
populates layer_0's BitGrid fields. Also port draw_outlined_pixel
(slot 17) and draw_crosshair (slot 16) which draw pixels through
layer_0's put_pixel_clipped vtable method.

Fix lock_surface_read/write vtable signatures to use *mut u32 output
pointers instead of u32.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

crates/openwa-core/src/display/dd_display.rs CHANGED
@@ -275,6 +275,7 @@ bind_DDDisplayVtable!(DDDisplay, vtable);
275
  // Ported DDDisplay vtable methods
276
  // =========================================================================
277
 
 
278
  use super::gfx::DisplayGfx;
279
 
280
  /// Port of DDDisplay::GetDimensions (vtable slot 1, 0x56A460).
@@ -427,6 +428,75 @@ unsafe fn flush_render_lock(gfx: *mut DisplayGfx) {
427
  }
428
  }
429
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
430
  /// Port of DDDisplay::FillRect (vtable slot 18, 0x56B810).
431
  ///
432
  /// Fills a rectangle with a solid color. Pixel-integer coordinates are
@@ -491,3 +561,82 @@ pub unsafe extern "thiscall" fn fill_rect(
491
  color,
492
  );
493
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
275
  // Ported DDDisplay vtable methods
276
  // =========================================================================
277
 
278
+ use super::bitgrid::DisplayBitGrid;
279
  use super::gfx::DisplayGfx;
280
 
281
  /// Port of DDDisplay::GetDimensions (vtable slot 1, 0x56A460).
 
428
  }
429
  }
430
 
431
+ /// Port of the render-lock acquire helper at 0x56A370.
432
+ ///
433
+ /// If the render lock is NOT held, queries DDDisplayWrapper for framebuffer
434
+ /// dimensions (slot 3) and locks the surface for writing (slot 17), then
435
+ /// populates layer_0's BitGrid fields (data, stride, dimensions) from the
436
+ /// locked surface and copies DisplayBase's clip rect into layer_0.
437
+ ///
438
+ /// Original uses ESI = this (usercall).
439
+ ///
440
+ /// # Safety
441
+ /// `gfx` must be a valid `*mut DisplayGfx` with `layer_0` initialized.
442
+ /// `g_DDDisplayWrapper` must be initialized.
443
+ unsafe fn acquire_render_lock(gfx: *mut DisplayGfx) {
444
+ if (*gfx).render_lock != 0 {
445
+ return; // already locked
446
+ }
447
+
448
+ let wrapper = *(rb(va::G_DD_DISPLAY_WRAPPER) as *const *mut DDDisplayWrapper);
449
+ let mut buf = FastcallResult::default();
450
+
451
+ // Get framebuffer dimensions (slot 3).
452
+ // The wrapper writes width and height to the output buffer.
453
+ let mut dims: [u32; 2] = [0; 2];
454
+ DDDisplayWrapper::get_framebuffer_dims_raw(wrapper, &mut buf, dims.as_mut_ptr());
455
+ let fb_width = dims[0];
456
+ let fb_height = dims[1];
457
+
458
+ // Lock surface for writing (slot 17).
459
+ // The wrapper writes framebuffer pointer and stride through the params.
460
+ let mut data_ptr: u32 = 0;
461
+ let mut stride: u32 = 0;
462
+ DDDisplayWrapper::lock_surface_write_raw(wrapper, &mut buf, &mut data_ptr, &mut stride);
463
+
464
+ // Populate layer_0 from the locked surface
465
+ let layer = (*gfx).layer_0;
466
+ if (*layer).external_buffer != 0 {
467
+ (*layer).width = fb_width;
468
+ (*layer).height = fb_height;
469
+ (*layer).data = data_ptr as *mut u8;
470
+ (*layer).row_stride = stride;
471
+ (*layer).clip_left = 0;
472
+ (*layer).clip_top = 0;
473
+ (*layer).clip_right = fb_width;
474
+ (*layer).clip_bottom = fb_height;
475
+ }
476
+
477
+ // Copy DisplayBase clip rect to layer_0, clamped to layer dimensions
478
+ let base = &(*gfx).base;
479
+ (*layer).clip_left = base.clip_x1 as u32;
480
+ (*layer).clip_top = base.clip_y1 as u32;
481
+ (*layer).clip_right = base.clip_x2 as u32;
482
+ (*layer).clip_bottom = base.clip_y2 as u32;
483
+
484
+ if base.clip_x1 < 0 {
485
+ (*layer).clip_left = 0;
486
+ }
487
+ if base.clip_y1 < 0 {
488
+ (*layer).clip_top = 0;
489
+ }
490
+ if base.clip_x2 > (*layer).width as i32 {
491
+ (*layer).clip_right = (*layer).width;
492
+ }
493
+ if base.clip_y2 > (*layer).height as i32 {
494
+ (*layer).clip_bottom = (*layer).height;
495
+ }
496
+
497
+ (*gfx).render_lock = 1;
498
+ }
499
+
500
  /// Port of DDDisplay::FillRect (vtable slot 18, 0x56B810).
501
  ///
502
  /// Fills a rectangle with a solid color. Pixel-integer coordinates are
 
561
  color,
562
  );
563
  }
564
+
565
+ /// Port of DDDisplay::DrawOutlinedPixel (vtable slot 17, 0x56BFD0).
566
+ ///
567
+ /// Draws a center pixel in `color_fg` with 4 cardinal neighbor pixels in
568
+ /// `color_bg` (if `color_bg != 0`). Pixel-integer coordinates with camera offset.
569
+ ///
570
+ /// # Safety
571
+ /// `this` must be a valid `*mut DDDisplay` (actually a `*mut DisplayGfx`).
572
+ pub unsafe extern "thiscall" fn draw_outlined_pixel(
573
+ this: *mut DDDisplay,
574
+ x: i32,
575
+ y: i32,
576
+ color_fg: u32,
577
+ color_bg: i32,
578
+ ) {
579
+ let gfx = this as *mut DisplayGfx;
580
+ let cx = x + (*gfx).camera_x;
581
+ let cy = y + (*gfx).camera_y;
582
+
583
+ acquire_render_lock(gfx);
584
+
585
+ let layer = (*gfx).layer_0;
586
+ if color_bg != 0 {
587
+ let bg = color_bg as u8;
588
+ DisplayBitGrid::put_pixel_clipped_raw(layer, cx - 1, cy, bg);
589
+ DisplayBitGrid::put_pixel_clipped_raw(layer, cx + 1, cy, bg);
590
+ DisplayBitGrid::put_pixel_clipped_raw(layer, cx, cy - 1, bg);
591
+ DisplayBitGrid::put_pixel_clipped_raw(layer, cx, cy + 1, bg);
592
+ }
593
+ DisplayBitGrid::put_pixel_clipped_raw(layer, cx, cy, color_fg as u8);
594
+ }
595
+
596
+ /// Port of DDDisplay::DrawCrosshair (vtable slot 16, 0x56BE80).
597
+ ///
598
+ /// Draws a 2x2 foreground block at (cx, cy)–(cx+1, cy+1) with an 8-pixel
599
+ /// outline in `color_bg`. Pixel-integer coordinates with camera offset.
600
+ ///
601
+ /// ```text
602
+ /// bg bg
603
+ /// bg FG FG bg
604
+ /// bg FG FG bg
605
+ /// bg bg
606
+ /// ```
607
+ ///
608
+ /// # Safety
609
+ /// `this` must be a valid `*mut DDDisplay` (actually a `*mut DisplayGfx`).
610
+ pub unsafe extern "thiscall" fn draw_crosshair(
611
+ this: *mut DDDisplay,
612
+ x: i32,
613
+ y: i32,
614
+ color_fg: u32,
615
+ color_bg: u32,
616
+ ) {
617
+ let gfx = this as *mut DisplayGfx;
618
+ let cx = x + (*gfx).camera_x;
619
+ let cy = y + (*gfx).camera_y;
620
+
621
+ acquire_render_lock(gfx);
622
+
623
+ let layer = (*gfx).layer_0;
624
+ let bg = color_bg as u8;
625
+ let fg = color_fg as u8;
626
+
627
+ // Background outline (8 pixels)
628
+ DisplayBitGrid::put_pixel_clipped_raw(layer, cx, cy - 1, bg);
629
+ DisplayBitGrid::put_pixel_clipped_raw(layer, cx + 1, cy - 1, bg);
630
+ DisplayBitGrid::put_pixel_clipped_raw(layer, cx - 1, cy, bg);
631
+ DisplayBitGrid::put_pixel_clipped_raw(layer, cx + 2, cy, bg);
632
+ DisplayBitGrid::put_pixel_clipped_raw(layer, cx - 1, cy + 1, bg);
633
+ DisplayBitGrid::put_pixel_clipped_raw(layer, cx + 2, cy + 1, bg);
634
+ DisplayBitGrid::put_pixel_clipped_raw(layer, cx, cy + 2, bg);
635
+ DisplayBitGrid::put_pixel_clipped_raw(layer, cx + 1, cy + 2, bg);
636
+
637
+ // Foreground 2x2 block (4 pixels)
638
+ DisplayBitGrid::put_pixel_clipped_raw(layer, cx, cy, fg);
639
+ DisplayBitGrid::put_pixel_clipped_raw(layer, cx + 1, cy, fg);
640
+ DisplayBitGrid::put_pixel_clipped_raw(layer, cx, cy + 1, fg);
641
+ DisplayBitGrid::put_pixel_clipped_raw(layer, cx + 1, cy + 1, fg);
642
+ }
crates/openwa-core/src/display/display_wrapper.rs CHANGED
@@ -160,13 +160,15 @@ pub struct DDDisplayWrapperVtable {
160
  this: *mut DDDisplayWrapper,
161
  result: *mut FastcallResult,
162
  ) -> *mut FastcallResult,
163
- /// lock surface for reading — returns framebuffer ptr + width (0x5A2690, RET 0x8)
 
 
164
  #[slot(15)]
165
  pub lock_surface_read: unsafe extern "fastcall" fn(
166
  this: *mut DDDisplayWrapper,
167
  result: *mut FastcallResult,
168
- p2: u32,
169
- p3: u32,
170
  ) -> *mut FastcallResult,
171
  /// unlock surface (0x5A2C10, RET 0x4)
172
  ///
@@ -178,12 +180,14 @@ pub struct DDDisplayWrapperVtable {
178
  p2: u32,
179
  ) -> *mut FastcallResult,
180
  /// lock surface for writing (0x5A2690 — same fn as slot 15, RET 0x8)
 
 
181
  #[slot(17)]
182
  pub lock_surface_write: unsafe extern "fastcall" fn(
183
  this: *mut DDDisplayWrapper,
184
  result: *mut FastcallResult,
185
- p2: u32,
186
- p3: u32,
187
  ) -> *mut FastcallResult,
188
  /// unlock surface after writing (0x5A2C10 — same fn as slot 16, RET 0x4)
189
  #[slot(18)]
 
160
  this: *mut DDDisplayWrapper,
161
  result: *mut FastcallResult,
162
  ) -> *mut FastcallResult,
163
+ /// lock surface for reading (0x5A2690, RET 0x8)
164
+ ///
165
+ /// Writes framebuffer pointer to `*out_data` and stride to `*out_stride`.
166
  #[slot(15)]
167
  pub lock_surface_read: unsafe extern "fastcall" fn(
168
  this: *mut DDDisplayWrapper,
169
  result: *mut FastcallResult,
170
+ out_data: *mut u32,
171
+ out_stride: *mut u32,
172
  ) -> *mut FastcallResult,
173
  /// unlock surface (0x5A2C10, RET 0x4)
174
  ///
 
180
  p2: u32,
181
  ) -> *mut FastcallResult,
182
  /// lock surface for writing (0x5A2690 — same fn as slot 15, RET 0x8)
183
+ ///
184
+ /// Writes framebuffer pointer to `*out_data` and stride to `*out_stride`.
185
  #[slot(17)]
186
  pub lock_surface_write: unsafe extern "fastcall" fn(
187
  this: *mut DDDisplayWrapper,
188
  result: *mut FastcallResult,
189
+ out_data: *mut u32,
190
+ out_stride: *mut u32,
191
  ) -> *mut FastcallResult,
192
  /// unlock surface after writing (0x5A2C10 — same fn as slot 16, RET 0x4)
193
  #[slot(18)]
crates/openwa-dll/src/replacements/display.rs CHANGED
@@ -81,13 +81,15 @@ pub fn install() -> Result<(), String> {
81
 
82
  // Patch DDDisplay vtable (0x66A218): replace ported methods with Rust.
83
  vtable_replace!(DDDisplayVtable, va::DD_DISPLAY_VTABLE, {
84
- get_dimensions => dd_display::get_dimensions,
85
- fill_rect => dd_display::fill_rect,
86
- flush_render => dd_display::flush_render,
87
- set_camera_offset => dd_display::set_camera_offset,
88
- set_clip_rect => dd_display::set_clip_rect,
 
 
89
  })?;
90
- let _ = log_line("[Display] DDDisplay: patched 5 methods → Rust");
91
  }
92
 
93
  Ok(())
 
81
 
82
  // Patch DDDisplay vtable (0x66A218): replace ported methods with Rust.
83
  vtable_replace!(DDDisplayVtable, va::DD_DISPLAY_VTABLE, {
84
+ get_dimensions => dd_display::get_dimensions,
85
+ draw_crosshair => dd_display::draw_crosshair,
86
+ draw_outlined_pixel => dd_display::draw_outlined_pixel,
87
+ fill_rect => dd_display::fill_rect,
88
+ flush_render => dd_display::flush_render,
89
+ set_camera_offset => dd_display::set_camera_offset,
90
+ set_clip_rect => dd_display::set_clip_rect,
91
  })?;
92
+ let _ = log_line("[Display] DDDisplay: patched 7 methods → Rust");
93
  }
94
 
95
  Ok(())