fennel_engine/
app.rs

1use std::sync::{Arc, Mutex};
2
3use fennel_core::{events::{KeyboardEvent, WindowEventHandler}, Window};
4use specs::{Dispatcher, DispatcherBuilder, WorldExt};
5
6use crate::{ecs::{input::InputSystem, sprite::{HostPtr, RenderingSystem, Sprite}}, events::KeyEvents};
7
8pub struct App {
9    pub window: fennel_core::Window,
10    pub world: specs::World,
11    pub dispatcher: Dispatcher<'static, 'static>,
12}
13
14#[derive(Default, Debug)]
15pub struct AppBuilder {
16    name: &'static str,
17    dimensions: (u32, u32),
18}
19
20unsafe impl Send for App {}
21unsafe impl Sync for App {}
22
23#[async_trait::async_trait]
24impl WindowEventHandler for App {
25    fn update(&self, _window: &mut Window) -> anyhow::Result<()> {
26        Ok(())
27    }
28
29    fn draw(&mut self, window: &mut Window) -> anyhow::Result<()> {
30        self.frame_tick();
31        window.graphics.canvas.present();
32        Ok(())
33    }
34
35    fn key_down_event(&self, _window: &mut Window, event: KeyboardEvent) -> anyhow::Result<()> {
36        println!("{:?}", event.keycode);
37        Ok(())
38    }
39}
40
41impl App {
42    pub async fn run(mut self) -> anyhow::Result<()> {
43        // you know what? fuck you and your borrow checker.
44        // i'm 100% sure this app is single-threaded and its 11 pm
45        // at the moment so i'm not gonna solve this shit in some
46        // safe way
47        // as long this works and doesn't SEGFAULTs i'll keep it 
48        let ptr: *mut App = &mut self as *mut App;
49        fennel_core::events::run(&mut self.window, unsafe { &mut *ptr as &mut App }).await;
50        Ok(())
51    }
52
53    pub fn frame_tick(&mut self) {
54        let host_ptr = HostPtr(self as *mut App);
55        self.world.insert(host_ptr);
56        self.dispatcher.dispatch(&self.world);
57        self.world.maintain();
58        self.world.remove::<HostPtr>();
59    }
60}
61
62impl AppBuilder {
63    pub fn new() -> AppBuilder {
64        AppBuilder {
65            name: "",
66            dimensions: (100, 100),
67        }
68    }
69
70    pub fn name(mut self, name: &'static str) -> AppBuilder {
71        self.name = name;
72        self
73    }
74
75    pub fn dimensions(mut self, dimensions: (u32, u32)) -> AppBuilder {
76        self.dimensions = dimensions;
77        self
78    }
79
80    pub fn build(&self) -> anyhow::Result<App> {
81        let resource_manager = Arc::new(Mutex::new(fennel_core::resources::ResourceManager::new()));
82        let graphics = fennel_core::graphics::Graphics::new(
83            self.name.to_string(),
84            self.dimensions,
85            resource_manager.clone(),
86        );
87        let window = fennel_core::Window::new(
88            graphics.expect("failed to initialize graphics"),
89            resource_manager,
90        );
91        let mut world = specs::World::new();
92        let mut dispatcher = DispatcherBuilder::new()
93            .with_thread_local(RenderingSystem)
94            .with(InputSystem, "input_system", &[])
95            .build();
96        world.register::<Sprite>();
97        world.insert(KeyEvents::default());
98        dispatcher.setup(&mut world);
99
100        Ok(App {
101            window,
102            world,
103            dispatcher,
104        })
105    }
106}