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 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}