1use std::{
2 fs,
3 sync::{Arc, Mutex},
4};
5
6use fennel_core::{
7 Window,
8 events::{KeyboardEvent, WindowEventHandler},
9 graphics::WindowConfig,
10};
11use serde::{Deserialize, Serialize};
12use specs::{Builder, Dispatcher, DispatcherBuilder, WorldExt};
13
14use crate::{
15 ecs::{
16 input::InputSystem,
17 scene::SceneSystem,
18 sprite::{HostPtr, RenderingSystem, Sprite, SpriteFactory},
19 },
20 events::KeyEvents,
21 registry::ComponentRegistry,
22 scenes::{ActiveScene, Scene},
23};
24
25pub struct App {
28 pub window: fennel_core::Window,
30 pub world: specs::World,
32 pub dispatcher: Dispatcher<'static, 'static>,
34 pub scenes: Vec<Scene>,
36 pub component_registry: ComponentRegistry,
38 pub active_scene: ActiveScene
40}
41
42#[derive(Default, Debug)]
44pub struct AppBuilder {
45 name: &'static str,
46 dimensions: (u32, u32),
47 config: &'static str,
48 window_config: WindowConfig,
49}
50
51#[derive(Deserialize, Serialize, Debug)]
53struct Config {
54 assets_path: String,
56 scenes_path: String,
58 initial_scene: String,
60}
61
62unsafe impl Send for App {}
63unsafe impl Sync for App {}
64
65#[async_trait::async_trait]
66impl WindowEventHandler for App {
67 fn update(&self, _window: &mut Window) -> anyhow::Result<()> {
68 Ok(())
69 }
70
71 fn draw(&mut self, window: &mut Window) -> anyhow::Result<()> {
72 self.frame_tick();
73 window.graphics.canvas.present();
74 Ok(())
75 }
76
77 fn key_down_event(&self, _window: &mut Window, event: KeyboardEvent) -> anyhow::Result<()> {
78 println!("{:?}", event.keycode);
79 Ok(())
80 }
81}
82
83impl App {
84 pub async fn run(mut self) -> anyhow::Result<()> {
86 let ptr: *mut App = &mut self as *mut App;
92 fennel_core::events::run(&mut self.window, unsafe { &mut *ptr as &mut App }).await;
93 Ok(())
94 }
95
96 pub fn frame_tick(&mut self) {
98 let host_ptr = HostPtr(self as *mut App);
99 self.world.insert(host_ptr);
100 self.dispatcher.dispatch(&self.world);
101 self.world.maintain();
102 self.world.remove::<HostPtr>();
103 }
104}
105
106impl AppBuilder {
107 pub fn new() -> AppBuilder {
109 AppBuilder {
110 name: "",
111 dimensions: (100, 100),
112 config: "",
113 window_config: WindowConfig {
114 resizable: false,
115 fullscreen: false,
116 centered: false,
117 },
118 }
119 }
120
121 pub fn name(mut self, name: &'static str) -> AppBuilder {
123 self.name = name;
124 self
125 }
126
127 pub fn dimensions(mut self, dimensions: (u32, u32)) -> AppBuilder {
129 self.dimensions = dimensions;
130 self
131 }
132
133 pub fn config(mut self, path: &'static str) -> AppBuilder {
135 self.config = path;
136 self
137 }
138
139 pub fn build(self) -> anyhow::Result<App> {
141 let resource_manager = Arc::new(Mutex::new(fennel_core::resources::ResourceManager::new()));
142 let config_reader = fs::read(self.config)?;
143 let config: Config = toml::from_slice(&config_reader)?;
144 let graphics = fennel_core::graphics::Graphics::new(
145 self.name.to_string(),
146 self.dimensions,
147 resource_manager.clone(),
148 |graphics| {
149 resource_manager.lock().unwrap().load_dir(config.assets_path.clone().into(), graphics).unwrap();
150 },
151 self.window_config
152 );
153 let window = fennel_core::Window::new(
154 graphics.expect("failed to initialize graphics"),
155 resource_manager,
156 );
157 let mut component_registry = ComponentRegistry::new();
158 let mut world = specs::World::new();
159 let mut dispatcher = DispatcherBuilder::new()
160 .with_thread_local(RenderingSystem)
161 .with(SceneSystem, "scene_system", &[])
162 .with(InputSystem, "input_system", &[])
163 .build();
164 let mut scenes: Vec<Scene> = vec![];
165
166 component_registry.register("sprite", Box::new(SpriteFactory));
167 world.register::<Scene>();
168 world.register::<Sprite>();
169 world.insert(KeyEvents::default());
170
171 for entry in fs::read_dir(config.scenes_path).expect("meow") {
172 let scene_reader = fs::read(entry.unwrap().path()).expect("meow");
173 let scene: Scene = ron::de::from_bytes(&scene_reader)?;
174 world.create_entity().with(scene.clone()).build();
175 scenes.push(scene.clone());
176 }
177
178 dispatcher.setup(&mut world);
179
180 Ok(App {
181 window,
182 world,
183 dispatcher,
184 scenes,
185 component_registry,
186 active_scene: ActiveScene { name: String::from("main"), loaded: false }
188 })
189 }
190}