mirage_engine/context.rs
1use core::time::Duration;
2use std::collections::HashMap;
3#[cfg(feature = "ui")]
4use std::sync::Arc;
5
6#[cfg(feature = "ui")]
7use crate::Error;
8use crate::animation::{AnimationStates, Animator};
9use crate::assets::Assets;
10#[cfg(feature = "ui")]
11use crate::assets::font;
12use crate::input::{
13 Axis2Binding, AxisBinding, ButtonBinding, Cursor, InputAction, InputAxis2Action,
14 InputAxisAction, InputButtonAction, Queries, Ticking,
15};
16use crate::math::{UVec2, Vec2};
17use crate::mesh::{Instance, Mesh, Part};
18use crate::post_effect::{PostEffect, PostEffectId, PostEffects};
19use crate::renderer::draw_list::DrawList;
20use crate::renderer::mesh_cache::MeshCatalog;
21use crate::renderer::skybox::SkyCatalog;
22use crate::save::{SaveKey, Saved};
23use crate::sound::{SoundCue, Sounding};
24use crate::surface_style::{SurfaceStyle, SurfaceStyleId, SurfaceStyles};
25use crate::time::{FrameTime, TickInterval};
26use crate::ui::{Building, Claims, Layer};
27use crate::{Camera, Config, Game, Holds, Light, Seats, View};
28
29/// The work the startup closure [`run`](crate::run) takes may do.
30pub struct InitContext<'a, G: Game> {
31 startup: Startup<'a>,
32 meshes: &'a mut MeshCatalog<G::Meshes>,
33 audio: &'a mut Sounding<G::Sounds>,
34}
35
36impl<'a, G: Game> InitContext<'a, G> {
37 pub(crate) fn new(
38 engine: Engine<'a>,
39 meshes: &'a mut MeshCatalog<G::Meshes>,
40 audio: &'a mut Sounding<G::Sounds>,
41 saves: &'a Saved,
42 assets: &'a Assets,
43 ui: &'a Layer,
44 ) -> Self {
45 Self {
46 startup: Startup::new(engine, saves, assets, ui),
47 meshes,
48 audio,
49 }
50 }
51
52 /// The startup work that is typed by no vocabulary of the game's own.
53 ///
54 /// Required if you want to start two games the same way: `Startup` is
55 /// one type whatever the game, so code shared between them takes
56 /// `&mut Startup<'_>`.
57 pub fn startup(&mut self) -> &mut Startup<'a> {
58 &mut self.startup
59 }
60
61 /// How long `sound` plays for at its own pitch: the whole clip, before
62 /// any trim.
63 ///
64 /// Required if you want to time a game against a sound. Every value the
65 /// vocabulary catalogs is built before this runs, and a streamed one
66 /// reports what the decode at startup measured.
67 pub fn duration(&mut self, sound: G::Sounds) -> Duration {
68 self.audio.duration(&sound)
69 }
70
71 /// How long each value that the vocabulary catalogs plays for, keyed by the
72 /// value.
73 ///
74 /// Required if you want to time a game against a whole vocabulary. A
75 /// value the catalog leaves out is absent from the map; read that one
76 /// through [`duration`](Self::duration).
77 pub fn durations(&mut self) -> HashMap<G::Sounds, Duration> {
78 self.audio.durations()
79 }
80
81 /// Builds and uploads `mesh` now, instead of on its first draw; the
82 /// copy is then held like any drawn mesh's under
83 /// [`Config::with_mesh_memory`], and no longer than that.
84 ///
85 /// Takes a mesh of [`Game::Meshes`](crate::Game::Meshes) and no other.
86 pub fn prepare<M>(&mut self, mesh: M)
87 where
88 G::Meshes: Holds<M>,
89 {
90 self.meshes.prepare(mesh.into());
91 }
92}
93
94/// The part of [`InitContext`] that is typed by no vocabulary of the game's
95/// own, which [`InitContext::startup`] returns.
96pub struct Startup<'a> {
97 engine: Engine<'a>,
98 saves: &'a Saved,
99 #[cfg(feature = "ui")]
100 assets: &'a Assets,
101 #[cfg(feature = "ui")]
102 ui: &'a Layer,
103}
104
105impl<'a> Startup<'a> {
106 /// What a startup reads: the values a run saved, the store its sources
107 /// loaded into, and the UI.
108 #[cfg(feature = "ui")]
109 pub(crate) fn new(
110 engine: Engine<'a>,
111 saves: &'a Saved,
112 assets: &'a Assets,
113 ui: &'a Layer,
114 ) -> Self {
115 Self {
116 engine,
117 saves,
118 assets,
119 ui,
120 }
121 }
122
123 /// The same without the UI, which is the one reader of a font.
124 #[cfg(not(feature = "ui"))]
125 pub(crate) fn new(
126 engine: Engine<'a>,
127 saves: &'a Saved,
128 _assets: &'a Assets,
129 _ui: &'a Layer,
130 ) -> Self {
131 Self { engine, saves }
132 }
133
134 /// The value the last run to save `key` kept, or its fallback where
135 /// none did, or where what was kept no longer reads as the key's own
136 /// value, with a debug log.
137 pub fn saved<K: SaveKey>(&self, key: K) -> K::Value {
138 self.saves.read(key)
139 }
140
141 /// The window's drawing area, in physical pixels; zero while minimized.
142 pub fn window_size(&self) -> UVec2 {
143 self.engine.window_size
144 }
145
146 /// The configuration the engine started with.
147 pub fn config(&self) -> &Config {
148 self.engine.config
149 }
150
151 /// The font a source loaded under `name`, to name in an
152 /// `egui::FontDefinitions`.
153 ///
154 /// Required if you want the UI to draw in a game's own font: a source is
155 /// a `.ttf` or an `.otf` [`Config::with_assets`] loads, named by its
156 /// stem. A name no source loaded a font under, or one two sources share,
157 /// is an error. The `ui` feature's own.
158 #[cfg(feature = "ui")]
159 pub fn font(&self, name: &str) -> Result<egui::FontData, Error> {
160 let bytes = self.assets.font(name)?;
161
162 Ok(egui::FontData::from_owned(bytes.to_vec()))
163 }
164
165 /// Draws every frame's UI in `fonts`, from the first frame on.
166 ///
167 /// Required if you want the UI to draw in a game's own font. Fails,
168 /// naming the font, where an entry of `font_data` does not decode at its
169 /// own index, and where a family lists a name `font_data` does not hold.
170 /// egui's own fonts stay wherever `fonts` keeps them, and the last call
171 /// is what draws. The `ui` feature's own.
172 #[cfg(feature = "ui")]
173 pub fn set_fonts(&mut self, fonts: egui::FontDefinitions) -> Result<(), Error> {
174 for (name, data) in &fonts.font_data {
175 font::decode_at(&data.font, data.index)
176 .map_err(|error| Error::msg(format!("the font `{name}` {error}")))?;
177 }
178 for (family, names) in &fonts.families {
179 for name in names {
180 if !fonts.font_data.contains_key(name) {
181 return Err(Error::msg(format!(
182 "the font family `{family}` lists `{name}`, which `font_data` does \
183 not hold"
184 )));
185 }
186 }
187 }
188 self.ui.set_fonts(fonts);
189
190 Ok(())
191 }
192}
193
194/// The work [`Game::tick`](crate::Game::tick) may do: simulate, never draw.
195pub struct TickContext<'a, G: Game> {
196 engine: Engine<'a>,
197 meshes: &'a mut MeshCatalog<G::Meshes>,
198 audio: &'a mut Sounding<G::Sounds>,
199 ticking: &'a Ticking<'a>,
200 saves: &'a mut Saved,
201 run: &'a mut Run,
202 dt: Duration,
203 /// The run clock at the frame these ticks belong to, which every draw
204 /// of that frame is posed at too.
205 elapsed: Duration,
206 claims: Claims,
207}
208
209impl<'a, G: Game> TickContext<'a, G> {
210 /// Whether `action` is held right now.
211 ///
212 /// Every tick of one drawn frame reads the same controls.
213 pub fn down<A: InputButtonAction>(&self, action: A) -> bool
214 where
215 G::InputActions: Seats<A, A::Binding>,
216 {
217 self.ticking.down(action)
218 }
219
220 /// Whether `action` went down since the last frame whose ticks ran.
221 ///
222 /// A frame that runs no ticks holds its edges for the ticks that follow,
223 /// so every press is read by the ticks of exactly one frame.
224 pub fn pressed<A: InputButtonAction>(&self, action: A) -> bool
225 where
226 G::InputActions: Seats<A, A::Binding>,
227 {
228 self.ticking.pressed(action)
229 }
230
231 /// Whether `action` came up since the last frame whose ticks ran.
232 ///
233 /// A release is held for the ticks that follow, the same as a press.
234 pub fn released<A: InputButtonAction>(&self, action: A) -> bool
235 where
236 G::InputActions: Seats<A, A::Binding>,
237 {
238 self.ticking.released(action)
239 }
240
241 /// Presses of `action` in a row, counting the one these ticks read:
242 /// `1` for a single click, `2` for a double, `0` where they read no
243 /// press; see [`FrameContext::clicks`].
244 ///
245 /// The ticks of one frame read one press however many landed in them,
246 /// so a control pressed twice inside one frame reads one press of two
247 /// clicks.
248 pub fn clicks<A: InputButtonAction>(&self, action: A) -> u32
249 where
250 G::InputActions: Seats<A, A::Binding>,
251 {
252 self.ticking.clicks(action)
253 }
254
255 /// Analog reading of `action`: a fraction in `-1..=1` from a pad axis,
256 /// a joystick axis or a button composite, of which a trigger reads
257 /// `0..=1`, and the scaled distance, which nothing clamps, from a
258 /// [`PointerDelta`](crate::PointerDelta) or
259 /// [`WheelDelta`](crate::WheelDelta) lane.
260 ///
261 /// Read those two in [`Game::frame`](crate::Game::frame): the ticks of
262 /// one frame each read the whole distance that frame moved.
263 pub fn axis<A: InputAxisAction>(&self, action: A) -> f32
264 where
265 G::InputActions: Seats<A, A::Binding>,
266 {
267 self.ticking.axis(action)
268 }
269
270 /// `action`'s reading: a vector no longer than `1` from a stick or a
271 /// button composite, and the scaled distance, which nothing clamps,
272 /// from [`Axis2Binding::pointer`].
273 ///
274 /// Read the pointer in [`Game::frame`](crate::Game::frame): the ticks
275 /// of one frame each read the whole distance that frame moved.
276 pub fn axis2<A: InputAxis2Action>(&self, action: A) -> Vec2
277 where
278 G::InputActions: Seats<A, A::Binding>,
279 {
280 self.ticking.axis2(action)
281 }
282
283 /// Pointer position, in physical pixels from the drawing area's top
284 /// left; the origin until it is first seen.
285 ///
286 /// The mouse and the first touch share it, and
287 /// [`window_size`](Self::window_size) is in the same pixels, so
288 /// [`Camera::ray_through`] takes it as it is.
289 pub fn pointer(&self) -> Vec2 {
290 self.ticking.pointer()
291 }
292
293 /// Plays `sound` once, keeping wherever it is placed as of this tick.
294 ///
295 /// Every call is a voice of its own, so the same sound twice over is
296 /// heard twice; the ticks of one frame are played together at the end
297 /// of it.
298 pub fn play(&mut self, sound: impl Into<SoundCue<G::Sounds>>) {
299 self.audio.play(sound.into());
300 }
301
302 /// The value the last run to save `key` kept, or its fallback where
303 /// none did, or where what was kept no longer reads as the key's own
304 /// value, with a debug log.
305 pub fn saved<K: SaveKey>(&self, key: K) -> K::Value {
306 self.saves.read(key)
307 }
308
309 /// Keeps `value` under `key`, for the rest of this run and the runs
310 /// after it.
311 ///
312 /// The store is written once the frame these ticks belong to is drawn,
313 /// and only where a value changed, so saving every tick costs nothing.
314 pub fn save<K: SaveKey>(&mut self, key: K, value: K::Value) {
315 self.saves.write(key, value);
316 }
317
318 /// Whether the platform allows sound to start right now; see
319 /// [`FrameContext::sound_unlocked`].
320 pub fn sound_unlocked(&self) -> bool {
321 self.engine.sound_unlocked
322 }
323
324 /// Runs `animator` up to this tick against `input`, over the clips
325 /// `mesh` holds: where its state goes from here, and what the state it
326 /// lands in plays.
327 ///
328 /// Takes a mesh of [`Game::Meshes`](crate::Game::Meshes) and a machine
329 /// typed by that mesh, so a machine runs on the clips of the value the
330 /// game draws and no other. Every tick of one drawn
331 /// frame runs at one instant, as every one of them reads one snapshot
332 /// of the controls, and the frame draws at that same instant.
333 pub fn animate<M, P, S>(&mut self, mesh: M, animator: &mut Animator<M, S>, input: &S::Input)
334 where
335 G::Meshes: Holds<M>,
336 M: Mesh<P, S::Clip>,
337 P: Part,
338 S: AnimationStates,
339 {
340 let now = self.elapsed;
341 animator.animate(input, now, self.meshes.clips(mesh));
342 }
343
344 /// This tick's fixed time step: [`Config::tick_interval`] until
345 /// [`set_tick_interval`](Self::set_tick_interval) changes it.
346 pub fn dt(&self) -> Duration {
347 self.dt
348 }
349
350 /// Sets the simulated time every later tick covers; see
351 /// [`FrameContext::set_tick_interval`].
352 pub fn set_tick_interval(&mut self, interval: Duration) {
353 self.run.tick_interval.set(interval);
354 }
355
356 /// Ends the run once the frame these ticks belong to is drawn; see
357 /// [`FrameContext::close`].
358 pub fn close(&mut self) {
359 self.run.closing = true;
360 }
361
362 /// Whether the UI took the pointer last frame. Always false without the
363 /// `ui` feature.
364 pub fn ui_wants_pointer(&self) -> bool {
365 self.claims.pointer
366 }
367
368 /// Whether the UI took the keyboard last frame. Always false without the
369 /// `ui` feature.
370 pub fn ui_wants_keyboard(&self) -> bool {
371 self.claims.keyboard
372 }
373
374 /// The window's drawing area, in physical pixels; zero while minimized.
375 pub fn window_size(&self) -> UVec2 {
376 self.engine.window_size
377 }
378
379 /// The camera the last drawn frame was viewed from; [`Camera::default`]
380 /// before the first frame.
381 ///
382 /// Required if you want a ray through a pixel: the player points at what
383 /// was last drawn.
384 pub fn last_camera(&self) -> Camera {
385 self.engine.last_camera
386 }
387
388 /// The configuration the engine started with.
389 pub fn config(&self) -> &Config {
390 self.engine.config
391 }
392}
393
394/// The work [`Game::frame`](crate::Game::frame) may do.
395pub struct FrameContext<'a, G: Game> {
396 engine: Engine<'a>,
397 draws: &'a mut DrawList,
398 meshes: &'a mut MeshCatalog<G::Meshes>,
399 skies: &'a mut SkyCatalog<G::Skyboxes>,
400 audio: &'a mut Sounding<G::Sounds>,
401 input: &'a mut Queries,
402 saves: &'a mut Saved,
403 run: &'a mut Run,
404 time: FrameTime,
405 layer: Building<'a>,
406}
407
408impl<'a, G: Game> FrameContext<'a, G> {
409 /// Whether `action` is held right now.
410 pub fn down<A: InputButtonAction>(&self, action: A) -> bool
411 where
412 G::InputActions: Seats<A, A::Binding>,
413 {
414 self.input.down(action)
415 }
416
417 /// Whether `action` went down during this frame.
418 pub fn pressed<A: InputButtonAction>(&self, action: A) -> bool
419 where
420 G::InputActions: Seats<A, A::Binding>,
421 {
422 self.input.pressed(action)
423 }
424
425 /// Whether `action` came up during this frame.
426 pub fn released<A: InputButtonAction>(&self, action: A) -> bool
427 where
428 G::InputActions: Seats<A, A::Binding>,
429 {
430 self.input.released(action)
431 }
432
433 /// Presses of `action` in a row, counting this frame's: `1` for a
434 /// single click, `2` for a double, and `0` on a frame where `action`
435 /// was not pressed.
436 ///
437 /// A press counts with the one before it where the same control took
438 /// both, no later than the double click interval after it — the
439 /// platform's own until
440 /// [`Config::with_double_click_interval`](crate::Config::with_double_click_interval)
441 /// sets one. The engine counts one control at a time, so an action
442 /// whose press lands in the same frame as another control's reads `0`
443 /// where the count is on that other one. A headless session counts
444 /// against the clock its caller drives, so presses at one instant of it
445 /// count together.
446 pub fn clicks<A: InputButtonAction>(&self, action: A) -> u32
447 where
448 G::InputActions: Seats<A, A::Binding>,
449 {
450 self.input.clicks(action)
451 }
452
453 /// Analog reading of `action`: a fraction in `-1..=1` from a pad axis,
454 /// a joystick axis or a button composite, of which a trigger reads
455 /// `0..=1`, and the scaled distance, which nothing clamps, from a
456 /// [`PointerDelta`](crate::PointerDelta) or
457 /// [`WheelDelta`](crate::WheelDelta) lane.
458 pub fn axis<A: InputAxisAction>(&self, action: A) -> f32
459 where
460 G::InputActions: Seats<A, A::Binding>,
461 {
462 self.input.axis(action)
463 }
464
465 /// `action`'s reading: a vector no longer than `1` from a stick or a
466 /// button composite, and the scaled distance, which nothing clamps,
467 /// from [`Axis2Binding::pointer`].
468 pub fn axis2<A: InputAxis2Action>(&self, action: A) -> Vec2
469 where
470 G::InputActions: Seats<A, A::Binding>,
471 {
472 self.input.axis2(action)
473 }
474
475 /// Pointer position, in physical pixels from the drawing area's top
476 /// left; the origin until it is first seen.
477 ///
478 /// The mouse and the first touch share it, and
479 /// [`window_size`](Self::window_size) is in the same pixels, so
480 /// [`Camera::ray_through`] takes it as it is.
481 pub fn pointer(&self) -> Vec2 {
482 self.input.pointer()
483 }
484
485 /// Draws the pointer as `cursor` this frame; the last call in a frame
486 /// is the one it draws.
487 ///
488 /// A frame that never calls this draws it as [`Cursor::Arrow`]. Where
489 /// the UI sets a cursor of its own, the UI's is drawn instead.
490 ///
491 /// [`Cursor::Held`] holds the pointer in place, and the UI's own
492 /// cursor does not take `Held` over: [`pointer`](Self::pointer) reads
493 /// the place it was held at, a [`PointerDelta`](crate::PointerDelta)
494 /// binding keeps reading how far it moves, and the first frame to set
495 /// another cursor releases it. A browser takes the pointer lock only from
496 /// inside a gesture of the player's, so there the hold is taken on the
497 /// player's next press or touch. A window loses the hold as it loses
498 /// focus, and takes it again on the first frame to set `Held` after the
499 /// focus returns.
500 pub fn set_cursor(&mut self, cursor: Cursor) {
501 *self.layer.cursor = cursor;
502 }
503
504 /// Binds `action` to `bindings` for the rest of the run, and keeps it
505 /// for the runs after that — written when the frame ends, and only
506 /// when these bindings are not already what `action` is bound to.
507 ///
508 /// The kind of binding follows the action, so a stick cannot be bound to
509 /// a button.
510 pub fn rebind<A: InputAction>(&mut self, action: A, bindings: Vec<A::Binding>)
511 where
512 G::InputActions: Seats<A, A::Binding>,
513 {
514 self.input.rebind(action, bindings);
515 }
516
517 /// The bindings `action` reads through right now, which a controls menu
518 /// shows through each binding's text.
519 pub fn bindings<A: InputAction>(&self, action: A) -> Vec<A::Binding>
520 where
521 G::InputActions: Seats<A, A::Binding>,
522 {
523 self.input.bindings(action)
524 }
525
526 /// The button control the player pressed this frame, for a controls menu
527 /// listening for one to bind.
528 ///
529 /// Nothing where the player pressed nothing new; polling is the whole
530 /// mechanism, so a menu that stops calling this stops listening.
531 pub fn actuated_button(&self) -> Option<ButtonBinding> {
532 self.input.actuated_button()
533 }
534
535 /// The analog control the player pushed this frame, past the deadzone a
536 /// binding starts with.
537 ///
538 /// The pointer and the wheel are never returned: they would take the
539 /// smallest nudge for a choice.
540 pub fn actuated_axis(&self) -> Option<AxisBinding> {
541 self.input.actuated_axis()
542 }
543
544 /// The stick the player pushed this frame, past the deadzone a binding
545 /// starts with.
546 pub fn actuated_axis2(&self) -> Option<Axis2Binding> {
547 self.input.actuated_axis2()
548 }
549
550 /// Duration of the previous frame: this frame's own variable time
551 /// step, distinct from the fixed one `tick` runs at.
552 pub fn dt(&self) -> Duration {
553 self.time.dt
554 }
555
556 /// Duration the game has been running.
557 pub fn elapsed(&self) -> Duration {
558 self.time.elapsed
559 }
560
561 /// This frame's position into the next simulation step, a fraction in
562 /// `0.0..1.0`; used to draw between two tick states.
563 pub fn alpha(&self) -> f32 {
564 self.time.alpha
565 }
566
567 /// Sets the simulated time every later tick covers, from the next frame
568 /// on; held to at least `Duration::from_micros(1)`.
569 ///
570 /// Required if you want to pace the simulation against something outside
571 /// the engine, such as a program on another machine. The ticks a frame
572 /// already runs keep the step they started with.
573 pub fn set_tick_interval(&mut self, interval: Duration) {
574 self.run.tick_interval.set(interval);
575 }
576
577 /// Ends the run once this frame is drawn: what the frame saved is
578 /// written, and no tick or frame runs after it.
579 ///
580 /// On the desktop the window closes and [`run`](crate::run) returns. In
581 /// the browser there is no program to end: the loop stops, and the
582 /// canvas the engine created is dropped from the page, while one the
583 /// game named through [`Config::with_canvas_id`] stays as the page left
584 /// it.
585 pub fn close(&mut self) {
586 self.run.closing = true;
587 }
588
589 /// Views the rest of the frame from `camera`. A later call in the same
590 /// frame replaces this one; without any, [`Camera::default`] is used.
591 pub fn set_camera(&mut self, camera: Camera) {
592 self.draws.set_camera(camera);
593 }
594
595 /// Draws `instance` this frame. The engine decides the order and which
596 /// draws share GPU work.
597 ///
598 /// Takes a draw of a mesh of [`Game::Meshes`](crate::Game::Meshes) and
599 /// no other.
600 pub fn draw<M>(&mut self, instance: Instance<M, G::SurfaceStyles>)
601 where
602 G::Meshes: Holds<M>,
603 {
604 let draw = instance.record().into_set();
605 let id = self.meshes.id_of(draw.mesh());
606 self.draws.push(draw.keyed(id));
607 }
608
609 /// Passes the style `T` the values its WGSL reads this frame; the last
610 /// call for a style is the one it reads.
611 ///
612 /// A frame that never calls this for a style leaves it reading the
613 /// default value of every field. Takes a style of
614 /// [`Game::SurfaceStyles`](crate::Game::SurfaceStyles) and no other.
615 pub fn set_surface_style<T: SurfaceStyle>(&mut self, style: T)
616 where
617 G::SurfaceStyles: Holds<T>,
618 {
619 let style = G::SurfaceStyles::from(style);
620 self.draws
621 .set_surface_style(SurfaceStyleId(style.seat()), |into| style.write(into));
622 }
623
624 /// Runs the post effect `T` over this frame with the values its WGSL
625 /// reads; the last call for an effect is the one it runs with.
626 ///
627 /// A frame that never calls this for an effect runs no pass for it.
628 /// Takes an effect of
629 /// [`Game::PostEffects`](crate::Game::PostEffects) and no other.
630 pub fn set_post_effect<T: PostEffect>(&mut self, effect: T)
631 where
632 G::PostEffects: Holds<T>,
633 {
634 let effect = G::PostEffects::from(effect);
635 self.draws
636 .set_post_effect(PostEffectId(effect.seat()), |into| effect.write(into));
637 }
638
639 /// Draws and lights this frame by `sky`: what it draws where nothing
640 /// else was drawn, and the ambient — the light every surface takes from
641 /// every direction.
642 ///
643 /// Takes a value of [`Game::Skyboxes`](crate::Game::Skyboxes) and no
644 /// other; startup built every one of them. The last call in a frame is
645 /// the one it draws, and a frame that never calls this draws and is lit
646 /// by the default sky.
647 pub fn set_skybox(&mut self, sky: G::Skyboxes) {
648 self.draws.set_skybox(self.skies.id(&sky));
649 }
650
651 /// Lights the frame with `light`, in addition to any already submitted.
652 ///
653 /// The first call replaces the default environment's light; past
654 /// [`MAX_LIGHTS`](crate::MAX_LIGHTS), excess is ignored — warned the
655 /// first frame, a debug log after.
656 pub fn light(&mut self, light: Light) {
657 self.draws.push_light(light);
658 }
659
660 /// Scales the frame's light before the curve, as a fraction of it; a
661 /// value under `0.0` is clamped to it, and `1.0` is used where a frame
662 /// never calls this.
663 ///
664 /// The last call in a frame replaces the rest.
665 pub fn set_exposure(&mut self, exposure: f32) {
666 self.draws.set_exposure(exposure);
667 }
668
669 /// Spreads the frame's brightest light over what is around it; the
670 /// value is clamped into `0.0..=1.0`, and `0.0` is used where a frame
671 /// never calls this.
672 ///
673 /// The value is the fraction of the frame the spread replaces, and `0.0`
674 /// is no work at all. The last call in a frame replaces the rest.
675 pub fn set_bloom(&mut self, amount: f32) {
676 self.draws.set_bloom(amount);
677 }
678
679 /// Plays `sound` once, keeping wherever it is placed as of this frame.
680 ///
681 /// Every call is a voice of its own, so the same sound twice over is
682 /// heard twice.
683 pub fn play(&mut self, sound: impl Into<SoundCue<G::Sounds>>) {
684 self.audio.play(sound.into());
685 }
686
687 /// Keeps `sound` playing while frames go on declaring it, and fades it
688 /// out over its fade once one does not.
689 ///
690 /// What a frame declares is the whole of what it wants sounding. One
691 /// voice per value, whose knobs follow what each frame declares; the
692 /// last call for a value in a frame is the one that counts. A value a
693 /// frame stops declaring is dropped once it has faded, so declaring it
694 /// again after that starts it at its window start.
695 pub fn sustain(&mut self, sound: impl Into<SoundCue<G::Sounds>>) {
696 self.audio.sustain(sound.into());
697 }
698
699 /// Hears the frame from `listener`, in place of the frame's camera.
700 pub fn set_listener(&mut self, listener: View) {
701 self.audio.set_listener(listener);
702 }
703
704 /// Plays everything this frame at `volume`, the fraction of each
705 /// sound's own gain it multiplies; `1.0` where a frame never calls this.
706 ///
707 /// The mix slides to it over [`SoundCue::DEFAULT_GLIDE`], so a slider a
708 /// player moves never steps the sound.
709 pub fn set_volume(&mut self, volume: f32) {
710 self.audio.set_volume(volume);
711 }
712
713 /// Whether the platform allows sound to start right now.
714 ///
715 /// True from the first frame on the desktop, with or without an audio
716 /// device: what holds it false is the browser, which plays nothing until
717 /// the player has done something. A one-shot played while it is false is
718 /// dropped; a sustain declared then starts when it turns true.
719 pub fn sound_unlocked(&self) -> bool {
720 self.engine.sound_unlocked
721 }
722
723 /// The value the last run to save `key` kept, or its fallback where
724 /// none did, or where what was kept no longer reads as the key's own
725 /// value, with a debug log.
726 pub fn saved<K: SaveKey>(&self, key: K) -> K::Value {
727 self.saves.read(key)
728 }
729
730 /// Keeps `value` under `key`, for the rest of this run and the runs
731 /// after it.
732 ///
733 /// The store is written once the frame is drawn, and only where a value
734 /// changed, so saving every frame costs nothing.
735 pub fn save<K: SaveKey>(&mut self, key: K, value: K::Value) {
736 self.saves.write(key, value);
737 }
738
739 /// Builds this frame's UI, drawn over the scene.
740 ///
741 /// Calls append to one layer, which is placed `8` points clear of the
742 /// window's edges; floating windows go through `ui.ctx()`, and
743 /// `egui::Panel::left` and the three beside it hold a panel against one
744 /// side of that layer, shown in the `ui` this call takes.
745 #[cfg(feature = "ui")]
746 pub fn ui(&mut self, build: impl FnOnce(&mut egui::Ui)) {
747 build(&mut *self.layer.ui);
748 }
749
750 /// Physical pixels per logical point of the UI this frame, a fraction
751 /// over `1.0` on a dense screen: what a pixel [`Camera::pixel_of`]
752 /// returns is divided by before the UI draws at it.
753 #[cfg(feature = "ui")]
754 pub fn pixels_per_point(&self) -> f32 {
755 self.layer.pixels_per_point
756 }
757
758 /// `text` laid out in `font` at no width, so a row ends only where a
759 /// `\n` starts the next one.
760 ///
761 /// Required if you want to size or place what you draw against text: a
762 /// box a name has to fit in, a line as wide as the word over it. Its
763 /// `size()` is the width and the height the text takes, in logical
764 /// points. One kept past a change of
765 /// [`pixels_per_point`](Self::pixels_per_point) still reports the size
766 /// the frame that laid it out measured. The `ui` feature's own.
767 #[cfg(feature = "ui")]
768 pub fn text_layout(&self, text: &str, font: egui::FontId) -> Arc<egui::Galley> {
769 self.layer.ui.ctx().fonts_mut(|fonts| {
770 fonts.layout_no_wrap(text.to_owned(), font, egui::Color32::PLACEHOLDER)
771 })
772 }
773
774 /// Whether the UI took the pointer last frame. Always false without the
775 /// `ui` feature.
776 pub fn ui_wants_pointer(&self) -> bool {
777 self.layer.claims.pointer
778 }
779
780 /// Whether the UI took the keyboard last frame. Always false without the
781 /// `ui` feature.
782 pub fn ui_wants_keyboard(&self) -> bool {
783 self.layer.claims.keyboard
784 }
785
786 /// The window's drawing area, in physical pixels; zero while minimized.
787 pub fn window_size(&self) -> UVec2 {
788 self.engine.window_size
789 }
790
791 /// The camera the last drawn frame was viewed from; [`Camera::default`]
792 /// before the first frame.
793 ///
794 /// Required if you want a ray through a pixel: the player points at what
795 /// was last drawn, not at what this frame has set since.
796 pub fn last_camera(&self) -> Camera {
797 self.engine.last_camera
798 }
799
800 /// The configuration the engine started with.
801 pub fn config(&self) -> &Config {
802 self.engine.config
803 }
804
805 /// Builds and uploads `mesh` now, instead of on its first draw; the
806 /// copy is then held like any drawn mesh's under
807 /// [`Config::with_mesh_memory`], and no longer than that.
808 ///
809 /// Takes a mesh of [`Game::Meshes`](crate::Game::Meshes) and no other.
810 pub fn prepare<M>(&mut self, mesh: M)
811 where
812 G::Meshes: Holds<M>,
813 {
814 self.meshes.prepare(mesh.into());
815 }
816}
817
818/// Everything a tick is recorded against: what it plays through, keeps
819/// in, and the run it paces and ends.
820pub(crate) struct Simulating<'a, G: Game> {
821 pub(crate) audio: &'a mut Sounding<G::Sounds>,
822 pub(crate) saves: &'a mut Saved,
823 pub(crate) run: &'a mut Run,
824}
825
826impl<'a, G: Game> Simulating<'a, G> {
827 /// The context one tick of `dt` runs with, reading `ticking`'s controls
828 /// and running every machine it is passed at `elapsed` on the run
829 /// clock.
830 pub(crate) fn tick_context(
831 self,
832 engine: Engine<'a>,
833 meshes: &'a mut MeshCatalog<G::Meshes>,
834 ticking: &'a Ticking<'a>,
835 dt: Duration,
836 elapsed: Duration,
837 claims: Claims,
838 ) -> TickContext<'a, G> {
839 let Self { audio, saves, run } = self;
840 TickContext {
841 engine,
842 meshes,
843 audio,
844 ticking,
845 saves,
846 run,
847 dt,
848 elapsed,
849 claims,
850 }
851 }
852}
853
854/// Everything a frame is recorded against: what a tick is, and what it
855/// draws into, keys its meshes and skies through, and reads its controls
856/// from.
857pub(crate) struct Recording<'a, G: Game> {
858 pub(crate) draws: &'a mut DrawList,
859 pub(crate) meshes: &'a mut MeshCatalog<G::Meshes>,
860 pub(crate) skies: &'a mut SkyCatalog<G::Skyboxes>,
861 pub(crate) input: &'a mut Queries,
862 pub(crate) simulating: Simulating<'a, G>,
863}
864
865impl<'a, G: Game> Recording<'a, G> {
866 /// The context one frame at `time` runs with, building its UI in
867 /// `layer`.
868 ///
869 /// The frame starts at the instant `time` reads, so every draw it
870 /// records is posed at that one instant.
871 pub(crate) fn frame_context(
872 self,
873 engine: Engine<'a>,
874 time: FrameTime,
875 layer: Building<'a>,
876 ) -> FrameContext<'a, G> {
877 let Self {
878 draws,
879 meshes,
880 skies,
881 input,
882 simulating: Simulating { audio, saves, run },
883 } = self;
884 draws.start(time.elapsed);
885
886 FrameContext {
887 engine,
888 draws,
889 meshes,
890 skies,
891 audio,
892 input,
893 saves,
894 run,
895 time,
896 layer,
897 }
898 }
899}
900
901/// What a game changes about the run itself: how long its ticks are, and
902/// whether it goes on.
903pub(crate) struct Run {
904 tick_interval: TickInterval,
905 closing: bool,
906}
907
908impl Run {
909 /// A run that ticks every `tick_interval` until the game closes it.
910 pub(crate) fn new(tick_interval: Duration) -> Self {
911 Self {
912 tick_interval: TickInterval::new(tick_interval),
913 closing: false,
914 }
915 }
916
917 /// Starts a batch of ticks, and returns the step each one takes.
918 pub(crate) fn start_ticks(&mut self) -> Duration {
919 self.tick_interval.advance();
920 self.tick_interval.current()
921 }
922
923 /// The step the ticks running now take.
924 pub(crate) fn tick_interval(&self) -> Duration {
925 self.tick_interval.current()
926 }
927
928 /// Whether the game has requested that the run end.
929 pub(crate) fn closing(&self) -> bool {
930 self.closing
931 }
932}
933
934/// Everything every context uses: the area being drawn to, the settings the
935/// engine started with, the camera the last frame was drawn from, and
936/// whether the platform allows sound to start. Nothing of it reaches the
937/// device.
938pub(crate) struct Engine<'a> {
939 window_size: UVec2,
940 config: &'a Config,
941 last_camera: Camera,
942 sound_unlocked: bool,
943}
944
945impl<'a> Engine<'a> {
946 pub(crate) fn new(
947 window_size: UVec2,
948 config: &'a Config,
949 last_camera: Camera,
950 sound_unlocked: bool,
951 ) -> Self {
952 Self {
953 window_size,
954 config,
955 last_camera,
956 sound_unlocked,
957 }
958 }
959}