mod support; use std::{sync::Arc, time::Instant}; use anyhow::Context; use egui::TextBuffer; use egui_glow::glow::{HasContext, COLOR_BUFFER_BIT}; use egui_sdl2_platform::sdl2; use sdl2::event::{Event, WindowEvent}; use gemma::chip8::computer::Chip8Computer; use support::timestep::TimeStep; use crate::support::gemma_egui_support::GemmaEguiSupport; const SCREEN_WIDTH: u32 = 800; const SCREEN_HEIGHT: u32 = 480; async fn run() -> anyhow::Result { // Initialize SDL2 and video subsystem let sdl = sdl2::init().map_err(|e| anyhow::anyhow!("Failed to create SDL context: {}", e))?; let mut video = sdl.video().map_err(|e| anyhow::anyhow!("Failed to initialize SDL video subsystem: {}", e))?; // Create SDL2 window and OpenGL context let window = video.window("Window", SCREEN_WIDTH, SCREEN_HEIGHT) .opengl() .position_centered() .build()?; let _gl_context = window.gl_create_context().expect("Failed to create GL context"); // Load OpenGL functions let gl = unsafe { egui_glow::painter::Context::from_loader_function(|name| { video.gl_get_proc_address(name) as *const _ }) }; let mut painter = egui_glow::Painter::new(Arc::new(gl), "", None)?; // Setup Egui and SDL2 platform let mut platform = egui_sdl2_platform::Platform::new(window.size())?; let mut event_pump = sdl.event_pump().map_err(|e| anyhow::anyhow!("Failed to get SDL event pump: {}", e))?; // Initial settings let color = [0.0, 0.0, 0.0, 1.0]; // Background color let start_time = Instant::now(); let mut timestep = TimeStep::new(); let mut computer = Chip8Computer::new(); let mut is_running: bool = false; computer.load_bytes_to_memory(0x200, &std::fs::read("resources/roms/3-corax+.ch8")?); // Main loop 'main: loop { // Update the Egui platform with the current time platform.update_time(start_time.elapsed().as_secs_f64()); // Begin Egui frame let ctx = platform.context(); if is_running { computer.step_system(); } egui::Window::new("Hello, world!").show(&ctx, |ui| { GemmaEguiSupport::video_view(&computer, ui); GemmaEguiSupport::memory_view(&computer, ui); GemmaEguiSupport::registers_view(&computer, ui); }); // Process Egui frame let full_output = platform.end_frame(&mut video)?; let paint_jobs = platform.tessellate(&full_output); // Clear the screen with the current color unsafe { painter.gl().clear_color(color[0], color[1], color[2], 1.0); painter.gl().clear(COLOR_BUFFER_BIT); } // Paint Egui outputs and update textures let size = window.size(); painter.paint_and_update_textures([size.0, size.1], 1.0, paint_jobs.as_slice(), &full_output.textures_delta); window.gl_swap_window(); // Run the timestep logic timestep.run_this(|_| {}); // Handle SDL2 events for event in event_pump.poll_iter() { match event { Event::Quit { .. } | Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::Escape), .. } => break 'main, Event::Window { window_id, win_event, .. } if window_id == window.id() => { if let WindowEvent::Close = win_event { break 'main; } } Event::KeyUp { keycode: Some(sdl2::keyboard::Keycode::F3), .. } => { println!("USER PRESSED F3 -> running"); is_running = true; } Event::KeyUp { keycode: Some(sdl2::keyboard::Keycode::F4), .. } => { println!("USER PRESSED F4 -> stopping"); is_running = false; } Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::F5), .. } => { println!("USER PRESSED F5 -> Step"); computer.step_system(); } Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::F6), .. } => { println!("USER PRESSED F6 -> RESET"); computer.reset(); } Event::ControllerButtonDown { which, .. } => { println!("PLAYER {which} DOWN"); } Event::ControllerButtonDown { button, .. } => { println!("BUTTON {:?}", button); } Event::JoyButtonDown {button_idx, .. } => { println!("JoyButtonDown {}", button_idx); } Event::JoyAxisMotion { which, axis_idx, .. } => { println!("JoyAxismotion {which} {axis_idx}"); } _ => platform.handle_event(&event, &sdl, &video), } } // Optionally log the frame rate if let Some(fps) = timestep.frame_rate() { println!("{:?} fps", fps); } let num_js = sdl.joystick().unwrap().num_joysticks().unwrap(); println!("NUM JS = {num_js}"); } Ok(("").parse()?) } fn main() -> anyhow::Result<()> { pollster::block_on(run())?; Ok(()) }