raui_app/
render_worker.rs1use 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}