1#[cfg(feature = "bindings")]
4pub mod bindings;
5#[cfg(feature = "global-state")]
6pub mod global_state;
7
8pub mod camera_controller;
9use super::*;
10
11#[derive(Default)]
12pub struct Modifiers {
13 pub shift: bool,
14}
15
16#[derive(Default)]
17pub struct Pointer {
18 pub primary_down: bool,
19 pub secondary_down: bool,
20 pub interact_pos: Option<Vector2>,
21 pub modifiers: Modifiers,
22}
23
24#[derive(Default)]
25pub struct Input {
26 pub pointer: Pointer,
27 pub scroll_delta: Vector2,
28 pub screen_rect: Vector4,
29}
30
31pub struct Ctx {
39 pub focused: bool,
40 pub input: Input,
41 pub should_stop: bool,
42}
43
44impl Default for Ctx {
45 fn default() -> Self {
46 Self {
47 focused: true,
48 input: Default::default(),
49 should_stop: false,
50 }
51 }
52}
53
54impl Ctx {
55 pub fn new_frame(&mut self, x: u16, y: u16, w: u16, h: u16) {
57 self.input.pointer.modifiers = Default::default();
58 self.input.scroll_delta = Vector2::default();
59 self.input.screen_rect = Vector4::new(x as f32, y as f32, w as f32, h as f32);
60 }
61}
62
63#[cfg(feature = "crossterm")]
64use crossterm::event::{
65 Event, KeyCode, KeyEvent, KeyModifiers, MouseButton, MouseEvent, MouseEventKind,
66};
67
68#[cfg(feature = "crossterm")]
69impl Ctx {
70 pub fn event(&mut self, e: Event) {
72 match e {
73 Event::FocusGained => self.focused = true,
74 Event::FocusLost => self.focused = false,
75 Event::Key(KeyEvent {
76 code, modifiers, ..
77 }) => {
78 if code == KeyCode::Char('c') && modifiers.contains(KeyModifiers::CONTROL) {
79 self.should_stop = true;
80 }
81 }
82 Event::Mouse(MouseEvent {
83 kind,
84 column,
85 row,
86 modifiers,
87 ..
88 }) => {
89 self.input.pointer.modifiers.shift = modifiers.contains(KeyModifiers::SHIFT);
90 self.input.pointer.interact_pos = Some(Vector2::new(column as f32, row as f32));
91 match kind {
92 MouseEventKind::Down(b) => match b {
93 MouseButton::Left => self.input.pointer.primary_down = true,
94 MouseButton::Right => self.input.pointer.secondary_down = true,
95 _ => (),
96 },
97 MouseEventKind::Up(b) => {
98 self.input.pointer.interact_pos = None;
99 match b {
100 MouseButton::Left => self.input.pointer.primary_down = false,
101 MouseButton::Right => self.input.pointer.secondary_down = false,
102 _ => (),
103 }
104 }
105 MouseEventKind::Drag(b) => match b {
106 MouseButton::Left => self.input.pointer.primary_down = true,
107 MouseButton::Right => self.input.pointer.secondary_down = true,
108 _ => (),
109 },
110 MouseEventKind::ScrollUp => {
111 self.input.scroll_delta.y += 1.0;
112 }
113 MouseEventKind::ScrollDown => {
114 self.input.scroll_delta.y -= 1.0;
115 }
116 MouseEventKind::ScrollLeft => {
117 self.input.scroll_delta.x -= 1.0;
118 }
119 MouseEventKind::ScrollRight => {
120 self.input.scroll_delta.x += 1.0;
121 }
122 _ => (),
123 }
124 }
125 _ => (),
126 }
127 }
128}
129
130pub fn create_transform(
131 position: na::Vector3<f32>,
132 rotation: na::UnitQuaternion<f32>,
133 scale: na::Vector3<f32>,
134) -> na::Transform3<f32> {
135 let translation = na::Translation3::from(position).to_homogeneous();
137
138 let rotation_matrix = rotation.to_homogeneous();
140
141 let scale_matrix = na::Matrix4::new_nonuniform_scaling(&scale);
143
144 let mat = translation * rotation_matrix * scale_matrix; na::Transform3::from_matrix_unchecked(mat)
148}
149
150pub fn ortho_proj(
151 left: f32,
152 right: f32,
153 bottom: f32,
154 top: f32,
155 znear: f32,
156 zfar: f32,
157) -> na::Orthographic3<f32> {
158 let m = *na::Orthographic3::new(left, right, bottom, top, znear, zfar).as_matrix();
159
160 #[rustfmt::skip]
161 pub const OPENGL_TO_AR_MATRIX: na::Matrix4<f32> = na::matrix![
162 1.0, 0.0, 0.0, 0.0;
163 0.0, 1.0, 0.0, 0.0;
164 0.0, 0.0, 0.5, 0.5;
165 0.0, 0.0, 0.0, 1.0
166 ];
167
168 na::Orthographic3::from_matrix_unchecked(OPENGL_TO_AR_MATRIX * m)
169}