1use std::collections::BTreeMap;
2
3use egui::TextureId;
4use pfx_gpu::{Gpu, wgpu};
5use pfx_live::demand::{Limits, Need, Next};
6use pfx_live::renderer::{Exposure, Renderer};
7use pfx_live::scene::{Override, Staged};
8use pfx_load::scene::{Camera, Scene, SceneDiff};
9
10pub const FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Rgba8UnormSrgb;
11pub const SHOWN: wgpu::TextureFormat = wgpu::TextureFormat::Rgba8Unorm;
12pub const IN_FLIGHT: u64 = 1;
13
14#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
15pub struct Drawn {
16 pub drew: bool,
17 pub picked: Option<u32>,
18 pub awaiting: bool,
19}
20
21struct Surface {
22 texture: wgpu::Texture,
23 view: wgpu::TextureView,
24 shown: wgpu::TextureView,
25}
26
27fn surface(gpu: &Gpu, size: [u32; 2]) -> Surface {
28 let texture = gpu.device.create_texture(&wgpu::TextureDescriptor {
29 label: Some("editor viewport"),
30 size: wgpu::Extent3d {
31 width: size[0],
32 height: size[1],
33 depth_or_array_layers: 1,
34 },
35 mip_level_count: 1,
36 sample_count: 1,
37 dimension: wgpu::TextureDimension::D2,
38 format: FORMAT,
39 usage: wgpu::TextureUsages::RENDER_ATTACHMENT
40 | wgpu::TextureUsages::TEXTURE_BINDING
41 | wgpu::TextureUsages::COPY_SRC
42 | wgpu::TextureUsages::COPY_DST,
43 view_formats: &[SHOWN],
44 });
45 let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
46 let shown = texture.create_view(&wgpu::TextureViewDescriptor {
47 format: Some(SHOWN),
48 ..wgpu::TextureViewDescriptor::default()
49 });
50 Surface {
51 texture,
52 view,
53 shown,
54 }
55}
56
57pub struct Live {
58 gpu: Gpu,
59 renderer: Renderer,
60 staged: Staged,
61 scene: Scene,
62 revision: u64,
63 camera: Camera,
64 surface: Surface,
65 id: TextureId,
66 size: [u32; 2],
67 awaiting: bool,
68 drawn: u64,
69}
70
71fn aspect(size: [u32; 2]) -> f32 {
72 size[0].max(1) as f32 / size[1].max(1) as f32
73}
74
75impl Live {
76 pub fn new(
77 gpu: &Gpu,
78 egui: &mut egui_wgpu::Renderer,
79 scene: &Scene,
80 revision: u64,
81 camera: Camera,
82 size: [u32; 2],
83 ) -> Result<Live, String> {
84 let mut renderer = Renderer::new_with_output_format(gpu.clone(), size[0], size[1], FORMAT)
85 .map_err(|error| format!("the live renderer could not start: {error}"))?;
86 renderer.set_exposure(Exposure::Fixed(1.0))?;
87 renderer.set_frames_on_demand(Some(Limits::default()))?;
88 let mut shown = scene.clone();
89 shown.camera = Some(camera);
90 let staged = renderer.stage(&shown)?;
91 renderer.wait_sky()?;
92 renderer.set_lens(staged.lens(aspect(size)));
93 let surface = surface(gpu, size);
94 let id =
95 egui.register_native_texture(&gpu.device, &surface.shown, wgpu::FilterMode::Nearest);
96 Ok(Live {
97 gpu: gpu.clone(),
98 renderer,
99 staged,
100 scene: shown,
101 revision,
102 camera,
103 surface,
104 id,
105 size,
106 awaiting: false,
107 drawn: 0,
108 })
109 }
110
111 pub fn texture(&self) -> TextureId {
112 self.id
113 }
114
115 pub fn size(&self) -> [u32; 2] {
116 self.size
117 }
118
119 pub fn revision(&self) -> u64 {
120 self.revision
121 }
122
123 pub fn drawn(&self) -> u64 {
124 self.drawn
125 }
126
127 pub fn staged(&self) -> &Staged {
128 &self.staged
129 }
130
131 pub fn image(&self) -> &wgpu::Texture {
132 &self.surface.texture
133 }
134
135 pub fn resize(
136 &mut self,
137 egui: &mut egui_wgpu::Renderer,
138 size: [u32; 2],
139 ) -> Result<bool, String> {
140 if size == self.size {
141 return Ok(false);
142 }
143 self.renderer.resize(size[0], size[1])?;
144 self.surface = surface(&self.gpu, size);
145 egui.update_egui_texture_from_wgpu_texture(
146 &self.gpu.device,
147 &self.surface.shown,
148 wgpu::FilterMode::Nearest,
149 self.id,
150 );
151 self.size = size;
152 self.renderer.set_lens(self.staged.lens(aspect(size)));
153 Ok(true)
154 }
155
156 pub fn show(&mut self, scene: &Scene, revision: u64) -> Result<(), String> {
157 let mut next = scene.clone();
158 next.camera = self.scene.camera;
159 let diff = self.scene.diff(&next);
160 self.staged.apply(&mut self.renderer, &next, &diff)?;
161 self.scene = next;
162 self.revision = revision;
163 Ok(())
164 }
165
166 pub fn look(&mut self, camera: Camera) -> Result<(), String> {
167 if self.camera == camera {
168 return Ok(());
169 }
170 self.scene.camera = Some(camera);
171 let diff = SceneDiff {
172 camera: true,
173 ..SceneDiff::default()
174 };
175 self.staged.apply(&mut self.renderer, &self.scene, &diff)?;
176 self.renderer.set_lens(self.staged.lens(aspect(self.size)));
177 self.camera = camera;
178 Ok(())
179 }
180
181 pub fn overrides(&mut self, wanted: &BTreeMap<String, Override>) {
182 let gone: Vec<String> = self
183 .staged
184 .overrides()
185 .keys()
186 .filter(|name| !wanted.contains_key(*name))
187 .cloned()
188 .collect();
189 for name in gone {
190 self.staged.clear_override(&name);
191 }
192 for (name, change) in wanted {
193 if self.staged.overrides().get(name) != Some(change) {
194 self.staged.set_override(name, *change);
195 }
196 }
197 }
198
199 pub fn gpu_ms(&self) -> Option<f64> {
200 self.renderer
201 .timings()
202 .filter(|timings| !timings.passes.is_empty())
203 .map(|timings| timings.passes.iter().map(|t| t.milliseconds).sum())
204 }
205
206 pub fn drops(&self) -> u64 {
207 let drops = self.renderer.timing_drops();
208 drops.ring + drops.late
209 }
210
211 pub fn draw(&mut self, pick: Option<[u32; 2]>) -> Result<Drawn, String> {
212 let mut drawn = Drawn::default();
213 if self.awaiting
214 && let Some(picked) = self.renderer.picked()
215 {
216 self.awaiting = false;
217 drawn.picked = Some(picked.id);
218 }
219 let size = self.size;
220 let finish = self.staged.finish();
221 let frame = self.staged.frame(aspect(size), 0.0, 0);
222 let next = Next::new(&frame.scene, &frame.text, &frame.effects, finish);
223 if let Some([x, y]) = pick {
224 self.renderer.pick(x.min(size[0] - 1), y.min(size[1] - 1))?;
225 self.renderer
226 .render_needed(&next, &Need::Full, &self.surface.view)?;
227 match self.renderer.picked() {
228 Some(picked) => drawn.picked = Some(picked.id),
229 None => self.awaiting = true,
230 }
231 drawn.drew = true;
232 } else {
233 let need = self.renderer.frame_needed(&next);
234 if need.draws() {
235 if self.renderer.frames_in_flight() >= IN_FLIGHT {
236 self.renderer.wait_frames(IN_FLIGHT - 1)?;
237 }
238 self.renderer
239 .submit_needed(&next, &need, &self.surface.view)?;
240 drawn.drew = true;
241 }
242 }
243 if drawn.drew {
244 self.drawn += 1;
245 }
246 drawn.awaiting = self.awaiting;
247 Ok(drawn)
248 }
249}