Skip to main content

repame_view2d/
sprite.rs

1//! Sprite data: one row per drawn quad, its blend, and its tint.
2//!
3//! [`SpriteInstance`] is the input to the instanced batch in [`batch`](crate::batch)
4//! and the output type of the sim-side particle steppers, so both ends of the
5//! snapshot speak it.
6
7use glam::Vec2;
8use repose_core::Color;
9
10/// Blend mode per sprite. Additive uses `SrcAlpha + One`.
11/// Sorted into ranges (alpha, then multiply, then additive): push order
12/// across blend modes is NOT preserved, see the batch module docs.
13#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
14pub enum SpriteBlend {
15    #[default]
16    Alpha,
17    Additive,
18    Multiply,
19}
20
21/// One batched sprite. `uv` is in atlas texels normalized to 0..1.
22#[derive(Clone, Copy, Debug)]
23pub struct SpriteInstance {
24    /// World-space center, rotation radians, size in world units.
25    pub center: Vec2,
26    pub rotation: f32,
27    pub size: Vec2,
28    /// Normalized anchor: `[0.5, 0.5]` centers the quad on `center`,
29    /// `[0, 0]` pins the top-left corner. Y-down.
30    pub anchor: Vec2,
31    /// Mirror about the anchor axes. Canvas fills are flip-invariant;
32    /// the GPU batch mirrors geometry (UVs untouched).
33    pub flip_x: bool,
34    pub flip_y: bool,
35    pub uv_min: Vec2,
36    pub uv_max: Vec2,
37    /// RGBA tint, `(c * 255) as u8` per channel.
38    pub color: [f32; 4],
39    /// Atlas page index for multi-texture batches.
40    pub page: u32,
41    /// Draw key within one blend range; higher draws on top. Default 0.
42    /// Stable-sorted by `z` inside the range, but blend ranges draw
43    /// alpha-then-multiply-then-additive regardless of `z` (see
44    /// [`SpriteBlend`]).
45    pub z: f32,
46    pub blend: SpriteBlend,
47    /// Light layer bits, `1` (layer 0) by default. The sprite is lit by every
48    /// light whose `light_mask` shares the sprite's lowest set bit, and reads
49    /// the layer that bit names (see [`light`](crate::light)); `0` renders it
50    /// unlit, ignoring ambient and modulate alike.
51    pub light_mask: u32,
52}
53
54impl Default for SpriteInstance {
55    fn default() -> Self {
56        Self {
57            center: Vec2::ZERO,
58            rotation: 0.0,
59            size: Vec2::ONE,
60            anchor: Vec2::new(0.5, 0.5),
61            flip_x: false,
62            flip_y: false,
63            uv_min: Vec2::ZERO,
64            uv_max: Vec2::ONE,
65            color: [1.0, 1.0, 1.0, 1.0],
66            page: 0,
67            z: 0.0,
68            blend: SpriteBlend::Alpha,
69            light_mask: 1,
70        }
71    }
72}
73
74/// World-anchored text floater (damage numbers, `+25`).
75#[derive(Clone, Debug, Default)]
76pub struct WorldText {
77    pub text: String,
78    /// World-space anchor.
79    pub pos: Vec2,
80    /// RGBA, `(c * 255) as u8` per channel.
81    pub color: [f32; 4],
82    /// Font size in world units.
83    pub size: f32,
84    /// Font family name to resolve, or `None` (default) for the stack the
85    /// text engine picks itself. The name must already be known to the
86    /// engine; an unresolved name falls back to the default stack.
87    pub font_family: Option<&'static str>,
88}
89
90pub fn rgba8(c: [f32; 4]) -> Color {
91    Color::from_rgba(
92        (c[0].clamp(0.0, 1.0) * 255.0) as u8,
93        (c[1].clamp(0.0, 1.0) * 255.0) as u8,
94        (c[2].clamp(0.0, 1.0) * 255.0) as u8,
95        (c[3].clamp(0.0, 1.0) * 255.0) as u8,
96    )
97}