Skip to main content

euv_engine/sprite/
struct.rs

1use super::*;
2
3/// Defines a single frame in a sprite animation.
4#[derive(Clone, Copy, Data, Debug, Default, New, PartialEq, PartialOrd)]
5pub struct SpriteFrame {
6    /// The source rectangle within the sprite sheet image.
7    #[get(type(copy))]
8    pub(crate) source: Rect,
9    /// The duration this frame should be displayed, in seconds.
10    #[get(type(copy))]
11    #[get_mut(pub(crate))]
12    #[set(pub(crate))]
13    pub(crate) duration: f64,
14}
15
16/// Defines a sprite sheet with uniform frame grid dimensions.
17#[derive(Clone, Data, Debug, New, PartialEq)]
18pub struct SpriteSheet {
19    /// The source image element loaded from an asset.
20    #[get_mut(pub(crate))]
21    #[set(pub(crate))]
22    pub(crate) image: HtmlImageElement,
23    /// The width of each individual frame in pixels.
24    #[get(pub(crate), type(copy))]
25    #[get_mut(pub(crate))]
26    #[set(pub(crate))]
27    pub(crate) frame_width: f64,
28    /// The height of each individual frame in pixels.
29    #[get(pub(crate), type(copy))]
30    #[get_mut(pub(crate))]
31    #[set(pub(crate))]
32    pub(crate) frame_height: f64,
33    /// The number of columns in the sprite sheet grid.
34    #[get(type(copy))]
35    #[get_mut(pub(crate))]
36    #[set(pub(crate))]
37    pub(crate) columns: u32,
38    /// The number of rows in the sprite sheet grid.
39    #[get(type(copy))]
40    #[get_mut(pub(crate))]
41    #[set(pub(crate))]
42    pub(crate) rows: u32,
43}
44
45/// A named sequence of frames that form an animation.
46#[derive(Clone, Data, Debug, New, PartialEq)]
47pub struct SpriteAnimation {
48    /// The name identifying this animation (e.g., `"idle"`, `"walk"`).
49    #[get_mut(pub(crate))]
50    #[set(pub(crate))]
51    pub(crate) name: String,
52    /// The ordered list of frames in this animation.
53    pub(crate) frames: Vec<SpriteFrame>,
54    /// The playback mode (loop, once, ping-pong).
55    #[get(type(copy))]
56    #[get_mut(pub(crate))]
57    pub(crate) mode: AnimationMode,
58}
59
60/// Manages the playback state of sprite animations.
61#[derive(Clone, Data, Debug, New, PartialEq)]
62pub struct Animator {
63    /// The currently active animation, if any.
64    #[get(type(clone))]
65    #[get_mut(pub(crate))]
66    #[new(skip)]
67    #[set(pub(crate))]
68    pub(crate) current_animation: Option<SpriteAnimation>,
69    /// The index of the current frame being displayed.
70    #[get(type(copy))]
71    #[get_mut(pub(crate))]
72    #[set(pub(crate))]
73    #[new(skip)]
74    pub(crate) current_frame_index: usize,
75    /// The elapsed time within the current frame, in seconds.
76    #[get(type(copy))]
77    #[get_mut(pub(crate))]
78    #[set(pub(crate))]
79    #[new(skip)]
80    #[get(pub(crate))]
81    pub(crate) elapsed_time: f64,
82    /// The current playback state.
83    #[get(type(copy))]
84    #[get_mut(pub(crate))]
85    pub(crate) state: AnimationState,
86    /// The direction of playback (1 = forward, -1 = backward) for ping-pong mode.
87    #[get(type(copy))]
88    #[get_mut(pub(crate))]
89    #[set(pub(crate))]
90    pub(crate) direction: i32,
91    /// Whether to flip the sprite horizontally when rendering.
92    #[get(type(copy))]
93    #[get_mut(pub(crate))]
94    #[new(skip)]
95    #[get(pub(crate))]
96    #[set(pub(crate))]
97    pub(crate) flip_x: bool,
98    /// Whether to flip the sprite vertically when rendering.
99    #[get(type(copy))]
100    #[get_mut(pub(crate))]
101    #[new(skip)]
102    #[set(pub(crate))]
103    pub(crate) flip_y: bool,
104}
105
106/// The nine source or destination sub-rectangles produced by a nine-slice split.
107///
108/// Stored as a three-by-three grid in reading order — row 0 is the top
109/// (`TOP_LEFT`, `TOP`, `TOP_RIGHT`), row 1 the middle (`LEFT`, `CENTER`,
110/// `RIGHT`), row 2 the bottom (`BOTTOM_LEFT`, `BOTTOM`, `BOTTOM_RIGHT`).
111/// The named accessors read through those indices, so callers get
112/// self-documenting access while the storage stays a single array that
113/// can be iterated directly when emitting the nine `drawImage` calls.
114#[derive(Clone, Copy, Data, Debug, New, PartialEq)]
115pub struct NineSliceRects {
116    /// The nine sub-rectangles in reading order, row-major.
117    #[get(type(copy))]
118    #[get_mut(pub(crate))]
119    #[set(pub(crate))]
120    pub(crate) grid: [[Rect; 3]; 3],
121}
122
123/// The four per-edge border insets that carve an image into nine patches.
124///
125/// This is the pure geometry half of a nine-slice: it holds no image
126/// handle, so the split can be computed and tested without a DOM. Insets
127/// are clamped so `left + right` never exceeds the source width and
128/// `top + bottom` never exceeds the source height; a degenerate center
129/// patch collapses to zero size rather than inverting.
130#[derive(Clone, Copy, Data, Debug, Default, New, PartialEq)]
131pub struct NineSliceInsets {
132    /// The left border inset in source pixels.
133    #[get(type(copy))]
134    #[get_mut(pub(crate))]
135    #[set(pub(crate))]
136    pub(crate) left: f64,
137    /// The right border inset in source pixels.
138    #[get(type(copy))]
139    #[get_mut(pub(crate))]
140    #[set(pub(crate))]
141    pub(crate) right: f64,
142    /// The top border inset in source pixels.
143    #[get(type(copy))]
144    #[get_mut(pub(crate))]
145    #[set(pub(crate))]
146    pub(crate) top: f64,
147    /// The bottom border inset in source pixels.
148    #[get(type(copy))]
149    #[get_mut(pub(crate))]
150    #[set(pub(crate))]
151    pub(crate) bottom: f64,
152}
153
154/// A source image paired with the insets that split it into nine patches.
155///
156/// Corners keep their natural size, the four edge patches stretch along
157/// one axis only, and the center patch stretches along both — so a
158/// bordered panel can be resized to any destination size without
159/// distorting its corners. The geometry itself lives on
160/// [`NineSliceInsets`]; this type only carries the image handle so it
161/// can be stored inside a deferred `DrawCommand`.
162#[derive(Clone, Data, Debug, New, PartialEq)]
163pub struct NineSlice {
164    /// The source image element containing the nine patches.
165    #[get(type(clone))]
166    #[get_mut(pub(crate))]
167    #[set(pub(crate))]
168    pub(crate) image: HtmlImageElement,
169    /// The per-edge border insets defining the split.
170    #[get(pub(crate), type(copy))]
171    #[get_mut(pub(crate))]
172    #[set(pub(crate))]
173    pub(crate) insets: NineSliceInsets,
174}
175
176/// Normalized texture coordinates for one sub-rectangle of an atlas image.
177///
178/// Values are fractions of the atlas dimensions in the range 0.0 to 1.0,
179/// with `(0.0, 0.0)` at the image's top-left corner. The V axis runs
180/// downward to match the top-left origin used by `Rect`.
181#[derive(Clone, Copy, Data, Debug, New, PartialEq)]
182pub struct UvRect {
183    /// The normalized left edge (U at the rectangle's left).
184    #[get(type(copy))]
185    #[get_mut(pub(crate))]
186    #[set(pub(crate))]
187    pub(crate) u0: f64,
188    /// The normalized top edge (V at the rectangle's top).
189    #[get(type(copy))]
190    #[get_mut(pub(crate))]
191    #[set(pub(crate))]
192    pub(crate) v0: f64,
193    /// The normalized right edge (U at the rectangle's right).
194    #[get(type(copy))]
195    #[get_mut(pub(crate))]
196    #[set(pub(crate))]
197    pub(crate) u1: f64,
198    /// The normalized bottom edge (V at the rectangle's bottom).
199    #[get(type(copy))]
200    #[get_mut(pub(crate))]
201    #[set(pub(crate))]
202    pub(crate) v1: f64,
203}
204
205/// The name-to-rectangle index of a sprite atlas, without the image handle.
206///
207/// Separating the index from the image keeps the lookup half of an atlas
208/// free of any DOM dependency, so region bookkeeping can be exercised
209/// without a live `HtmlImageElement`.
210#[derive(Clone, Data, Debug, Default, New, PartialEq)]
211pub struct AtlasRegions {
212    /// The named source rectangles keyed by sprite name.
213    #[get_mut(pub(crate))]
214    #[get(pub(crate))]
215    #[set(pub(crate))]
216    pub(crate) regions: HashMap<String, Rect>,
217}
218
219/// A named collection of sprite regions packed into one shared image.
220///
221/// Packing many sprites into a single texture keeps the number of canvas
222/// draw calls (and image decode stalls) low. Each entry stores a source
223/// rectangle in pixels; [`SpriteAtlas::uv`] converts it to normalized
224/// coordinates for GPU samplers, and [`SpriteAtlas::draw`] blits it
225/// directly through the 2D canvas API.
226#[derive(Clone, Data, Debug, New, PartialEq)]
227pub struct SpriteAtlas {
228    /// The shared image element holding every packed sprite.
229    #[get(type(clone))]
230    #[get_mut(pub(crate))]
231    #[set(pub(crate))]
232    pub(crate) image: HtmlImageElement,
233    /// The named source rectangles keyed by sprite name.
234    #[get(pub(crate), type(clone))]
235    #[get_mut(pub(crate))]
236    #[set(pub(crate))]
237    pub(crate) regions: AtlasRegions,
238}