initial arhitectural overhaul
Signed-off-by: Sienna Meridian Satterwhite <sienna@r3t.io>
This commit is contained in:
103
crates/libmarathon/src/platform/ios/pencil_bridge.rs
Normal file
103
crates/libmarathon/src/platform/ios/pencil_bridge.rs
Normal file
@@ -0,0 +1,103 @@
|
||||
//! Apple Pencil input bridge for iOS
|
||||
//!
|
||||
//! This module captures raw Apple Pencil input via Swift/UIKit and converts
|
||||
//! it to engine-agnostic InputEvents.
|
||||
|
||||
use crate::engine::input_events::{InputEvent, TouchPhase};
|
||||
use glam::Vec2;
|
||||
use std::sync::Mutex;
|
||||
|
||||
/// Raw pencil point data from Swift UITouch
|
||||
///
|
||||
/// This matches the C struct defined in PencilBridge.h
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
#[repr(C)] // Use C memory layout so Swift can interop
|
||||
pub struct RawPencilPoint {
|
||||
/// Screen X coordinate in points (not pixels)
|
||||
pub x: f32,
|
||||
/// Screen Y coordinate in points (not pixels)
|
||||
pub y: f32,
|
||||
/// Force/pressure (0.0 - 4.0 on Apple Pencil)
|
||||
pub force: f32,
|
||||
/// Altitude angle in radians (0 = flat, π/2 = perpendicular)
|
||||
pub altitude: f32,
|
||||
/// Azimuth angle in radians (rotation around vertical)
|
||||
pub azimuth: f32,
|
||||
/// iOS timestamp (seconds since system boot)
|
||||
pub timestamp: f64,
|
||||
/// Touch phase: 0=began, 1=moved, 2=ended
|
||||
pub phase: u8,
|
||||
}
|
||||
|
||||
/// Thread-safe buffer for pencil points
|
||||
///
|
||||
/// Swift's main thread pushes points here via C FFI.
|
||||
/// Bevy's Update schedule drains them each frame.
|
||||
static BUFFER: Mutex<Vec<RawPencilPoint>> = Mutex::new(Vec::new());
|
||||
|
||||
/// FFI function called from Swift when a pencil point is received
|
||||
///
|
||||
/// This is exposed as a C function so Swift can call it.
|
||||
/// The `#[no_mangle]` prevents Rust from changing the function name.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn pencil_point_received(point: RawPencilPoint) {
|
||||
if let Ok(mut buf) = BUFFER.lock() {
|
||||
buf.push(point);
|
||||
}
|
||||
}
|
||||
|
||||
/// Drain all buffered pencil points and convert to InputEvents
|
||||
///
|
||||
/// Call this from your Bevy Update system to consume input.
|
||||
pub fn drain_as_input_events() -> Vec<InputEvent> {
|
||||
BUFFER
|
||||
.lock()
|
||||
.ok()
|
||||
.map(|mut b| {
|
||||
std::mem::take(&mut *b)
|
||||
.into_iter()
|
||||
.map(raw_to_input_event)
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Drain raw pencil points without conversion
|
||||
///
|
||||
/// Useful for debugging or custom processing.
|
||||
pub fn drain_raw() -> Vec<RawPencilPoint> {
|
||||
BUFFER
|
||||
.lock()
|
||||
.ok()
|
||||
.map(|mut b| std::mem::take(&mut *b))
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Convert a raw pencil point to an engine InputEvent
|
||||
fn raw_to_input_event(p: RawPencilPoint) -> InputEvent {
|
||||
InputEvent::Stylus {
|
||||
pos: Vec2::new(p.x, p.y),
|
||||
pressure: p.force,
|
||||
tilt: Vec2::new(p.altitude, p.azimuth),
|
||||
phase: match p.phase {
|
||||
0 => TouchPhase::Started,
|
||||
1 => TouchPhase::Moved,
|
||||
2 => TouchPhase::Ended,
|
||||
_ => TouchPhase::Cancelled,
|
||||
},
|
||||
timestamp: p.timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
/// Attach the pencil capture system to a UIView
|
||||
///
|
||||
/// This is only available on iOS. On other platforms, it's a no-op.
|
||||
#[cfg(target_os = "ios")]
|
||||
extern "C" {
|
||||
pub fn swift_attach_pencil_capture(view: *mut std::ffi::c_void);
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "ios"))]
|
||||
pub unsafe fn swift_attach_pencil_capture(_: *mut std::ffi::c_void) {
|
||||
// No-op on non-iOS platforms
|
||||
}
|
||||
Reference in New Issue
Block a user