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, 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}