1use crate::cardinal_orcas_symbols::cardinal_orcas_symbols::get_slice;
2
3impl<'a> Stage<'a> {
4 pub fn load_symbols(&mut self, data: &[u8]) {
6 if let Ok(map) = varvara::Varvara::parse_symbols_from_bytes(data) {
7 self.dev.symbols = Some(map);
8 }
9 }
10 pub fn load_rom_with_path<P: AsRef<std::path::Path>>(&mut self, path: P) {
12 let path = path.as_ref();
13 if let Ok(data) = std::fs::read(path) {
14 let _ = self.vm.reset(&data);
15 self.dev.reset(&data);
16 self.vm.run(&mut self.dev, 0x100);
17 let out = self.dev.output(&self.vm);
18 self.size = out.size;
19 if let Some(file_name) = path.file_name() {
21 use std::ffi::OsString;
22 use std::path::PathBuf;
23 let mut sys_file = OsString::from(file_name);
24 sys_file.push(".sym");
25 let mut sys_path = PathBuf::from(path);
26 sys_path.set_file_name(sys_file);
27 #[cfg(windows)]
28 let mut sys_path_str = sys_path.to_string_lossy().to_string();
29 #[cfg(windows)]
30 {
31 sys_path_str = sys_path_str.replace("/", "\\");
32 }
33 #[cfg(not(windows))]
34 let sys_path_str = sys_path.to_string_lossy().to_string();
35 println!(
36 "[DEBUG][Stage] Attempting to load symbols from {sys_path_str}");
37 if sys_path.exists() {
38 let _ = self.dev.load_symbols_into_self(&sys_path_str);
39 println!(
40 "[DEBUG][Stage] Loaded symbols from {sys_path_str}"
41 );
42 }
43 }
44 }
45 }
46
47 pub fn handle_mouse_input(
49 &mut self,
50 input: &egui::InputState,
51 _response: &egui::Response,
52 rect: egui::Rect,
53 ) {
54 if let Some(mouse_pos) = input.pointer.hover_pos() {
55 if rect.contains(mouse_pos) {
56 let rel_x =
57 (mouse_pos.x - rect.min.x).max(0.0).min(rect.width());
58 let rel_y =
59 (mouse_pos.y - rect.min.y).max(0.0).min(rect.height());
60 let mut buttons = 0u8;
61 if input.pointer.button_down(egui::PointerButton::Primary) {
62 buttons |= 1;
63 }
64 if input.pointer.button_down(egui::PointerButton::Middle) {
65 buttons |= 2;
66 }
67 if input.pointer.button_down(egui::PointerButton::Secondary) {
68 buttons |= 4;
69 }
70 let mouse_state = varvara::MouseState {
71 pos: (rel_x, rel_y),
72 scroll: (0.0, 0.0),
73 buttons,
74 };
75 self.dev.mouse(&mut self.vm, mouse_state);
76 }
77 }
78 for event in &input.events {
80 if let egui::Event::PointerButton {
81 pos,
82 button,
83 pressed,
84 ..
85 } = event
86 {
87 if rect.contains(*pos) {
88 let rel_x = (pos.x - rect.min.x).max(0.0).min(rect.width());
89 let rel_y =
90 (pos.y - rect.min.y).max(0.0).min(rect.height());
91 let mut buttons = 0u8;
92 if *button == egui::PointerButton::Primary && *pressed {
93 buttons |= 1;
94 }
95 if *button == egui::PointerButton::Middle && *pressed {
96 buttons |= 2;
97 }
98 if *button == egui::PointerButton::Secondary && *pressed {
99 buttons |= 4;
100 }
101 let mouse_state = varvara::MouseState {
102 pos: (rel_x, rel_y),
103 scroll: (0.0, 0.0),
104 buttons,
105 };
106 self.dev.mouse(&mut self.vm, mouse_state);
107 }
108 }
109 }
110 }
111
112 pub fn handle_keyboard_input(&mut self, input: &egui::InputState) {
114 for event in &input.events {
115 if let egui::Event::Key { key, pressed, .. } = event {
116 if let Some(varvara_key) = map_egui_key_to_varvara_key(*key) {
117 println!("[DEBUG][Stage] Forwarding key: {key:?} pressed={pressed} to VM as {varvara_key:?}");
118 if *pressed {
119 self.dev.pressed(&mut self.vm, varvara_key, false);
120 } else {
121 self.dev.released(&mut self.vm, varvara_key);
122 }
123 } else {
124 println!("[DEBUG][Stage] Ignored key: {key:?}");
125 }
126 }
127 }
128 }
129
130 pub fn draw_at(&self, ui: &mut egui::Ui, rect: egui::Rect) {
132 let panel_size =
133 egui::Vec2::new(self.size.0 as f32, self.size.1 as f32)
134 * self.scale;
135 let mut mesh = egui::Mesh::with_texture(self.texture.id());
136 mesh.add_rect_with_uv(
137 egui::Rect {
138 min: rect.min,
139 max: rect.min + panel_size,
140 },
141 egui::Rect {
142 min: egui::Pos2::new(0.0, 0.0),
143 max: egui::Pos2::new(1.0, 1.0),
144 },
145 egui::Color32::WHITE,
146 );
147 ui.painter().add(egui::Shape::mesh(mesh));
148 }
149
150 pub fn handle_input(
152 &mut self,
153 input: &egui::InputState,
154 _response: &egui::Response,
155 rect: egui::Rect,
156 ) {
157 for event in &input.events {
159 if let egui::Event::Text(s) = event {
160 for c in s.chars() {
161 if c.is_ascii_graphic() || c == ' ' {
163 let byte = c as u8;
164 println!("[DEBUG][Stage] Forwarding char event: '{c}' (0x{byte:02x}) to VM (from egui::Event::Text)");
165 self.dev.pressed(
166 &mut self.vm,
167 varvara::Key::Char(byte),
168 false,
169 );
170 self.dev.char(&mut self.vm, byte);
171 } else {
172 println!("[DEBUG][Stage] Ignored char event: '{}' (0x{:02x}) (not printable)", c, c as u8);
173 }
174 }
175 }
176 }
177 use egui::Key;
179 for event in &input.events {
180 if let egui::Event::Key { key, pressed, .. } = event {
181 let is_printable = matches!(
182 key,
183 Key::A
184 | Key::B
185 | Key::C
186 | Key::D
187 | Key::E
188 | Key::F
189 | Key::G
190 | Key::H
191 | Key::I
192 | Key::J
193 | Key::K
194 | Key::L
195 | Key::M
196 | Key::N
197 | Key::O
198 | Key::P
199 | Key::Q
200 | Key::R
201 | Key::S
202 | Key::T
203 | Key::U
204 | Key::V
205 | Key::W
206 | Key::X
207 | Key::Y
208 | Key::Z
209 | Key::Num0
210 | Key::Num1
211 | Key::Num2
212 | Key::Num3
213 | Key::Num4
214 | Key::Num5
215 | Key::Num6
216 | Key::Num7
217 | Key::Num8
218 | Key::Num9
219 | Key::Space
220 | Key::Tab
221 | Key::Backtick
222 | Key::Backslash
223 | Key::Pipe
224 | Key::Comma
225 | Key::Equals
226 | Key::Plus
227 | Key::OpenBracket
228 | Key::Minus
229 | Key::Period
230 | Key::CloseBracket
231 | Key::Semicolon
232 | Key::Colon
233 | Key::Slash
234 | Key::Questionmark
235 );
236 if !is_printable {
237 if let Some(varvara_key) = map_egui_key_to_varvara_key(*key)
238 {
239 println!("[DEBUG][Stage] Forwarding non-printable key: {key:?} pressed={pressed} to VM as {varvara_key:?}");
240 if *pressed {
241 self.dev.pressed(&mut self.vm, varvara_key, false);
242 } else {
243 self.dev.released(&mut self.vm, varvara_key);
244 }
245 } else {
246 println!("[DEBUG][Stage] Ignored key: {key:?}");
247 }
248 }
249 }
250 }
251 if let Some(mouse_pos) = input.pointer.hover_pos() {
253 if rect.contains(mouse_pos) {
254 let rel_x =
255 (mouse_pos.x - rect.min.x).max(0.0).min(rect.width());
256 let rel_y =
257 (mouse_pos.y - rect.min.y).max(0.0).min(rect.height());
258 let mut buttons = 0u8;
259 if input.pointer.button_down(egui::PointerButton::Primary) {
260 buttons |= 1;
261 }
262 if input.pointer.button_down(egui::PointerButton::Middle) {
263 buttons |= 2;
264 }
265 if input.pointer.button_down(egui::PointerButton::Secondary) {
266 buttons |= 4;
267 }
268 let mouse_state = varvara::MouseState {
269 pos: (rel_x, rel_y),
270 scroll: (0.0, 0.0),
271 buttons,
272 };
273 self.dev.mouse(&mut self.vm, mouse_state);
274 }
275 }
276 for event in &input.events {
278 if let egui::Event::PointerButton {
279 pos,
280 button,
281 pressed,
282 ..
283 } = event
284 {
285 if rect.contains(*pos) {
286 let rel_x = (pos.x - rect.min.x).max(0.0).min(rect.width());
287 let rel_y =
288 (pos.y - rect.min.y).max(0.0).min(rect.height());
289 let mut buttons = 0u8;
290 if *button == egui::PointerButton::Primary && *pressed {
291 buttons |= 1;
292 }
293 if *button == egui::PointerButton::Middle && *pressed {
294 buttons |= 2;
295 }
296 if *button == egui::PointerButton::Secondary && *pressed {
297 buttons |= 4;
298 }
299 let mouse_state = varvara::MouseState {
300 pos: (rel_x, rel_y),
301 scroll: (0.0, 0.0),
302 buttons,
303 };
304 println!("[DEBUG][Stage] Forwarding pointer button: {button:?} pressed={pressed} at rel=({rel_x:.1},{rel_y:.1})");
305 self.dev.mouse(&mut self.vm, mouse_state);
306 }
307 }
308 }
309 }
310}
311
312fn map_egui_key_to_varvara_key(key: egui::Key) -> Option<varvara::Key> {
314 use egui::Key;
315 use varvara::Key as VKey;
316 Some(match key {
317 Key::ArrowUp => VKey::Up,
318 Key::ArrowDown => VKey::Down,
319 Key::ArrowLeft => VKey::Left,
320 Key::ArrowRight => VKey::Right,
321 Key::Home => VKey::Home,
322 Key::End => VKey::End,
323 Key::Tab => VKey::Char(b'\t'),
324 Key::Backspace => VKey::Char(8),
325 Key::Enter => VKey::Char(b'\n'),
326 Key::Space => VKey::Char(b' '),
327 Key::A => VKey::Char(b'a'),
328 Key::B => VKey::Char(b'b'),
329 Key::C => VKey::Char(b'c'),
330 Key::D => VKey::Char(b'd'),
331 Key::E => VKey::Char(b'e'),
332 Key::F => VKey::Char(b'f'),
333 Key::G => VKey::Char(b'g'),
334 Key::H => VKey::Char(b'h'),
335 Key::I => VKey::Char(b'i'),
336 Key::J => VKey::Char(b'j'),
337 Key::K => VKey::Char(b'k'),
338 Key::L => VKey::Char(b'l'),
339 Key::M => VKey::Char(b'm'),
340 Key::N => VKey::Char(b'n'),
341 Key::O => VKey::Char(b'o'),
342 Key::P => VKey::Char(b'p'),
343 Key::Q => VKey::Char(b'q'),
344 Key::R => VKey::Char(b'r'),
345 Key::S => VKey::Char(b's'),
346 Key::T => VKey::Char(b't'),
347 Key::U => VKey::Char(b'u'),
348 Key::V => VKey::Char(b'v'),
349 Key::W => VKey::Char(b'w'),
350 Key::X => VKey::Char(b'x'),
351 Key::Y => VKey::Char(b'y'),
352 Key::Z => VKey::Char(b'z'),
353 Key::Num0 => VKey::Char(b'0'),
354 Key::Num1 => VKey::Char(b'1'),
355 Key::Num2 => VKey::Char(b'2'),
356 Key::Num3 => VKey::Char(b'3'),
357 Key::Num4 => VKey::Char(b'4'),
358 Key::Num5 => VKey::Char(b'5'),
359 Key::Num6 => VKey::Char(b'6'),
360 Key::Num7 => VKey::Char(b'7'),
361 Key::Num8 => VKey::Char(b'8'),
362 Key::Num9 => VKey::Char(b'9'),
363 _ => return None,
364 })
365}
366use eframe::egui;
367use std::sync::mpsc;
368use uxn::Uxn;
369use varvara::Varvara;
370
371#[derive(Debug)]
372pub enum Event {
373 LoadRom(Vec<u8>),
374 SetMuted(bool),
375 Console(u8),
376}
377
378pub struct Stage<'a> {
379 pub vm: Uxn<'a>,
380 pub dev: Varvara,
381 pub scale: f32,
382 pub size: (u16, u16),
383 pub next_frame: f64,
384 pub scroll: (f32, f32),
385 pub cursor_pos: Option<(f32, f32)>,
386 pub texture: egui::TextureHandle,
387 pub event_rx: mpsc::Receiver<Event>,
388 pub resized: Option<Box<dyn FnMut(u16, u16)>>,
389}
390
391impl<'a> Stage<'a> {
392 pub fn new(
393 vm: Uxn<'a>,
394 dev: Varvara,
395 size: (u16, u16),
396 scale: f32,
397 event_rx: mpsc::Receiver<Event>,
398 ctx: &egui::Context,
399 texture_name: String,
400 ) -> Self {
401 let image = egui::ColorImage::new(
402 [usize::from(size.0), usize::from(size.1)],
403 vec![egui::Color32::BLACK; (size.0 as usize) * (size.1 as usize)],
404 );
405 let texture = ctx.load_texture(
406 &texture_name,
407 image,
408 egui::TextureOptions::NEAREST,
409 );
410 Stage {
411 vm,
412 dev,
413 scale,
414 size,
415 next_frame: 0.0,
416 event_rx,
417 resized: None,
418 scroll: (0.0, 0.0),
419 cursor_pos: None,
420 texture,
421 }
422 }
423
424 pub fn get_bang(&self) {
425 get_slice(self.vm.ram,"*");
426 }
427
428 pub fn set_resize_callback(&mut self, f: Box<dyn FnMut(u16, u16)>) {
429 self.resized = Some(f);
430 }
431 pub fn load_rom(&mut self, data: &[u8]) {
432 let _ = self.vm.reset(data);
433 self.dev.reset(data);
434 self.vm.run(&mut self.dev, 0x100);
435 let out = self.dev.output(&self.vm);
436 self.size = out.size;
437 }
438 pub fn step(&mut self) {
439 self.dev.redraw(&mut self.vm);
441 }
442 pub fn update_texture(&mut self) {
443 let out = self.dev.output(&self.vm);
444 let mut image = egui::ColorImage::new(
445 [out.size.0 as usize, out.size.1 as usize],
446 vec![
447 egui::Color32::BLACK;
448 (out.size.0 as usize) * (out.size.1 as usize)
449 ],
450 );
451 for (i, o) in out.frame.chunks(4).zip(image.pixels.iter_mut()) {
452 *o = egui::Color32::from_rgba_unmultiplied(i[0], i[1], i[2], i[3]);
453 }
454 self.texture.set(image, egui::TextureOptions::NEAREST);
455 }
456 pub fn draw(&self, ui: &mut egui::Ui) {
457 let panel_size =
458 egui::Vec2::new(self.size.0 as f32, self.size.1 as f32)
459 * self.scale;
460 let (_rect_id, rect) = ui.allocate_space(panel_size);
461 let mut mesh = egui::Mesh::with_texture(self.texture.id());
462 mesh.add_rect_with_uv(
463 egui::Rect {
464 min: rect.min,
465 max: rect.min + panel_size,
466 },
467 egui::Rect {
468 min: egui::Pos2::new(0.0, 0.0),
469 max: egui::Pos2::new(1.0, 1.0),
470 },
471 egui::Color32::WHITE,
472 );
473 ui.painter().add(egui::Shape::mesh(mesh));
474 }
475
476 pub fn handle_usb_input(&mut self) {
477 if let Some(controller_usb) = self.dev.controller_usb_mut() {
478 let events =
479 varvara::controller_usb::ControllerPollEvents::poll_usb_events(
480 controller_usb,
481 &mut self.vm,
482 );
483 for event in events {
484 self.dev.process_event(&mut self.vm, event);
485 }
486 }
487 }
496}