Skip to main content

ursus_core/app/
context.rs

1use crate::app::Plugin;
2use crate::assets::registry::AssetRegistry;
3use crate::assets::upload::GpuUploadRequest;
4use crate::render::extract::{ExtractSchedule, ExtractSystem};
5use crate::render::frame_pipeline::render_pipeline::RenderPipeline;
6use crate::render::frame_stats::FrameStats;
7use crate::render::thread::command::{PipelineFactory, RenderCommand};
8use crate::render::triple_buffer::TripleBuffer;
9use crate::render::world::{ExtractedRenderSettings, RWorld};
10use std::sync::mpsc::Sender;
11use std::sync::Arc;
12use ursus_ecs::tick::default_tick_schedule;
13use ursus_ecs::{TickSchedule, TickSystem, World};
14
15#[allow(clippy::enum_variant_names)]
16pub enum WindowCommand {
17    SetTitle(String),
18    SetSize(u32, u32),
19    SetFullscreen(bool), // true = borderless fullscreen
20}
21
22pub struct EngineContext {
23    pub world: World,
24    pub asset_registry: AssetRegistry,
25    pub extract_schedule: ExtractSchedule,
26    pub tick_schedule: TickSchedule,
27
28    pub(crate) cmd_tx: Sender<RenderCommand>,
29    upload_tx: Sender<GpuUploadRequest>,
30    triple_buf: Arc<TripleBuffer<RWorld>>,
31    pub(crate) output_size: (f32, f32),
32    frame_stats: FrameStats,
33    pub(crate) window_cmd_tx: Sender<WindowCommand>,
34}
35
36impl EngineContext {
37    pub(crate) fn new(
38        cmd_tx: Sender<RenderCommand>,
39        upload_tx: Sender<GpuUploadRequest>,
40        triple_buf: Arc<TripleBuffer<RWorld>>,
41        output_size: (f32, f32),
42        frame_stats: FrameStats,
43        window_cmd_tx: Sender<WindowCommand>,
44    ) -> anyhow::Result<Self> {
45        Ok(Self {
46            world: World::new(),
47            asset_registry: AssetRegistry::default(),
48            extract_schedule: ExtractSchedule::default(),
49            tick_schedule: default_tick_schedule(),
50            cmd_tx,
51            upload_tx,
52            triple_buf,
53            output_size,
54            frame_stats,
55            window_cmd_tx,
56        })
57    }
58
59    pub fn frame_stats(&self) -> &FrameStats {
60        &self.frame_stats
61    }
62
63    pub fn send_render_cmd(&self, cmd: RenderCommand) {
64        let _ = self.cmd_tx.send(cmd);
65    }
66
67    pub fn set_pipeline<P>(&self)
68    where
69        P: RenderPipeline + Default + 'static,
70    {
71        self.send_render_cmd(RenderCommand::SetPipeline(PipelineFactory::of::<P>()));
72    }
73
74    pub(crate) fn publish_frame(&mut self, clear_color: [f32; 4], interpolation_alpha: f32) {
75        let write = self.triple_buf.write_slot();
76        write.clear();
77        write.insert(ExtractedRenderSettings {
78            clear_color,
79            output_size: self.output_size,
80            fsr_sharpness: 0.2,
81            exposure: 0.5,
82            interpolation_alpha,
83        });
84        self.extract_schedule.run(&self.world, write);
85        self.asset_registry.flush_uploads(&self.upload_tx);
86        self.triple_buf.publish();
87    }
88
89    pub fn set_window_title(&self, title: impl Into<String>) {
90        let _ = self.window_cmd_tx.send(WindowCommand::SetTitle(title.into()));
91    }
92    pub fn set_window_size(&self, width: u32, height: u32) {
93        let _ = self.window_cmd_tx.send(WindowCommand::SetSize(width, height));
94    }
95    pub fn set_fullscreen(&self, enabled: bool) {
96        let _ = self.window_cmd_tx.send(WindowCommand::SetFullscreen(enabled));
97    }
98
99    pub fn add_extract_system(&mut self, system: impl ExtractSystem + 'static) {
100        self.extract_schedule.add(system);
101    }
102
103    pub fn add_tick_system(&mut self, system: impl TickSystem + 'static) {
104        self.tick_schedule.add(system);
105    }
106
107    pub fn add_plugin(&mut self, plugin: impl Plugin) {
108        plugin.build(self);
109    }
110
111    pub fn add_plugins(&mut self, plugins: impl IntoIterator<Item = impl Plugin>) {
112        for p in plugins {
113            self.add_plugin(p);
114        }
115    }
116}