1use std::collections::BTreeMap;
2
3use pfx_live::frame::{
4 Instance, InstanceSurface, Matrix, Scene as FrameScene, SceneWind, multiply,
5};
6use pfx_live::glass;
7use pfx_live::renderer::{Effects, Renderer, Text, invert};
8use pfx_live::scene::{self as live_scene, Staged};
9use pfx_live::skin::InstancePose;
10use pfx_live::text::TextSpace;
11use pfx_load::scene::{Camera, Scene, surface as sprite_surface};
12use pfx_materials::{Family, Material};
13use pfx_post::{Bloom, Chain, Pass, Tone};
14
15use crate::PlayError;
16use crate::world::{Look, ObjectId, World};
17
18pub struct PlayFrame<'a> {
19 pub scene: FrameScene<'a>,
20 pub text: Text<'a>,
21 pub effects: Effects<'a>,
22}
23
24#[derive(Default)]
25pub(crate) struct Presenter {
26 instances: Vec<Instance>,
27 glass: Vec<glass::Surface>,
28 materials: Vec<Material>,
29 previous: Vec<Matrix>,
30 previous_palettes: BTreeMap<usize, Vec<Matrix>>,
31 surfaces: Vec<InstanceSurface>,
32 last_view_projection: Option<Matrix>,
33 lens_camera: Option<Camera>,
34 cut: bool,
35 lit: u64,
36 exposed: u64,
37 touched: Touched,
38}
39
40#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
41pub(crate) struct Touched {
42 pub lights: bool,
43 pub finish: bool,
44 pub posed: bool,
45 pub sprites: bool,
46}
47
48pub(crate) fn cut(renderer: &mut Renderer) -> Result<(), PlayError> {
49 let (width, height) = renderer.size();
50 renderer.resize(width, height).map_err(PlayError::Render)
51}
52
53pub(crate) fn exposed(scene: &Scene, exposure: f32) -> Chain {
54 let mut chain = match &scene.finish {
55 Some(finish) => finish.chain.clone(),
56 None => Chain {
57 passes: vec![Pass::Bloom(Bloom::neutral(0.0)), Pass::Tone(Tone::aces())],
58 seed: 0,
59 frame: 0,
60 },
61 };
62 match chain.passes.first_mut() {
63 Some(Pass::Exposure(value)) => *value = exposure,
64 _ => chain.passes.insert(0, Pass::Exposure(exposure)),
65 }
66 chain
67}
68
69pub(crate) fn untouch(
70 scene: &Scene,
71 touched: Touched,
72 renderer: &mut Renderer,
73) -> Result<(), PlayError> {
74 if touched.lights {
75 renderer
76 .set_lights(&live_scene::local_lights(scene))
77 .map_err(PlayError::Render)?;
78 }
79 if touched.finish {
80 match &scene.finish {
81 Some(finish) => renderer.set_finish(finish.chain.clone()),
82 None => renderer.clear_finish(),
83 }
84 }
85 Ok(())
86}
87
88fn looked(world: &World, base: Material, look: &Look) -> Material {
89 let mut material = look
90 .material
91 .as_deref()
92 .and_then(|name| world.material(name))
93 .unwrap_or(base);
94 if let Some(color) = look.color {
95 material.base = color;
96 }
97 if let Some(emission) = look.emission {
98 material.emission = emission;
99 }
100 material
101}
102
103impl Presenter {
104 pub(crate) fn touched(&self) -> Touched {
105 self.touched
106 }
107
108 fn sync(&mut self, world: &World, renderer: &mut Renderer) -> Result<(), PlayError> {
109 if self.lit != world.lights_revision() {
110 let lights: Vec<_> = world
111 .lights()
112 .values()
113 .map(pfx_live::lights::local_light)
114 .collect();
115 renderer.set_lights(&lights).map_err(PlayError::Render)?;
116 self.lit = world.lights_revision();
117 self.touched.lights = true;
118 }
119 if self.exposed != world.exposure_revision() {
120 renderer.set_finish(exposed(world.scene(), world.exposure()));
121 self.exposed = world.exposure_revision();
122 self.touched.finish = true;
123 }
124 Ok(())
125 }
126
127 pub(crate) fn present<'a>(
128 &'a mut self,
129 world: &World,
130 staged: &'a Staged,
131 renderer: &mut Renderer,
132 aspect: f32,
133 time: f32,
134 seed: u32,
135 ) -> Result<PlayFrame<'a>, PlayError> {
136 if !self.cut {
137 cut(renderer)?;
138 self.cut = true;
139 }
140 self.sync(world, renderer)?;
141 let camera = world.fx.camera(&world.camera);
142 if self.lens_camera != Some(camera) {
143 renderer.set_lens(live_scene::lens(&camera, aspect));
144 self.lens_camera = Some(camera);
145 }
146 let posed = world.faced_models(&camera);
147 let draws = staged.draws();
148 let palettes = world.palettes();
149 let frames = world.sprite_frames();
150 let models = draws.models_posed(&posed, &palettes);
151 let mut skinned: Vec<(usize, usize)> = Vec::new();
152 self.surfaces.clear();
153 self.surfaces.extend_from_slice(staged.surfaces());
154 self.instances.clear();
155 self.instances.extend_from_slice(staged.instances());
156 self.materials.clear();
157 self.materials.extend_from_slice(staged.materials());
158 let edited = world.edited_materials();
159 if !edited.is_empty() {
160 for (slot, name) in self.materials.iter_mut().zip(&draws.names) {
161 if let Some(material) = edited.get(name) {
162 *slot = *material;
163 }
164 }
165 }
166 self.glass.clear();
167 let staged_glass = staged.glass();
168 let mut opaque = 0;
169 let mut glass_at = 0;
170 let mut made: BTreeMap<(usize, u32), u32> = BTreeMap::new();
171 for (index, draw) in draws.items.iter().enumerate() {
172 let model = models[index];
173 let previous = self.previous.get(index).copied().unwrap_or(model);
174 let object = draw
175 .owner
176 .filter(|&place| place < world.len())
177 .map(ObjectId::from_index);
178 let hidden = object.is_some_and(|id| world.hidden(id));
179 let look = object
180 .map(|id| world.look(id))
181 .filter(|look| !look.is_plain());
182 if draws.materials[draw.material as usize].family == Family::Glass {
183 if staged
184 .overrides()
185 .get(&draw.object)
186 .is_some_and(|change| change.hidden)
187 {
188 continue;
189 }
190 let Some(surface) = staged_glass.get(glass_at) else {
191 continue;
192 };
193 glass_at += 1;
194 if hidden {
195 continue;
196 }
197 let base = draws
198 .names
199 .get(draw.material as usize)
200 .and_then(|name| edited.get(name))
201 .copied()
202 .unwrap_or(surface.material);
203 let material = match look {
204 Some(look) => looked(world, base, look),
205 None => base,
206 };
207 self.glass.push(glass::Surface {
208 model,
209 material,
210 ..*surface
211 });
212 continue;
213 }
214 let Some(instance) = self.instances.get_mut(opaque) else {
215 continue;
216 };
217 if let Some(owner) = draw.owner {
218 if draw.geometry.skin.is_some() && palettes.contains_key(&owner) {
219 skinned.push((opaque, owner));
220 }
221 if let (Some(frame), Some(surface)) =
222 (frames.get(&owner), self.surfaces.get_mut(opaque))
223 {
224 let (offset, scale, crop) = sprite_surface(*frame);
225 surface.uv_offset = offset;
226 surface.uv_scale = scale;
227 surface.crop = crop;
228 }
229 }
230 opaque += 1;
231 instance.model = model;
232 instance.previous_model = previous;
233 if hidden {
234 instance.shadow_only = true;
235 instance.casts_shadow = false;
236 }
237 if let (Some(look), Some(id)) = (look, object) {
238 let key = (id.index(), instance.material);
239 instance.material = match made.get(&key) {
240 Some(&material) => material,
241 None => {
242 let base = self.materials[instance.material as usize];
243 let material = self.materials.len() as u32;
244 self.materials.push(looked(world, base, look));
245 made.insert(key, material);
246 material
247 }
248 };
249 }
250 }
251 self.previous = models;
252 let poses: Vec<InstancePose<'_>> = skinned
253 .iter()
254 .map(|(instance, owner)| {
255 let joints = &palettes[owner];
256 InstancePose {
257 instance: *instance,
258 joints,
259 previous: self
260 .previous_palettes
261 .get(owner)
262 .filter(|previous| previous.len() == joints.len())
263 .unwrap_or(joints),
264 }
265 })
266 .collect();
267 if !poses.is_empty() || self.touched.posed {
268 renderer.set_poses(&poses).map_err(PlayError::Render)?;
269 self.touched.posed = true;
270 }
271 drop(poses);
272 self.previous_palettes = palettes;
273 if !frames.is_empty() {
274 renderer
275 .set_surfaces(&self.surfaces)
276 .map_err(PlayError::Render)?;
277 self.touched.sprites = true;
278 }
279 let mut frame_camera = live_scene::camera(&camera, aspect);
280 let view_projection = multiply(frame_camera.projection, frame_camera.view);
281 if let Some(last) = self.last_view_projection {
282 frame_camera.previous_view_projection = last;
283 }
284 self.last_view_projection = Some(view_projection);
285 let mut text = staged.text(aspect);
286 let rest = staged.camera();
287 if rest != camera {
288 let before = multiply(rest.projection(aspect), rest.view());
289 if let Some(undo) = invert(before) {
290 let fix = multiply(view_projection, undo);
291 for item in &mut text.surface_quads {
292 match &mut item.space {
293 TextSpace::Surface {
294 model_view_projection,
295 } => *model_view_projection = multiply(fix, *model_view_projection),
296 TextSpace::LitSurface {
297 model_view_projection,
298 model,
299 } => *model_view_projection = multiply(view_projection, *model),
300 _ => {}
301 }
302 }
303 }
304 }
305 Ok(PlayFrame {
306 scene: FrameScene {
307 camera: frame_camera,
308 time,
309 seed,
310 sun: live_scene::sun(&staged.sun()),
311 instances: &self.instances,
312 materials: &self.materials,
313 deformers: &[],
314 wind: SceneWind::default(),
315 },
316 text,
317 effects: Effects {
318 glass: &self.glass,
319 ..Effects::default()
320 },
321 })
322 }
323}