1use wasm4fun_core::{blit, blit_sub, BLIT_FLIP_X, BLIT_FLIP_Y, BLIT_ROTATE};
10
11#[derive(Copy, Clone)]
13pub enum Rotation {
14 Rotate0,
16
17 Rotate90,
19
20 Rotate180,
22
23 Rotate270,
25}
26
27impl Rotation {
28 pub const fn add(&self, other: Rotation) -> Self {
30 match (self, other) {
31 (Self::Rotate0, other) => other,
32 (self2, Self::Rotate0) => *self2,
33 (Self::Rotate90, Self::Rotate90) => Self::Rotate180,
34 (Self::Rotate90, Self::Rotate180) => Self::Rotate270,
35 (Self::Rotate90, Self::Rotate270) => Self::Rotate0,
36 (Self::Rotate180, Self::Rotate90) => Self::Rotate270,
37 (Self::Rotate180, Self::Rotate180) => Self::Rotate0,
38 (Self::Rotate180, Self::Rotate270) => Self::Rotate90,
39 (Self::Rotate270, Self::Rotate90) => Self::Rotate0,
40 (Self::Rotate270, Self::Rotate180) => Self::Rotate90,
41 (Self::Rotate270, Self::Rotate270) => Self::Rotate180,
42 }
43 }
44}
45
46#[derive(Clone, Copy)]
66pub struct SpriteViewImpl<'a> {
67 sprite: &'a Sprite<'a>,
68 rotation: Rotation,
69 src_x: u32,
70 src_y: u32,
71 width: u32,
72 height: u32,
73 flip_horizontal: bool,
74 flip_vertical: bool,
75}
76
77impl<'a> SpriteViewImpl<'a> {
78 pub const fn new(sprite: &'a Sprite) -> Self {
80 Self {
81 sprite,
82 rotation: Rotation::Rotate0,
83 src_x: 0,
84 src_y: 0,
85 width: sprite.width,
86 height: sprite.height,
87 flip_horizontal: false,
88 flip_vertical: false,
89 }
90 }
91
92 pub const fn width(&self) -> u32 {
94 self.width
95 }
96
97 pub const fn height(&self) -> u32 {
99 self.height
100 }
101
102 pub const fn rotate(&self, rotation: Rotation) -> Self {
104 let mut new = *self;
105 new.rotation = new.rotation.add(rotation);
106 new
107 }
108
109 pub const fn flip_horizontally(&self, flip_horizontally: bool) -> Self {
111 let mut new = *self;
112 new.flip_horizontal = flip_horizontally;
113 new
114 }
115
116 pub const fn flip_vertically(&self, flip_vertically: bool) -> Self {
118 let mut new = *self;
119 new.flip_vertical = flip_vertically;
120 new
121 }
122
123 pub const fn clip(&self, src_x: u32, src_y: u32, width: u32, height: u32) -> Self {
125 let mut new = *self;
126 new.src_x += src_x;
127 new.src_y += src_y;
128 new.width = width;
129 new.height = height;
130 new
131 }
132
133 pub fn blit(&self, x: i32, y: i32) {
138 let flags = match (&self.rotation, &self.flip_horizontal, &self.flip_vertical) {
139 (Rotation::Rotate0, false, false) => 0,
140 (Rotation::Rotate90, false, false) => BLIT_FLIP_X | BLIT_FLIP_Y | BLIT_ROTATE,
141 (Rotation::Rotate180, false, false) => BLIT_FLIP_X | BLIT_FLIP_Y,
142 (Rotation::Rotate270, false, false) => BLIT_ROTATE,
143
144 (Rotation::Rotate0, false, true) => BLIT_FLIP_Y,
145 (Rotation::Rotate90, false, true) => BLIT_FLIP_X | BLIT_ROTATE,
146 (Rotation::Rotate180, false, true) => BLIT_FLIP_X,
147 (Rotation::Rotate270, false, true) => BLIT_FLIP_Y | BLIT_ROTATE,
148
149 (Rotation::Rotate0, true, false) => BLIT_FLIP_X,
150 (Rotation::Rotate90, true, false) => BLIT_FLIP_Y | BLIT_ROTATE,
151 (Rotation::Rotate180, true, false) => BLIT_FLIP_Y,
152 (Rotation::Rotate270, true, false) => BLIT_FLIP_X | BLIT_ROTATE,
153
154 (Rotation::Rotate0, true, true) => BLIT_FLIP_X | BLIT_FLIP_Y,
155 (Rotation::Rotate90, true, true) => BLIT_ROTATE,
156 (Rotation::Rotate180, true, true) => 0,
157 (Rotation::Rotate270, true, true) => BLIT_FLIP_X | BLIT_FLIP_Y | BLIT_ROTATE,
158 };
159
160 self.sprite.blit_sub_with_flags(
161 x,
162 y,
163 self.width,
164 self.height,
165 self.src_x,
166 self.src_y,
167 flags,
168 );
169 }
170}
171
172impl<'a> From<&'a Sprite<'a>> for SpriteViewImpl<'a> {
173 fn from(sprite: &'a Sprite) -> Self {
174 Self::new(sprite)
175 }
176}
177
178#[derive(Clone, Debug)]
208pub struct Sprite<'a> {
209 width: u32,
210 height: u32,
211 flags: u32,
212 data: &'a [u8],
213}
214
215impl<'a> Sprite<'a> {
216 pub const fn new(width: u32, height: u32, flags: u32, data: &'a [u8]) -> Self {
218 Self {
219 width,
220 height,
221 flags,
222 data,
223 }
224 }
225
226 pub const fn width(&self) -> u32 {
228 self.width
229 }
230
231 pub const fn height(&self) -> u32 {
233 self.height
234 }
235
236 pub const fn rotate(&self, rotation: Rotation) -> SpriteViewImpl {
238 let view = SpriteViewImpl::new(self);
239 SpriteViewImpl::rotate(&view, rotation)
240 }
241
242 pub fn flip_horizontally(&self, flip_horizontally: bool) -> SpriteViewImpl {
244 let view = SpriteViewImpl::new(self);
245 SpriteViewImpl::flip_horizontally(&view, flip_horizontally)
246 }
247
248 pub const fn flip_vertically(&self, flip_vertically: bool) -> SpriteViewImpl {
250 let view = SpriteViewImpl::new(self);
251 SpriteViewImpl::flip_vertically(&view, flip_vertically)
252 }
253
254 pub const fn clip(&self, src_x: u32, src_y: u32, width: u32, height: u32) -> SpriteViewImpl {
256 let view = SpriteViewImpl::new(self);
257 SpriteViewImpl::clip(&view, src_x, src_y, width, height)
258 }
259
260 pub fn blit(&self, x: i32, y: i32) {
264 blit(self.data, x, y, self.width, self.height, self.flags);
265 }
266
267 #[allow(clippy::too_many_arguments)]
273 fn blit_sub_with_flags(
274 &self,
275 x: i32,
276 y: i32,
277 width: u32,
278 height: u32,
279 src_x: u32,
280 src_y: u32,
281 flags: u32,
282 ) {
283 blit_sub(
284 self.data,
285 x,
286 y,
287 width,
288 height,
289 src_x,
290 src_y,
291 self.width,
292 self.flags | flags,
293 );
294 }
295}
296
297pub trait SpriteView<'a> {
306 fn width(&self) -> u32;
308
309 fn height(&self) -> u32;
311
312 fn rotate(&'a self, rotation: Rotation) -> SpriteViewImpl<'a>;
314
315 fn flip_horizontally(&'a self, flip_horizontally: bool) -> SpriteViewImpl<'a>;
317
318 fn flip_vertically(&'a self, flip_vertically: bool) -> SpriteViewImpl<'a>;
320
321 fn clip(&'a self, src_x: u32, src_y: u32, width: u32, height: u32) -> SpriteViewImpl<'a>;
323
324 fn blit(&self, x: i32, y: i32);
329}
330
331impl<'a> SpriteView<'a> for SpriteViewImpl<'a> {
332 fn width(&self) -> u32 {
333 SpriteViewImpl::width(self)
334 }
335
336 fn height(&self) -> u32 {
337 SpriteViewImpl::height(self)
338 }
339
340 fn rotate(&'a self, rotation: Rotation) -> SpriteViewImpl<'a> {
341 SpriteViewImpl::rotate(self, rotation)
342 }
343
344 fn flip_horizontally(&'a self, flip_horizontally: bool) -> SpriteViewImpl<'a> {
345 SpriteViewImpl::flip_horizontally(self, flip_horizontally)
346 }
347
348 fn flip_vertically(&'a self, flip_vertically: bool) -> SpriteViewImpl<'a> {
349 SpriteViewImpl::flip_vertically(self, flip_vertically)
350 }
351
352 fn clip(&'a self, src_x: u32, src_y: u32, width: u32, height: u32) -> SpriteViewImpl<'a> {
353 SpriteViewImpl::clip(self, src_x, src_y, width, height)
354 }
355
356 fn blit(&self, x: i32, y: i32) {
357 SpriteViewImpl::blit(self, x, y)
358 }
359}
360
361impl<'a> SpriteView<'a> for Sprite<'a> {
362 fn width(&self) -> u32 {
363 Sprite::width(self)
364 }
365
366 fn height(&self) -> u32 {
367 Sprite::height(self)
368 }
369
370 fn rotate(&'a self, rotation: Rotation) -> SpriteViewImpl<'a> {
371 Sprite::rotate(self, rotation)
372 }
373
374 fn flip_horizontally(&'a self, flip_horizontally: bool) -> SpriteViewImpl<'a> {
375 Sprite::flip_horizontally(self, flip_horizontally)
376 }
377
378 fn flip_vertically(&'a self, flip_vertically: bool) -> SpriteViewImpl<'a> {
379 Sprite::flip_vertically(self, flip_vertically)
380 }
381
382 fn clip(&'a self, src_x: u32, src_y: u32, width: u32, height: u32) -> SpriteViewImpl<'a> {
383 Sprite::clip(self, src_x, src_y, width, height)
384 }
385
386 fn blit(&self, x: i32, y: i32) {
387 Sprite::blit(self, x, y)
388 }
389}