pfx_editor_shell/
paint.rs1use egui::epaint::ClippedPrimitive;
2use egui::{Color32, TexturesDelta};
3use egui_wgpu::{Renderer, RendererOptions, ScreenDescriptor};
4use pfx_gpu::{Gpu, wgpu};
5
6pub struct Painter {
7 renderer: Renderer,
8}
9
10pub fn linear(v: u8) -> f64 {
11 let c = f64::from(v) / 255.0;
12 if c <= 0.04045 {
13 c / 12.92
14 } else {
15 ((c + 0.055) / 1.055).powf(2.4)
16 }
17}
18
19pub fn clear(colour: Color32) -> wgpu::Color {
20 wgpu::Color {
21 r: linear(colour.r()),
22 g: linear(colour.g()),
23 b: linear(colour.b()),
24 a: 1.0,
25 }
26}
27
28impl Painter {
29 pub fn new(gpu: &Gpu, format: wgpu::TextureFormat, options: RendererOptions) -> Painter {
30 Painter {
31 renderer: Renderer::new(&gpu.device, format, options),
32 }
33 }
34
35 pub fn renderer(&mut self) -> &mut Renderer {
36 &mut self.renderer
37 }
38
39 pub fn paint(
40 &mut self,
41 gpu: &Gpu,
42 view: &wgpu::TextureView,
43 screen: &ScreenDescriptor,
44 textures: &TexturesDelta,
45 primitives: &[ClippedPrimitive],
46 ground: Color32,
47 ) {
48 for (id, deltas) in &textures.set {
49 for delta in deltas {
50 self.renderer
51 .update_texture(&gpu.device, &gpu.queue, *id, delta);
52 }
53 }
54 let mut encoder = gpu
55 .device
56 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
57 label: Some("editor ui"),
58 });
59 let mut commands =
60 self.renderer
61 .update_buffers(&gpu.device, &gpu.queue, &mut encoder, primitives, screen);
62 {
63 let pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
64 multiview_mask: None,
65 label: Some("editor ui"),
66 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
67 view,
68 depth_slice: None,
69 resolve_target: None,
70 ops: wgpu::Operations {
71 load: wgpu::LoadOp::Clear(clear(ground)),
72 store: wgpu::StoreOp::Store,
73 },
74 })],
75 depth_stencil_attachment: None,
76 timestamp_writes: None,
77 occlusion_query_set: None,
78 });
79 let mut pass = pass.forget_lifetime();
80 self.renderer.render(&mut pass, primitives, screen);
81 }
82 commands.push(encoder.finish());
83 gpu.queue.submit(commands);
84 for id in &textures.free {
85 self.renderer.free_texture(id);
86 }
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn the_clear_colour_is_linear() {
96 let colour = clear(Color32::from_rgb(0, 255, 0x80));
97 assert_eq!(colour.r, 0.0);
98 assert_eq!(colour.g, 1.0);
99 assert!((colour.b - 0.2158605).abs() < 1e-6);
100 }
101}