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