Skip to main content

mirage_engine/
lib.rs

1//! An immediate-mode `3D` engine for simple games: implement [`Game`] and
2//! start the engine with [`run`]. See `examples/breakout-game.rs`.
3//!
4//! Coordinates are right-handed with `+Y` up and cameras looking down `−Z`;
5//! time is seconds, and colors are linear `f32`, encoded to sRGB on screen.
6
7#![warn(missing_docs)]
8
9use core::fmt;
10use core::time::Duration;
11
12pub use glam as math;
13
14/// The parallel iterators a game writes, which run on the workers the engine
15/// builds at startup; a game declares no version of its own. Parallel work
16/// is the few games' own, so the engine's prelude carries none of this: a
17/// game that writes it names this module's prelude in a `use` of its own.
18///
19/// A parallel sum over `f32` values adds them in whatever order the workers
20/// finish in, so it reads different bits run to run. A fold over fixed
21/// chunks reads the same bits at any worker count and on either target:
22///
23/// ```
24/// use mirage_engine::rayon::prelude::*;
25///
26/// fn total(values: &[f32]) -> f32 {
27///     values
28///         .par_chunks(1024)
29///         .map(|chunk| chunk.iter().sum::<f32>())
30///         .collect::<Vec<f32>>()
31///         .iter()
32///         .sum()
33/// }
34/// ```
35pub use rayon;
36
37/// The UI toolkit [`FrameContext::ui`] builds with; games never declare a
38/// version of it themselves.
39#[cfg(feature = "ui")]
40pub use egui;
41
42pub use animation::{AnimationStates, Animator, Motion, Progress, Transition};
43pub use assets::{Assets, ReliefData, ShadingData, TextureData};
44pub use camera::{Camera, Lens, Projection, View};
45pub use catalog::Catalog;
46pub use color::Color;
47pub use context::{FrameContext, InitContext, Startup, TickContext};
48pub use holds::{Holds, Seats};
49pub use input::{
50    Axis2Binding, AxisBinding, ButtonAxis, ButtonAxis2, ButtonBinding, Cursor, InputAction,
51    InputActions, InputAxis2Action, InputAxisAction, InputButtonAction, JoystickControl, Key,
52    MouseButton, NoInputActions, NoInputAxes, NoInputAxes2, NoInputButtons, Pad, PadAxis,
53    PointerDelta, Stick, WheelDelta,
54};
55pub use light::{Light, MAX_LIGHTS, MAX_SHADOWS, Spot};
56pub use material::Material;
57pub use mesh::{Clip, Mesh, Meshes, NoClips, NoMeshes, NoParts, Part, Slot};
58pub use mirage_engine_derive::{
59    Catalog, Clip, InputAxis2Action, InputAxisAction, InputButtonAction, Part, Saves, ShaderValues,
60};
61/// A point in time a run reads on either target: `std`'s `Instant` on the
62/// desktop, `web-time`'s in the browser, spelled the same either way.
63/// Required if a game times its own work on both targets.
64///
65/// One `Instant` minus another is a [`Duration`].
66pub use platform::Instant;
67pub use post_effect::{EffectStage, NoPostEffects, PostEffect, PostEffects};
68pub use ray::Ray;
69pub use save::{SaveKey, SaveValue, Saves};
70pub use skybox::{NoSkyboxes, SkyboxData, Skyboxes};
71pub use sound::{MAX_VOICES, NoSounds, SoundCue, SoundData, Sounds};
72pub use surface_style::{DrawPass, NoSurfaceStyles, SurfaceStyle, SurfaceStyles};
73pub use tonemap::Tonemap;
74pub use transform::Transform;
75
76pub use shader_values::ShaderValues;
77
78#[doc(hidden)]
79pub use holds::Sealed;
80#[doc(hidden)]
81pub use post_effect::Declarations as PostEffectDeclarations;
82#[doc(hidden)]
83pub use surface_style::Declarations as SurfaceStyleDeclarations;
84
85use math::UVec2;
86use renderer::{mesh_cache, shadows};
87
88// `#[derive(ShaderValues)]` names the engine by its own name, which the engine
89// is not to itself without this.
90extern crate self as mirage_engine;
91
92/// A game driven by the engine, which owns it for the whole run.
93///
94/// A vocabulary is a type of the game's own, usually an enum, whose values
95/// name everything of one kind the game may use; the contexts are typed by
96/// it. Six of them state what this game may draw, play, read, set its sky,
97/// style, and pass its frame through, and each has an empty one for a game
98/// with none of that kind, so every call in a tick or a frame takes a value
99/// of this game's own vocabulary and no other.
100///
101/// ```
102/// use mirage_engine::prelude::*;
103///
104/// meshes! { enum Shape { Cube } }
105///
106/// struct Hello;
107///
108/// impl Game for Hello {
109///     type Meshes = Shape;
110///     type Sounds = NoSounds;
111///     type InputActions = NoInputActions;
112///     type Skyboxes = NoSkyboxes;
113///     type SurfaceStyles = NoSurfaceStyles;
114///     type PostEffects = NoPostEffects;
115///
116///     fn tick(&mut self, _ctx: &mut TickContext<'_, Self>) {}
117///
118///     fn frame(&mut self, ctx: &mut FrameContext<'_, Self>) {
119///         ctx.draw(Cube.at(Vec3::ZERO));
120///     }
121/// }
122/// ```
123pub trait Game: Sized + 'static {
124    /// The set of every mesh this game draws — the enum [`meshes!`] writes,
125    /// one variant per mesh type — or `()` for a game that draws nothing.
126    ///
127    /// Startup builds every value the set's types catalog, and
128    /// [`FrameContext::draw`] takes a mesh the set holds and no other.
129    type Meshes: Meshes + 'static;
130
131    /// The values naming the sounds this game plays, usually an enum, or
132    /// [`NoSounds`] for a game with none.
133    ///
134    /// Startup builds every value of it, and the contexts are typed by it, so
135    /// [`FrameContext::play`] takes a value of this type and no other.
136    type Sounds: Sounds + 'static;
137
138    /// The three vocabularies naming what the player can do, usually enums,
139    /// or [`NoInputActions`] for a game that reads no input; [`Key`] for a
140    /// prototype that binds each key to itself.
141    ///
142    /// Startup materializes these into the table a player rebinds, and their
143    /// names are what a rebind is kept under. The contexts are typed by the
144    /// set, so [`FrameContext::down`] and every other query take an action
145    /// it seats and no other.
146    type InputActions: InputActions + 'static;
147
148    /// The set of every style this game draws with — the enum
149    /// [`surface_styles!`] writes — or `()` for a game that draws with the
150    /// built-in look alone.
151    ///
152    /// Startup compiles each of them into a pipeline of its own, and stops
153    /// the game where any of their WGSL does not compile.
154    type SurfaceStyles: SurfaceStyles + 'static;
155
156    /// The values naming the skies this game draws and is lit by, usually
157    /// an enum, or [`NoSkyboxes`] for a game under the default sky.
158    ///
159    /// Startup builds every value of it, and the contexts are typed by it,
160    /// so [`FrameContext::set_skybox`] takes a value of this type and no
161    /// other.
162    type Skyboxes: Skyboxes + 'static;
163
164    /// The set of every post effect this game passes its frame through — the
165    /// enum [`post_effects!`] writes — or `()` for a game that draws the
166    /// frame as the post chain leaves it.
167    ///
168    /// The post chain is the passes that take a drawn frame to the window,
169    /// and [`EffectStage`] states where in it an effect runs. Startup
170    /// compiles each effect into a pipeline of its own, and stops the game
171    /// where any of their WGSL does not compile.
172    type PostEffects: PostEffects + 'static;
173
174    /// Moves the simulation by one fixed step.
175    ///
176    /// Called zero or more times per drawn frame, one per
177    /// [`Config::tick_interval`] of elapsed time.
178    fn tick(&mut self, ctx: &mut TickContext<'_, Self>);
179
180    /// Runs the game's logic for one drawn frame, drawing as it goes.
181    fn frame(&mut self, ctx: &mut FrameContext<'_, Self>);
182}
183
184/// Opens the window and runs the game `init` builds until it is closed.
185///
186/// `init` runs once the GPU exists; returning `Err` aborts startup.
187///
188/// Blocks on the desktop; passes control to the browser's event loop and returns
189/// there. Errors that stop startup are reported to the standard error
190/// stream, or to the console and a page overlay in the browser.
191pub fn run<G: Game>(
192    config: Config,
193    init: impl FnOnce(&mut InitContext<'_, G>) -> Result<G, Error> + Send + 'static,
194) {
195    platform::run::<G>(config, init);
196}
197
198/// Presentation settings for a game.
199#[derive(Clone, Debug)]
200pub struct Config {
201    title: String,
202    size: UVec2,
203    tick_interval: Duration,
204    canvas_id: Option<String>,
205    asset_sources: Vec<String>,
206    antialiasing: bool,
207    tonemap: Tonemap,
208    shadow_resolution: u32,
209    mesh_memory: usize,
210    /// What a game set for itself, or nothing to count by whatever the
211    /// platform states.
212    double_click_interval: Option<Duration>,
213}
214
215impl Config {
216    /// The window size used when none is set, in logical pixels.
217    pub const DEFAULT_SIZE: UVec2 = UVec2::new(1280, 720);
218
219    /// The simulation step used when none is set: a sixtieth of a second.
220    pub const DEFAULT_TICK_INTERVAL: Duration = Duration::from_nanos(16_666_667);
221
222    /// A configuration with `title` and the engine's other defaults.
223    pub fn new(title: impl Into<String>) -> Self {
224        Self {
225            title: title.into(),
226            size: Self::DEFAULT_SIZE,
227            tick_interval: Self::DEFAULT_TICK_INTERVAL,
228            double_click_interval: None,
229            canvas_id: None,
230            asset_sources: Vec::new(),
231            antialiasing: true,
232            tonemap: Tonemap::default(),
233            shadow_resolution: shadows::DEFAULT_RESOLUTION,
234            mesh_memory: mesh_cache::DEFAULT_MEMORY,
235        }
236    }
237
238    /// Loads these sources before the game starts, into the [`Assets`] its
239    /// meshes build from.
240    ///
241    /// Sources are file paths on the desktop, relative to the working
242    /// directory the game runs in, and URLs relative to the page in the
243    /// browser. Anything that fails to load, decode, or match a cataloged
244    /// mesh's slots stops startup with an error.
245    #[must_use]
246    pub fn with_assets(mut self, sources: impl IntoIterator<Item = impl Into<String>>) -> Self {
247        self.asset_sources = sources.into_iter().map(Into::into).collect();
248        self
249    }
250
251    /// Requests an initial window size in logical pixels.
252    ///
253    /// The browser ignores it: the canvas fills the page, so the page sizes
254    /// the game.
255    #[must_use]
256    pub fn with_size(mut self, width: u32, height: u32) -> Self {
257        self.size = UVec2::new(width, height);
258        self
259    }
260
261    /// Draws edges smoothly, over four samples per pixel; on by default.
262    ///
263    /// Off draws one sample per pixel, which is less work.
264    #[must_use]
265    pub fn with_antialiasing(mut self, antialiasing: bool) -> Self {
266        self.antialiasing = antialiasing;
267        self
268    }
269
270    /// Sets the curve the frame is drawn to the screen through;
271    /// [`Tonemap::Neutral`] by default.
272    #[must_use]
273    pub fn with_tonemap(mut self, tonemap: Tonemap) -> Self {
274        self.tonemap = tonemap;
275        self
276    }
277
278    /// Sets the side of the depth map a light flagged with
279    /// [`Light::shadow`] draws into, in texels; `2048` by default.
280    ///
281    /// Held within `256..=4096`. A larger map has denser shadow edges and
282    /// costs more memory; each of a point light's six faces is half this
283    /// side. The maps live in arrays that grow to the most a frame ever
284    /// requested and never give it back — casting lights hold the most
285    /// memory they ever took for the whole run.
286    #[must_use]
287    pub fn with_shadow_resolution(mut self, texels: u32) -> Self {
288        // A side below this is not dense enough for a shadow edge, and one
289        // above it costs more than a simple game should spend.
290        self.shadow_resolution =
291            texels.clamp(shadows::SMALLEST_RESOLUTION, shadows::LARGEST_RESOLUTION);
292        self
293    }
294
295    /// Sets the memory the engine keeps built mesh data in, in bytes; `256`
296    /// MB by default.
297    ///
298    /// Past it the engine drops the copies used least and builds them again
299    /// when the game draws those meshes; a game whose meshes fit never
300    /// builds one twice. It bounds the system memory the copies hold, not
301    /// what the meshes take on the GPU. A mesh built through
302    /// [`prepare`](InitContext::prepare) is held like any other: past the cap
303    /// it too can be dropped and built again.
304    #[must_use]
305    pub fn with_mesh_memory(mut self, bytes: usize) -> Self {
306        self.mesh_memory = bytes;
307        self
308    }
309
310    /// Sets the simulated time one [`Game::tick`] covers, held to at least
311    /// `Duration::from_micros(1)`; [`Config::DEFAULT_TICK_INTERVAL`] by
312    /// default.
313    #[must_use]
314    pub fn with_tick_interval(mut self, interval: Duration) -> Self {
315        self.tick_interval = interval.max(time::MIN_TICK_INTERVAL);
316        self
317    }
318
319    /// Sets how long after a press a second one still counts as a double
320    /// click, which [`FrameContext::clicks`] counts by.
321    ///
322    /// Without this the engine counts by what the desktop states, and by
323    /// `400` milliseconds where the desktop states none; no browser states
324    /// one. A windowless session counts by those `400` milliseconds until
325    /// this sets another.
326    #[must_use]
327    pub fn with_double_click_interval(mut self, interval: Duration) -> Self {
328        self.double_click_interval = Some(interval);
329        self
330    }
331
332    /// Draws into the page's `<canvas>` with this id, instead of the one the
333    /// engine creates to fill the viewport.
334    ///
335    /// Ignored outside the browser; startup fails if the page has no such
336    /// canvas. A page of the game's own carries
337    /// `data-mirage-worker="<the worker script>"` on its `<body>` beside that
338    /// canvas, naming the script every worker of the run is started on — the
339    /// game thread and each worker of the pool; startup stops naming the
340    /// attribute where the page carries none.
341    #[must_use]
342    pub fn with_canvas_id(mut self, id: impl Into<String>) -> Self {
343        self.canvas_id = Some(id.into());
344        self
345    }
346
347    /// The window title.
348    pub fn title(&self) -> &str {
349        &self.title
350    }
351
352    /// The requested initial window size, in logical pixels.
353    pub fn size(&self) -> UVec2 {
354        self.size
355    }
356
357    /// Simulated time one [`Game::tick`] covers.
358    pub fn tick_interval(&self) -> Duration {
359        self.tick_interval
360    }
361
362    /// How long after a press a second one still counts as a double click,
363    /// where the game set it: `None` to count by what the platform states.
364    pub(crate) fn double_click_interval(&self) -> Option<Duration> {
365        self.double_click_interval
366    }
367
368    /// The page canvas to draw into, if the game named one.
369    pub fn canvas_id(&self) -> Option<&str> {
370        self.canvas_id.as_deref()
371    }
372
373    /// The asset sources loaded before the game starts, in load order.
374    pub fn asset_sources(&self) -> &[String] {
375        &self.asset_sources
376    }
377
378    /// Whether edges are drawn smoothly.
379    pub fn antialiasing(&self) -> bool {
380        self.antialiasing
381    }
382
383    /// The curve the frame is drawn to the screen through.
384    pub fn tonemap(&self) -> Tonemap {
385        self.tonemap
386    }
387
388    /// The side of one light's depth map, in texels.
389    pub fn shadow_resolution(&self) -> u32 {
390        self.shadow_resolution
391    }
392
393    /// Memory the engine keeps built mesh data in, in bytes.
394    pub fn mesh_memory(&self) -> usize {
395        self.mesh_memory
396    }
397}
398
399/// Something the engine could not do.
400///
401/// Only the edges of the API (startup and asset decoding) produce one, so
402/// code that runs each frame never handles an error.
403#[derive(Clone, Debug)]
404pub struct Error {
405    msg: String,
406}
407
408impl Error {
409    /// An error described by `msg`.
410    pub fn msg(msg: impl Into<String>) -> Self {
411        Self { msg: msg.into() }
412    }
413}
414
415impl fmt::Display for Error {
416    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
417        f.write_str(&self.msg)
418    }
419}
420
421impl std::error::Error for Error {}
422
423mod assets;
424mod camera;
425mod catalog;
426mod color;
427mod context;
428mod gpu;
429mod holds;
430mod light;
431mod material;
432mod overrun;
433mod platform;
434mod renderer;
435mod skybox;
436mod time;
437mod tonemap;
438mod transform;
439mod ui;
440
441pub mod animation;
442pub mod input;
443pub mod mesh;
444pub mod post_effect;
445pub mod ray;
446pub mod save;
447pub mod shader_values;
448pub mod sound;
449pub mod surface_style;
450
451#[cfg(all(feature = "offscreen", not(target_arch = "wasm32")))]
452pub mod headless;
453
454#[doc(hidden)]
455pub mod doctests {
456    //! `compile_fail` checks for what the type system holds; hidden from
457    //! the public docs, run by `cargo test`.
458    //!
459    //! The README's own code is compiled here too, so that it cannot go
460    //! stale: see [`readme`].
461    //!
462    //! A `Catalog` variant with fields:
463    //!
464    //! ```compile_fail
465    //! #[derive(mirage_engine::Catalog, Clone, Eq, Hash, PartialEq)]
466    //! enum Shape {
467    //!     Asteroid { seed: u32 },
468    //! }
469    //! ```
470    //!
471    //! A `Catalog` type under two attributes:
472    //!
473    //! ```compile_fail
474    //! #[derive(mirage_engine::Catalog, Hash, PartialEq, Eq, Clone)]
475    //! #[catalog(Self { seed: 0 })]
476    //! #[catalog(Self { seed: 1 })]
477    //! struct Asteroid { seed: u32 }
478    //! ```
479    //!
480    //! A `Catalog` attribute naming no value:
481    //!
482    //! ```compile_fail
483    //! #[derive(mirage_engine::Catalog, Hash, PartialEq, Eq, Clone)]
484    //! #[catalog()]
485    //! struct Asteroid { seed: u32 }
486    //! ```
487    //!
488    //! A `Part` variant with fields:
489    //!
490    //! ```compile_fail
491    //! #[derive(mirage_engine::Part, Clone, Debug, Eq, Hash, PartialEq)]
492    //! enum HullPart {
493    //!     Plating { layer: u32 },
494    //! }
495    //! ```
496    //!
497    //! A `Clip` variant with fields:
498    //!
499    //! ```compile_fail
500    //! #[derive(mirage_engine::Clip, Clone, Debug, Eq, Hash, PartialEq)]
501    //! enum Pace {
502    //!     Walk { speed: u32 },
503    //! }
504    //! ```
505    //!
506    //! A part of one mesh on a draw of another:
507    //!
508    //! ```compile_fail
509    //! use mirage_engine::prelude::*;
510    //!
511    //! #[derive(Catalog, Clone, Eq, Hash, PartialEq)]
512    //! struct Paddle;
513    //!
514    //! #[derive(Part, Clone, Debug, Eq, Hash, PartialEq)]
515    //! enum PaddlePart {
516    //!     Face,
517    //! }
518    //!
519    //! impl Mesh<PaddlePart> for Paddle {
520    //!     fn build(&self, assets: &Assets) -> MeshData<PaddlePart> {
521    //!         assets.mesh("paddle")
522    //!     }
523    //! }
524    //!
525    //! let _ = Cube
526    //!     .at::<NoSurfaceStyles>(Vec3::ZERO)
527    //!     .material_of(PaddlePart::Face, Material::default());
528    //! ```
529    //!
530    //! A draw of a mesh the game does not name in its
531    //! [`Meshes`](crate::Game::Meshes):
532    //!
533    //! ```compile_fail
534    //! use mirage_engine::prelude::*;
535    //!
536    //! meshes! { enum Shape { Cube } }
537    //!
538    //! struct Spheres;
539    //!
540    //! impl Game for Spheres {
541    //!     type Meshes = Shape;
542    //!     type Sounds = NoSounds;
543    //!     type InputActions = NoInputActions;
544    //!     type Skyboxes = NoSkyboxes;
545    //!     type SurfaceStyles = NoSurfaceStyles;
546    //!     type PostEffects = NoPostEffects;
547    //!
548    //!     fn tick(&mut self, _ctx: &mut TickContext<'_, Self>) {}
549    //!
550    //!     fn frame(&mut self, ctx: &mut FrameContext<'_, Self>) {
551    //!         ctx.draw(Sphere { subdivisions: 1 }.at(Vec3::ZERO));
552    //!     }
553    //! }
554    //! ```
555    //!
556    //! A set naming one mesh type twice:
557    //!
558    //! ```compile_fail
559    //! use mirage_engine::prelude::*;
560    //!
561    //! meshes! { enum Shape { Cube, Cube } }
562    //! ```
563    //!
564    //! An action with fields:
565    //!
566    //! ```compile_fail
567    //! #[derive(mirage_engine::InputButtonAction, Clone, Copy)]
568    //! enum Verb {
569    //!     Fire { rounds: u32 },
570    //! }
571    //! ```
572    //!
573    //! A save key with fields:
574    //!
575    //! ```compile_fail
576    //! #[derive(mirage_engine::Saves, Clone, Copy)]
577    //! enum Progress {
578    //!     Level { number: u32 },
579    //! }
580    //! ```
581    //!
582    //! A sound of a vocabulary the game does not name as its
583    //! [`Sounds`](crate::Game::Sounds):
584    //!
585    //! ```compile_fail
586    //! use mirage_engine::prelude::*;
587    //!
588    //! meshes! { enum Only { Cube } }
589    //!
590    //! #[derive(Catalog, Clone, Eq, Hash, PartialEq)]
591    //! enum Music {
592    //!     Theme,
593    //! }
594    //!
595    //! impl Sounds for Music {
596    //!     fn build(&self, assets: &Assets) -> SoundData {
597    //!         assets.sound("theme")
598    //!     }
599    //! }
600    //!
601    //! struct Quiet;
602    //!
603    //! impl Game for Quiet {
604    //!     type Meshes = Only;
605    //!     type Sounds = NoSounds;
606    //!     type InputActions = NoInputActions;
607    //!     type Skyboxes = NoSkyboxes;
608    //!     type SurfaceStyles = NoSurfaceStyles;
609    //!     type PostEffects = NoPostEffects;
610    //!
611    //!     fn tick(&mut self, _ctx: &mut TickContext<'_, Self>) {}
612    //!
613    //!     fn frame(&mut self, ctx: &mut FrameContext<'_, Self>) {
614    //!         ctx.play(Music::Theme);
615    //!     }
616    //! }
617    //! ```
618    //!
619    //! A sky of a vocabulary the game does not name as its
620    //! [`Skyboxes`](crate::Game::Skyboxes):
621    //!
622    //! ```compile_fail
623    //! use mirage_engine::prelude::*;
624    //!
625    //! meshes! { enum Only { Cube } }
626    //!
627    //! #[derive(Catalog, Clone, Debug, Eq, Hash, PartialEq)]
628    //! enum Weather {
629    //!     Clear,
630    //!     Storm,
631    //! }
632    //!
633    //! impl Skyboxes for Weather {
634    //!     fn build(&self, assets: &Assets) -> SkyboxData {
635    //!         assets.skybox("sky")
636    //!     }
637    //! }
638    //!
639    //! struct Outdoors;
640    //!
641    //! impl Game for Outdoors {
642    //!     type Meshes = Only;
643    //!     type Sounds = NoSounds;
644    //!     type InputActions = NoInputActions;
645    //!     type Skyboxes = NoSkyboxes;
646    //!     type SurfaceStyles = NoSurfaceStyles;
647    //!     type PostEffects = NoPostEffects;
648    //!
649    //!     fn tick(&mut self, _ctx: &mut TickContext<'_, Self>) {}
650    //!
651    //!     fn frame(&mut self, ctx: &mut FrameContext<'_, Self>) {
652    //!         ctx.set_skybox(Weather::Storm);
653    //!     }
654    //! }
655    //! ```
656    //!
657    //! An action of a vocabulary the game does not name as its
658    //! [`InputActions`](crate::Game::InputActions):
659    //!
660    //! ```compile_fail
661    //! use mirage_engine::prelude::*;
662    //!
663    //! meshes! { enum Only { Cube } }
664    //!
665    //! #[derive(InputButtonAction, Clone, Copy)]
666    //! enum Verb {
667    //!     Jump,
668    //! }
669    //!
670    //! impl InputButtonAction for Verb {
671    //!     fn bindings(&self) -> Vec<ButtonBinding> {
672    //!         vec![Key::Space.into()]
673    //!     }
674    //! }
675    //!
676    //! struct Controls;
677    //!
678    //! impl InputActions for Controls {
679    //!     type Button = Verb;
680    //!     type Axis = NoInputAxes;
681    //!     type Axis2 = NoInputAxes2;
682    //! }
683    //!
684    //! struct Jumper;
685    //!
686    //! impl Game for Jumper {
687    //!     type Meshes = Only;
688    //!     type Sounds = NoSounds;
689    //!     type InputActions = Controls;
690    //!     type Skyboxes = NoSkyboxes;
691    //!     type SurfaceStyles = NoSurfaceStyles;
692    //!     type PostEffects = NoPostEffects;
693    //!
694    //!     fn tick(&mut self, _ctx: &mut TickContext<'_, Self>) {}
695    //!
696    //!     fn frame(&mut self, ctx: &mut FrameContext<'_, Self>) {
697    //!         let _ = ctx.pressed(Key::Escape);
698    //!     }
699    //! }
700    //! ```
701    //!
702    //! A draw with a style the game does not name in its
703    //! [`SurfaceStyles`](crate::Game::SurfaceStyles):
704    //!
705    //! ```compile_fail
706    //! use mirage_engine::prelude::*;
707    //!
708    //! meshes! { enum Only { Cube } }
709    //!
710    //! #[derive(Default, ShaderValues)]
711    //! struct Water;
712    //!
713    //! impl SurfaceStyle for Water {
714    //!     const PASS: DrawPass = DrawPass::Translucent;
715    //! }
716    //!
717    //! #[derive(Default, ShaderValues)]
718    //! struct Foam;
719    //!
720    //! impl SurfaceStyle for Foam {
721    //!     const PASS: DrawPass = DrawPass::Translucent;
722    //! }
723    //!
724    //! #[derive(Default, ShaderValues)]
725    //! struct Ripple;
726    //!
727    //! impl SurfaceStyle for Ripple {
728    //!     const PASS: DrawPass = DrawPass::Opaque;
729    //! }
730    //!
731    //! surface_styles! { enum Looks { Water, Foam } }
732    //!
733    //! struct Pond;
734    //!
735    //! impl Game for Pond {
736    //!     type Meshes = Only;
737    //!     type Sounds = NoSounds;
738    //!     type InputActions = NoInputActions;
739    //!     type Skyboxes = NoSkyboxes;
740    //!     type SurfaceStyles = Looks;
741    //!     type PostEffects = NoPostEffects;
742    //!
743    //!     fn tick(&mut self, _ctx: &mut TickContext<'_, Self>) {}
744    //!
745    //!     fn frame(&mut self, ctx: &mut FrameContext<'_, Self>) {
746    //!         ctx.draw(Cube.at(Vec3::ZERO).surface_style::<Ripple>());
747    //!     }
748    //! }
749    //! ```
750    //!
751    //! The values of a style the game does not name in its
752    //! [`SurfaceStyles`](crate::Game::SurfaceStyles):
753    //!
754    //! ```compile_fail
755    //! use mirage_engine::prelude::*;
756    //!
757    //! meshes! { enum Only { Cube } }
758    //!
759    //! #[derive(Default, ShaderValues)]
760    //! struct Water;
761    //!
762    //! impl SurfaceStyle for Water {
763    //!     const PASS: DrawPass = DrawPass::Translucent;
764    //! }
765    //!
766    //! #[derive(Default, ShaderValues)]
767    //! struct Foam;
768    //!
769    //! impl SurfaceStyle for Foam {
770    //!     const PASS: DrawPass = DrawPass::Translucent;
771    //! }
772    //!
773    //! #[derive(Default, ShaderValues)]
774    //! struct Ripple;
775    //!
776    //! impl SurfaceStyle for Ripple {
777    //!     const PASS: DrawPass = DrawPass::Opaque;
778    //! }
779    //!
780    //! surface_styles! { enum Looks { Water, Foam } }
781    //!
782    //! struct Pond;
783    //!
784    //! impl Game for Pond {
785    //!     type Meshes = Only;
786    //!     type Sounds = NoSounds;
787    //!     type InputActions = NoInputActions;
788    //!     type Skyboxes = NoSkyboxes;
789    //!     type SurfaceStyles = Looks;
790    //!     type PostEffects = NoPostEffects;
791    //!
792    //!     fn tick(&mut self, _ctx: &mut TickContext<'_, Self>) {}
793    //!
794    //!     fn frame(&mut self, ctx: &mut FrameContext<'_, Self>) {
795    //!         ctx.set_surface_style(Ripple);
796    //!     }
797    //! }
798    //! ```
799    //!
800    //! A post effect the game does not name in its
801    //! [`PostEffects`](crate::Game::PostEffects):
802    //!
803    //! ```compile_fail
804    //! use mirage_engine::prelude::*;
805    //!
806    //! meshes! { enum Only { Cube } }
807    //!
808    //! #[derive(ShaderValues)]
809    //! struct Vignette;
810    //!
811    //! impl PostEffect for Vignette {
812    //!     const STAGE: EffectStage = EffectStage::ToneMapped;
813    //!     const SHADER: &'static str = "fn draw(pixel: Pixel) -> vec4<f32> { return pixel.color; }";
814    //! }
815    //!
816    //! #[derive(ShaderValues)]
817    //! struct Scanlines;
818    //!
819    //! impl PostEffect for Scanlines {
820    //!     const STAGE: EffectStage = EffectStage::ToneMapped;
821    //!     const SHADER: &'static str = "fn draw(pixel: Pixel) -> vec4<f32> { return pixel.color; }";
822    //! }
823    //!
824    //! #[derive(ShaderValues)]
825    //! struct Grain;
826    //!
827    //! impl PostEffect for Grain {
828    //!     const STAGE: EffectStage = EffectStage::ToneMapped;
829    //!     const SHADER: &'static str = "fn draw(pixel: Pixel) -> vec4<f32> { return pixel.color; }";
830    //! }
831    //!
832    //! post_effects! { enum Look { Vignette, Scanlines } }
833    //!
834    //! struct Space;
835    //!
836    //! impl Game for Space {
837    //!     type Meshes = Only;
838    //!     type Sounds = NoSounds;
839    //!     type InputActions = NoInputActions;
840    //!     type Skyboxes = NoSkyboxes;
841    //!     type SurfaceStyles = NoSurfaceStyles;
842    //!     type PostEffects = Look;
843    //!
844    //!     fn tick(&mut self, _ctx: &mut TickContext<'_, Self>) {}
845    //!
846    //!     fn frame(&mut self, ctx: &mut FrameContext<'_, Self>) {
847    //!         ctx.set_post_effect(Grain);
848    //!     }
849    //! }
850    //! ```
851    //!
852    //! A set naming one style twice, and one naming an effect twice:
853    //!
854    //! ```compile_fail
855    //! use mirage_engine::prelude::*;
856    //!
857    //! #[derive(Default, ShaderValues)]
858    //! struct Water;
859    //!
860    //! impl SurfaceStyle for Water {
861    //!     const PASS: DrawPass = DrawPass::Translucent;
862    //! }
863    //!
864    //! surface_styles! { enum Looks { Water, Water } }
865    //! ```
866    //!
867    //! ```compile_fail
868    //! use mirage_engine::prelude::*;
869    //!
870    //! #[derive(ShaderValues)]
871    //! struct Grain;
872    //!
873    //! impl PostEffect for Grain {
874    //!     const STAGE: EffectStage = EffectStage::ToneMapped;
875    //!     const SHADER: &'static str = "fn draw(pixel: Pixel) -> vec4<f32> { return pixel.color; }";
876    //! }
877    //!
878    //! post_effects! { enum Look { Grain, Grain } }
879    //! ```
880    //!
881    //! A value of a kind no shader lane holds:
882    //!
883    //! ```compile_fail
884    //! #[derive(mirage_engine::ShaderValues)]
885    //! struct Ripples {
886    //!     steps: bool,
887    //! }
888    //! ```
889    //!
890    //! Values a shader could not read by name:
891    //!
892    //! ```compile_fail
893    //! #[derive(mirage_engine::ShaderValues)]
894    //! struct Ripples(f32);
895    //! ```
896    //!
897    //! A relief, and the same call given a sampler of its own:
898    //!
899    //! ```
900    //! use mirage_engine::{ReliefData, math::UVec2};
901    //!
902    //! ReliefData::rgba8(UVec2::ONE, vec![128, 128, 255, 0]);
903    //! ```
904    //!
905    //! ```compile_fail
906    //! use mirage_engine::{ReliefData, math::UVec2};
907    //!
908    //! ReliefData::rgba8(UVec2::ONE, vec![128, 128, 255, 0]).pixelated();
909    //! ```
910    //!
911    //! A shading map given a sampler of its own:
912    //!
913    //! ```compile_fail
914    //! use mirage_engine::{ShadingData, math::UVec2};
915    //!
916    //! ShadingData::rgba8(UVec2::ONE, vec![255, 255, 255, 255]).pixelated();
917    //! ```
918    //!
919    //! A vocabulary of one kind declaring the bindings of another:
920    //!
921    //! ```compile_fail
922    //! #[derive(mirage_engine::InputAxisAction, Clone, Copy)]
923    //! enum Lever {
924    //!     Throttle,
925    //! }
926    //!
927    //! impl mirage_engine::InputButtonAction for Lever {
928    //!     fn bindings(&self) -> Vec<mirage_engine::ButtonBinding> {
929    //!         Vec::new()
930    //!     }
931    //! }
932    //! ```
933    #[doc = include_str!("../README.md")]
934    pub mod readme {}
935}
936
937/// The items of the public API most games use.
938pub mod prelude {
939    #[cfg(feature = "ui")]
940    pub use crate::egui;
941    pub use crate::math::*;
942    pub use crate::mesh::{
943        Cube, Frame, Instance, Mesh, MeshData, Meshes, NoClips, NoMeshes, NoParts, Plane, Quad,
944        Sheet, Slot, Sphere, Vertex,
945    };
946    pub use crate::{
947        AnimationStates, Animator, Assets, Axis2Binding, AxisBinding, ButtonAxis, ButtonAxis2,
948        ButtonBinding, Camera, Catalog, Clip, Color, Config, Cursor, DrawPass, EffectStage, Error,
949        FrameContext, Game, Holds, InitContext, InputAction, InputActions, InputAxis2Action,
950        InputAxisAction, InputButtonAction, Instant, JoystickControl, Key, Light, Material, Motion,
951        MouseButton, NoInputActions, NoInputAxes, NoInputAxes2, NoInputButtons, NoPostEffects,
952        NoSkyboxes, NoSounds, NoSurfaceStyles, Pad, PadAxis, Part, PointerDelta, PostEffect,
953        PostEffects, Progress, Projection, Ray, ReliefData, SaveKey, SaveValue, Saves, Seats,
954        ShaderValues, ShadingData, SkyboxData, Skyboxes, SoundCue, SoundData, Sounds, Spot,
955        Startup, Stick, SurfaceStyle, SurfaceStyles, TextureData, TickContext, Tonemap, Transform,
956        Transition, View, WheelDelta, run,
957    };
958    pub use crate::{meshes, post_effects, surface_styles};
959}