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}