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}