1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8pub struct EntityId(pub usize);
9
10impl std::fmt::Display for EntityId {
11 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12 write!(f, "Entity({})", self.0)
13 }
14}
15
16#[derive(Debug, Clone)]
18pub struct HitInfo {
19 pub entity_id: EntityId,
21 pub point: Vector3,
23 pub normal: Vector3,
25 pub uv: Option<Vector2>,
27 pub distance: f32,
29 pub face_index: Option<usize>,
31 pub instance_id: Option<usize>,
33}
34
35#[derive(Debug, Clone, Copy, Default, PartialEq)]
37pub struct Vector2 {
38 pub x: f32,
39 pub y: f32,
40}
41
42impl Vector2 {
43 pub fn new(x: f32, y: f32) -> Self {
44 Self { x, y }
45 }
46}
47
48#[derive(Debug, Clone, Copy, Default, PartialEq)]
50pub struct Vector3 {
51 pub x: f32,
52 pub y: f32,
53 pub z: f32,
54}
55
56impl Vector3 {
57 pub const ZERO: Self = Self {
58 x: 0.0,
59 y: 0.0,
60 z: 0.0,
61 };
62 pub const UP: Self = Self {
63 x: 0.0,
64 y: 1.0,
65 z: 0.0,
66 };
67 pub const RIGHT: Self = Self {
68 x: 1.0,
69 y: 0.0,
70 z: 0.0,
71 };
72 pub const FORWARD: Self = Self {
73 x: 0.0,
74 y: 0.0,
75 z: 1.0,
76 };
77
78 pub fn new(x: f32, y: f32, z: f32) -> Self {
79 Self { x, y, z }
80 }
81
82 pub fn length(&self) -> f32 {
83 (self.x * self.x + self.y * self.y + self.z * self.z).sqrt()
84 }
85
86 pub fn normalize(&self) -> Self {
87 let len = self.length();
88 if len > 0.0 {
89 Self {
90 x: self.x / len,
91 y: self.y / len,
92 z: self.z / len,
93 }
94 } else {
95 *self
96 }
97 }
98
99 pub fn distance(&self, other: &Self) -> f32 {
100 (*self - *other).length()
101 }
102}
103
104impl std::ops::Add for Vector3 {
105 type Output = Self;
106 fn add(self, rhs: Self) -> Self::Output {
107 Self::new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
108 }
109}
110
111impl std::ops::Sub for Vector3 {
112 type Output = Self;
113 fn sub(self, rhs: Self) -> Self::Output {
114 Self::new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
115 }
116}
117
118impl std::ops::Mul<f32> for Vector3 {
119 type Output = Self;
120 fn mul(self, rhs: f32) -> Self::Output {
121 Self::new(self.x * rhs, self.y * rhs, self.z * rhs)
122 }
123}
124
125#[derive(Debug, Clone, Copy, PartialEq, Eq)]
127pub enum MouseButton {
128 Left,
129 Middle,
130 Right,
131 Back,
132 Forward,
133}
134
135#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
137pub enum CursorStyle {
138 #[default]
139 Default,
140 Pointer,
141 Grab,
142 Grabbing,
143 Crosshair,
144 Move,
145 Text,
146 Wait,
147 Help,
148 None,
149}
150
151impl CursorStyle {
152 pub fn as_css(&self) -> &'static str {
153 match self {
154 CursorStyle::Default => "default",
155 CursorStyle::Pointer => "pointer",
156 CursorStyle::Grab => "grab",
157 CursorStyle::Grabbing => "grabbing",
158 CursorStyle::Crosshair => "crosshair",
159 CursorStyle::Move => "move",
160 CursorStyle::Text => "text",
161 CursorStyle::Wait => "wait",
162 CursorStyle::Help => "help",
163 CursorStyle::None => "none",
164 }
165 }
166}
167
168#[derive(Debug, Clone, Copy, PartialEq)]
170pub struct RaycastConfig {
171 pub enabled: bool,
173 pub recursive: bool,
175 pub max_distance: f32,
177 pub layer_mask: Option<u32>,
179}
180
181impl Default for RaycastConfig {
182 fn default() -> Self {
183 Self {
184 enabled: true,
185 recursive: true,
186 max_distance: 1000.0,
187 layer_mask: None,
188 }
189 }
190}
191
192#[derive(Debug, Clone)]
194pub struct PointerEvent {
195 pub hit: Option<HitInfo>,
197 pub screen_position: Vector2,
199 pub ndc_position: Vector2,
201 pub button: Option<MouseButton>,
203 pub shift_key: bool,
205 pub ctrl_key: bool,
207 pub alt_key: bool,
209}
210
211impl PointerEvent {
212 pub fn set_cursor(&self, _style: CursorStyle) {
215 }
218}
219
220#[derive(Debug, Clone)]
222pub struct PointerDragEvent {
223 pub hit: Option<HitInfo>,
225 pub start_hit: Option<HitInfo>,
227 pub screen_position: Vector2,
229 pub start_screen_position: Vector2,
231 pub world_position: Vector3,
233 pub start_world_position: Vector3,
235 pub delta: Vector2,
237 pub total_delta: Vector2,
239 pub button: MouseButton,
241}
242
243#[derive(Debug, Clone, Copy, PartialEq)]
245pub enum GestureEvent {
246 Pinch { scale: f32, center: Vector2 },
248 Rotate { angle: f32, center: Vector2 },
250 Pan { delta: Vector2 },
252}
253
254#[derive(Debug, Clone)]
256pub struct Raycaster {
257 pub origin: Vector3,
258 pub direction: Vector3,
259 pub near: f32,
260 pub far: f32,
261}
262
263impl Raycaster {
264 pub fn new(origin: Vector3, direction: Vector3) -> Self {
265 Self {
266 origin,
267 direction: direction.normalize(),
268 near: 0.0,
269 far: 1000.0,
270 }
271 }
272
273 pub fn from_camera(camera: &Camera, _screen_pos: Vector2) -> Self {
275 Self::new(camera.position, Vector3::FORWARD)
278 }
279
280 pub fn at(&self, distance: f32) -> Vector3 {
282 self.origin + self.direction * distance
283 }
284}
285
286#[derive(Debug, Clone)]
288pub struct Camera {
289 pub position: Vector3,
290 pub target: Vector3,
291 pub up: Vector3,
292 pub fov: f32,
293 pub aspect: f32,
294 pub near: f32,
295 pub far: f32,
296}
297
298impl Camera {
299 pub fn new(position: Vector3, target: Vector3) -> Self {
300 Self {
301 position,
302 target,
303 up: Vector3::UP,
304 fov: 75.0_f32.to_radians(),
305 aspect: 1.0,
306 near: 0.1,
307 far: 1000.0,
308 }
309 }
310}
311
312pub type PointerEventHandler = Box<dyn Fn(PointerEvent)>;
314pub type PointerDragEventHandler = Box<dyn Fn(PointerDragEvent)>;
315pub type GestureEventHandler = Box<dyn Fn(GestureEvent)>;
316
317#[derive(Debug, Clone, Default)]
319pub struct InputState {
320 pub pointer_position: Vector2,
322 pub pointer_down: bool,
324 pub cursor_style: CursorStyle,
326 pub keys_pressed: Vec<String>,
328 pub mouse_delta: Vector2,
330}
331
332impl InputState {
333 pub fn is_key_pressed(&self, key: &str) -> bool {
334 self.keys_pressed
335 .iter()
336 .any(|k| k.eq_ignore_ascii_case(key))
337 }
338}
339
340#[cfg(test)]
341mod tests {
342 use super::*;
343
344 #[test]
345 fn test_vector3_operations() {
346 let a = Vector3::new(1.0, 2.0, 3.0);
347 let b = Vector3::new(4.0, 5.0, 6.0);
348
349 let sum = a + b;
350 assert_eq!(sum.x, 5.0);
351 assert_eq!(sum.y, 7.0);
352 assert_eq!(sum.z, 9.0);
353
354 let diff = b - a;
355 assert_eq!(diff.x, 3.0);
356 assert_eq!(diff.y, 3.0);
357 assert_eq!(diff.z, 3.0);
358
359 let scaled = a * 2.0;
360 assert_eq!(scaled.x, 2.0);
361 assert_eq!(scaled.y, 4.0);
362 assert_eq!(scaled.z, 6.0);
363 }
364
365 #[test]
366 fn test_vector3_distance() {
367 let a = Vector3::new(0.0, 0.0, 0.0);
368 let b = Vector3::new(3.0, 4.0, 0.0);
369
370 assert_eq!(a.distance(&b), 5.0);
371 }
372
373 #[test]
374 fn test_entity_id_display() {
375 let id = EntityId(42);
376 assert_eq!(format!("{}", id), "Entity(42)");
377 }
378}