euv-engine 0.31.1

A high-performance 2D game engine built on the euv framework, featuring ECS, fixed-timestep game loop, canvas rendering, physics, collision detection, sprite animation, and audio.
Documentation
use super::*;

/// A 3D ray carrying the parameters needed for traversal and depth tracking.
#[derive(Clone, Data, Debug, PartialEq)]
pub struct Ray {
    /// The world-space origin of the ray.
    #[get(type(copy))]
    #[get_mut(pub(crate))]
    #[set(pub(crate))]
    pub origin: Vector3D,
    /// The unit direction of the ray.
    #[get(type(copy))]
    #[get_mut(pub(crate))]
    pub direction: Vector3D,
    /// The minimum acceptable `t` value for valid intersections.
    #[get(type(copy))]
    #[get_mut(pub(crate))]
    #[set(pub(crate))]
    pub t_min: f64,
    /// The maximum `t` value before the ray escapes the scene.
    #[get(type(copy))]
    #[get_mut(pub(crate))]
    #[set(pub(crate))]
    pub t_max: f64,
    /// The current recursion depth (used to terminate recursive bounces).
    #[get(type(copy))]
    #[get_mut(pub(crate))]
    #[set(pub(crate))]
    pub depth: u32,
}

/// The result of a ray-object intersection.
#[derive(Clone, Data, Debug, PartialEq)]
pub struct Hit {
    /// The ray parameter at the hit point.
    #[get(type(copy))]
    #[get_mut(pub(crate))]
    #[set(pub(crate))]
    pub t: f64,
    /// The world-space hit position.
    #[get(type(copy))]
    #[get_mut(pub(crate))]
    #[set(pub(crate))]
    pub position: Vector3D,
    /// The outward unit normal at the hit point.
    #[get(type(copy))]
    #[get_mut(pub(crate))]
    #[set(pub(crate))]
    pub normal: Vector3D,
    /// The material of the hit surface.
    #[get(pub(crate), type(clone))]
    #[get_mut(pub(crate))]
    #[set(pub(crate))]
    pub(crate) material: Material,
}

/// A ray-traceable geometric surface with an attached material.
#[derive(Clone, Data, Debug, PartialEq)]
pub struct Occluder {
    /// The geometric shape represented by this occluder.
    #[get(type(copy))]
    #[get_mut(pub(crate))]
    #[set(pub(crate))]
    pub kind: OccluderKind,
    /// For spheres: the center. For AABBs: the minimum corner. Unused by
    /// triangles, whose vertices live in `vertices`.
    #[get(type(copy))]
    #[get_mut(pub(crate))]
    #[set(pub(crate))]
    pub center: Vector3D,
    /// For spheres: `.x` is the radius. For AABBs: the maximum corner.
    /// Unused by triangles, whose vertices live in `vertices`.
    #[get(type(copy))]
    #[get_mut(pub(crate))]
    #[set(pub(crate))]
    pub extent: Vector3D,
    /// For triangles: the three corners in winding order. Unused by spheres
    /// and AABBs, which are fully described by `center` and `extent`.
    #[get(type(copy))]
    #[get_mut(pub(crate))]
    #[set(pub(crate))]
    pub vertices: [Vector3D; 3],
    /// The surface material.
    #[get(pub(crate))]
    #[get_mut(pub(crate))]
    #[set(pub(crate))]
    pub(crate) material: Material,
}

/// One node of the flat bounding volume hierarchy owned by
/// [`RayTraceScene`].
///
/// The hierarchy is stored as a preorder array: a node is followed
/// immediately by its left child at `index + 1`, and `escape` holds the
/// index of the first node after this node's entire subtree. A node with
/// `count == 0` is internal, and traversal either descends into
/// `index + 1` or jumps to `escape` when the ray misses the bounds. A node
/// with `count > 0` is a leaf whose `start`/`count` slice of the scene's
/// `indices` array lists the primitives it owns, reordered but never
/// renumbered: every entry stays the occluder's original index.
#[derive(Clone, Copy, Data, Debug, PartialEq)]
pub(crate) struct RayTraceNode {
    /// The minimum corner of the axis-aligned bounds covering the subtree.
    #[get(pub(crate), type(copy))]
    #[get_mut(pub(crate))]
    #[set(pub(crate))]
    pub(crate) lower: Vector3D,
    /// The maximum corner of the axis-aligned bounds covering the subtree.
    #[get(pub(crate), type(copy))]
    #[get_mut(pub(crate))]
    #[set(pub(crate))]
    pub(crate) upper: Vector3D,
    /// The first entry of this leaf's primitive slice in the scene's
    /// `indices` array; unused when `count == 0`.
    #[get(pub(crate), type(copy))]
    #[get_mut(pub(crate))]
    #[set(pub(crate))]
    pub(crate) start: usize,
    /// The number of primitives in this leaf; zero marks an internal node.
    #[get(pub(crate), type(copy))]
    #[get_mut(pub(crate))]
    #[set(pub(crate))]
    pub(crate) count: usize,
    /// The index of the first node after this subtree, so a miss can skip
    /// the whole subtree in one step.
    #[get(pub(crate), type(copy))]
    #[get_mut(pub(crate))]
    #[set(pub(crate))]
    pub(crate) escape: usize,
}

/// The per-primitive bounds and centroids a BVH build reads while
/// splitting.
///
/// Holding them apart from [`RayTraceScene`] keeps the build scratch out
/// of the stored scene: once the hierarchy is built the three arrays are
/// dropped, so nothing a query touches carries build-time state.
#[derive(Debug)]
pub(crate) struct BvhBuild {
    /// The minimum corner of each primitive's world-space bounds.
    pub(crate) lower: Vec<Vector3D>,
    /// The maximum corner of each primitive's world-space bounds.
    pub(crate) upper: Vec<Vector3D>,
    /// The midpoint of each primitive's bounds, used to bin and partition.
    pub(crate) centroids: Vec<Vector3D>,
}

/// An owned ray-tracing scene with a precomputed bounding volume
/// hierarchy and shadow data.
///
/// `RayTraceScene` bundles the occluder list, the flat BVH over their
/// bounds, and the `(center, radius)` shadow bounding spheres consumed by
/// [`soft_shadow_factor`], computing both exactly once at construction.
/// Tracing through [`RayTraceScene::trace`] and querying through
/// [`RayTraceScene::closest_hit`] perform no heap allocation per ray or
/// per bounce, making the scene the single canonical entry point for
/// tracing many rays against a static scene.
#[derive(Clone, Debug, Getter, PartialEq)]
pub struct RayTraceScene {
    /// All occluding surfaces in the scene.
    #[get(pub(crate))]
    pub(crate) occluders: Vec<Occluder>,
    /// The flat preorder BVH over the occluders' bounds. Shared verbatim
    /// with the GPU encoders, so the layout is part of the internal
    /// contract rather than an implementation detail.
    #[get(pub(crate))]
    pub(crate) nodes: Vec<RayTraceNode>,
    /// The reordered primitive indexes addressed by the leaves' `start` and
    /// `count` fields. Every value stays the occluder's original index.
    #[get(pub(crate))]
    pub(crate) indices: Vec<usize>,
    /// Precomputed `(center, radius)` shadow bounding spheres, one per
    /// occluder, in the same order as `occluders`.
    #[get(pub(crate))]
    pub(crate) shadow_points: Vec<(Vector3D, f64)>,
}