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::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}
39
40#[derive(Default, Debug)]
42pub struct AppBuilder {
43 name: &'static str,
44 dimensions: (u32, u32),
45 config: &'static str,
46 window_config: WindowConfig,
47}
48
49#[derive(Deserialize, Serialize, Debug)]
51struct Config {
52 assets_path: String,
54 scenes_path: String,
56 initial_scene: String,
58}
59
60unsafe impl Send for App {}
61unsafe impl Sync for App {}
62
63#[async_trait::async_trait]
64impl WindowEventHandler for App {
65 fn update(&self, _window: &mut Window) -> anyhow::Result<()> {
66 Ok(())
67 }
68
69 fn draw(&mut self, window: &mut Window) -> anyhow::Result<()> {
70 self.frame_tick();
71 window.graphics.canvas.present();
72 Ok(())
73 }
74
75 fn key_down_event(&self, _window: &mut Window, event: KeyboardEvent) -> anyhow::Result<()> {
76 println!("{:?}", event.keycode);
77 Ok(())
78 }
79}
80
81impl App {
82 pub async fn run(mut self) -> anyhow::Result<()> {
84 let ptr: *mut App = &mut self as *mut App;
90 fennel_core::events::run(&mut self.window, unsafe { &mut *ptr as &mut App }).await;
91 Ok(())
92 }
93
94 pub fn frame_tick(&mut self) {
96 let host_ptr = HostPtr(self as *mut App);
97 self.world.insert(host_ptr);
98 self.dispatcher.dispatch(&self.world);
99 self.world.maintain();
100 self.world.remove::<HostPtr>();
101 }
102}
103
104impl AppBuilder {
105 pub fn new() -> AppBuilder {
107 AppBuilder {
108 name: "",
109 dimensions: (100, 100),
110 config: "",
111 window_config: WindowConfig {
112 resizable: false,
113 fullscreen: false,
114 centered: false,
115 },
116 }
117 }
118
119 pub fn name(mut self, name: &'static str) -> AppBuilder {
121 self.name = name;
122 self
123 }
124
125 pub fn dimensions(mut self, dimensions: (u32, u32)) -> AppBuilder {
127 self.dimensions = dimensions;
128 self
129 }
130
131 pub fn config(mut self, path: &'static str) -> AppBuilder {
133 self.config = path;
134 self
135 }
136
137 pub fn build(self) -> anyhow::Result<App> {
139 let resource_manager = Arc::new(Mutex::new(fennel_core::resources::ResourceManager::new()));
140 let config_reader = fs::read(self.config)?;
141 let config: Config = toml::from_slice(&config_reader)?;
142 let graphics = fennel_core::graphics::Graphics::new(
143 self.name.to_string(),
144 self.dimensions,
145 resource_manager.clone(),
146 |graphics| {
147 resource_manager.lock().unwrap().load_dir(config.assets_path.clone().into(), graphics).unwrap();
148 },
149 self.window_config
150 );
151 let window = fennel_core::Window::new(
152 graphics.expect("failed to initialize graphics"),
153 resource_manager,
154 );
155 let mut component_registry = ComponentRegistry::new();
156 let mut world = specs::World::new();
157 let mut dispatcher = DispatcherBuilder::new()
158 .with_thread_local(RenderingSystem)
159 .with(SceneSystem, "scene_system", &[])
160 .with(InputSystem, "input_system", &[])
161 .build();
162 let mut scenes: Vec<Scene> = vec![];
163
164 component_registry.register("sprite", Box::new(SpriteFactory));
165 world.register::<Scene>();
166 world.register::<Sprite>();
167 world.insert(KeyEvents::default());
168
169 for entry in fs::read_dir(config.scenes_path).expect("meow") {
170 let scene_reader = fs::read(entry.unwrap().path()).expect("meow");
171 let scene: Scene = ron::de::from_bytes(&scene_reader)?;
172 world.create_entity().with(scene.clone()).build();
173 scenes.push(scene.clone());
174
175 for entity in &scene.entities {
176 for component in &entity.components {
177 let factory = component_registry.get(&component.id)
178 .unwrap_or_else(|| { panic!("no factory {} found", component.id) });
179 let entity = world.create_entity().build();
180 factory.insert(&mut world, entity, &component.config);
181 }
182 }
183 }
184
185 dispatcher.setup(&mut world);
186
187 Ok(App {
188 window,
189 world,
190 dispatcher,
191 scenes,
192 component_registry
193 })
194 }
195}