Skip to main content

raui_app/
render_worker.rs

1use crate::{AssetsManager, Vertex};
2use spitfire_glow::{
3    graphics::{Graphics, Shader, Surface},
4    renderer::GlowTextureFormat,
5};
6use std::collections::HashMap;
7
8pub struct RenderWorkerDescriptor {
9    pub id: String,
10    pub width: u32,
11    pub height: u32,
12    pub format: GlowTextureFormat,
13    pub color: [f32; 4],
14}
15
16#[derive(Default)]
17pub struct RenderWorkersViewModel {
18    surfaces: HashMap<String, Surface>,
19    commands: Vec<Command>,
20}
21
22impl RenderWorkersViewModel {
23    pub const VIEW_MODEL: &str = "RenderWorkersViewModel";
24
25    pub fn workers(&self) -> impl Iterator<Item = &str> {
26        self.surfaces.keys().map(|s| s.as_str())
27    }
28
29    pub fn add_worker(&mut self, worker: RenderWorkerDescriptor) {
30        self.commands.push(Command::Create { worker });
31    }
32
33    pub fn add_worker_surface(&mut self, id: impl ToString, surface: Surface) {
34        self.commands.push(Command::Add {
35            id: id.to_string(),
36            surface,
37        });
38    }
39
40    pub fn remove_worker(&mut self, worker: &str) {
41        self.commands.push(Command::Remove {
42            worker: worker.to_owned(),
43        });
44    }
45
46    pub fn schedule_task(
47        &mut self,
48        worker: &str,
49        clear: bool,
50        task: impl FnOnce(RenderWorkerTaskContext) + 'static,
51    ) {
52        self.commands.push(Command::Schedule {
53            worker: worker.to_owned(),
54            clear,
55            task: Box::new(task),
56        });
57    }
58
59    pub(crate) fn maintain(
60        &mut self,
61        graphics: &mut Graphics<Vertex>,
62        assets: &mut AssetsManager,
63        colored_shader: &Shader,
64        textured_shader: &Shader,
65        text_shader: &Shader,
66    ) {
67        for command in self.commands.drain(..) {
68            match command {
69                Command::Create { worker } => {
70                    let Ok(texture) =
71                        graphics.texture(worker.width, worker.height, 1, worker.format, None)
72                    else {
73                        continue;
74                    };
75                    let Ok(mut surface) = graphics.surface(vec![texture.clone().into()]) else {
76                        continue;
77                    };
78                    surface.set_color(worker.color);
79                    self.surfaces.insert(worker.id.clone(), surface);
80                    assets.add_texture(worker.id, texture);
81                }
82                Command::Add { id, surface } => {
83                    self.surfaces.insert(id, surface);
84                }
85                Command::Remove { worker } => {
86                    self.surfaces.remove(&worker);
87                    assets.remove_texture(&worker);
88                }
89                Command::Schedule {
90                    worker,
91                    clear,
92                    task,
93                } => {
94                    if let Some(surface) = self.surfaces.get(&worker) {
95                        let _ = graphics.draw();
96                        let _ = graphics.push_surface(surface.clone());
97                        let _ = graphics.prepare_frame(clear);
98                        (task)(RenderWorkerTaskContext {
99                            width: surface.width(),
100                            height: surface.height(),
101                            format: surface.attachments()[0].texture.format(),
102                            graphics,
103                            colored_shader,
104                            textured_shader,
105                            text_shader,
106                        });
107                        let _ = graphics.draw();
108                        let _ = graphics.pop_surface();
109                        let _ = graphics.prepare_frame(false);
110                    }
111                }
112            }
113        }
114    }
115}
116
117pub struct RenderWorkerTaskContext<'a> {
118    pub width: u32,
119    pub height: u32,
120    pub format: GlowTextureFormat,
121    pub graphics: &'a mut Graphics<Vertex>,
122    pub colored_shader: &'a Shader,
123    pub textured_shader: &'a Shader,
124    pub text_shader: &'a Shader,
125}
126
127enum Command {
128    Create {
129        worker: RenderWorkerDescriptor,
130    },
131    Add {
132        id: String,
133        surface: Surface,
134    },
135    Remove {
136        worker: String,
137    },
138    Schedule {
139        worker: String,
140        clear: bool,
141        #[allow(clippy::type_complexity)]
142        task: Box<dyn FnOnce(RenderWorkerTaskContext)>,
143    },
144}