mirage-engine 0.1.1

Mirage, an immediate-mode 3D engine for simple games on desktop and the browser
Documentation
//! The values a style's or a post effect's WGSL reads, and the WGSL struct
//! it reads them through.
//!
//! `#[derive(ShaderValues)]` over a struct writes both: the WGSL that
//! declares them, and the bytes laid out where that WGSL reads each
//! field. The WGSL struct takes the Rust type's own name, each field takes
//! its own name, and the fields keep the order they were written in; what
//! padding the shader's own layout calls for is the derive's, not the
//! game's.
//!
//! | Rust        | WGSL          |
//! |-------------|---------------|
//! | `f32`       | `f32`         |
//! | `u32`       | `u32`         |
//! | `Vec2`      | `vec2<f32>`   |
//! | `Vec3`      | `vec3<f32>`   |
//! | `Vec4`      | `vec4<f32>`   |
//! | `Mat4`      | `mat4x4<f32>` |
//! | [`Color`](crate::Color) | `vec4<f32>`, linear red, green, blue and alpha |
//!
//! A field of any other type does not compile. A type with no fields reads
//! no values and binds none.
//!
//! ```
//! use mirage_engine::prelude::*;
//!
//! #[derive(Default, ShaderValues)]
//! struct Water {
//!     wave: f32,
//!     tint: Color,
//! }
//! ```
//!
//! declares `struct Water { wave: f32, tint: vec4<f32> }`, which a style
//! reads as `style` and an effect as `effect`. [`Default`] is derived here
//! because a [`SurfaceStyle`](crate::SurfaceStyle) requires it — a frame
//! that passes a style no values draws with the default of every field —
//! where a [`PostEffect`](crate::PostEffect) does not, since an effect no
//! frame submits never runs.

/// The values one style's or one post effect's WGSL reads. Written by
/// [`ShaderValues`](macro@crate::ShaderValues) on a struct of `f32`, `u32`,
/// `Vec2`, `Vec3`, `Vec4`, `Mat4` and [`Color`](crate::Color) fields.
///
/// A style's code reads them as `style` and an effect's as `effect`. A type
/// that reads no values has no fields, and binds none.
pub trait ShaderValues: Sealed + 'static {
    /// Name of the WGSL struct these values are read through.
    #[doc(hidden)]
    const TYPE: &'static str;

    /// The WGSL declaring that struct; empty where the type has no fields.
    #[doc(hidden)]
    const DECLARATION: &'static str;

    /// Lays the values out where the shader reads each of them.
    #[doc(hidden)]
    fn write(&self, into: &mut Vec<u8>);

    /// The WGSL declaring these values and binding them at `group` under
    /// `name`; empty where the type has no fields.
    #[doc(hidden)]
    fn bound(group: u32, name: &str) -> String
    where
        Self: Sized,
    {
        if Self::DECLARATION.is_empty() {
            return String::new();
        }
        format!(
            "{}\n@group({group}) @binding(0) var<uniform> {name}: {};\n\n",
            Self::DECLARATION,
            Self::TYPE
        )
    }
}

/// [`ShaderValues`], [`SurfaceStyles`](crate::SurfaceStyles) and
/// [`PostEffects`](crate::PostEffects) are sealed by this, so only the
/// derive and the set macros implement them and nothing else lays values
/// out other than as the WGSL reads them.
#[doc(hidden)]
pub trait Sealed {}

impl Sealed for () {}