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}
48
49impl Default for SpriteInstance {
50    fn default() -> Self {
51        Self {
52            center: Vec2::ZERO,
53            rotation: 0.0,
54            size: Vec2::ONE,
55            anchor: Vec2::new(0.5, 0.5),
56            flip_x: false,
57            flip_y: false,
58            uv_min: Vec2::ZERO,
59            uv_max: Vec2::ONE,
60            color: [1.0, 1.0, 1.0, 1.0],
61            page: 0,
62            z: 0.0,
63            blend: SpriteBlend::Alpha,
64        }
65    }
66}
67
68/// World-anchored text floater (damage numbers, `+25`).
69#[derive(Clone, Debug, Default)]
70pub struct WorldText {
71    pub text: String,
72    /// World-space anchor.
73    pub pos: Vec2,
74    /// RGBA, `(c * 255) as u8` per channel.
75    pub color: [f32; 4],
76    /// Font size in world units.
77    pub size: f32,
78    /// Font family name to resolve, or `None` (default) for the stack the
79    /// text engine picks itself. The name must already be known to the
80    /// engine; an unresolved name falls back to the default stack.
81    pub font_family: Option<&'static str>,
82}
83
84pub fn rgba8(c: [f32; 4]) -> Color {
85    Color::from_rgba(
86        (c[0].clamp(0.0, 1.0) * 255.0) as u8,
87        (c[1].clamp(0.0, 1.0) * 255.0) as u8,
88        (c[2].clamp(0.0, 1.0) * 255.0) as u8,
89        (c[3].clamp(0.0, 1.0) * 255.0) as u8,
90    )
91}