Skip to main content

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