1use core::{Ignite, Scalar};
2use serde::{Deserialize, Serialize};
3use std::ops::{Add, Div, Mul, Neg, Not, Sub};
4
5#[inline]
6pub fn lerp(a: Scalar, b: Scalar, f: Scalar) -> Scalar {
7 (b - a) * f + a
8}
9
10#[inline]
11pub fn lerp_clamped(a: Scalar, b: Scalar, f: Scalar) -> Scalar {
12 lerp(a, b, f.max(0.0).min(1.0))
13}
14
15#[inline]
16pub fn unlerp(a: Scalar, b: Scalar, v: Scalar) -> Scalar {
17 (v - a) / (b - a)
18}
19
20#[derive(Ignite, Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
21pub struct Mat2d(pub [Scalar; 6]);
22
23impl Default for Mat2d {
24 fn default() -> Self {
25 Self([1.0, 0.0, 0.0, 1.0, 0.0, 0.0])
26 }
27}
28
29impl Mat2d {
30 pub fn new(cells: [Scalar; 6]) -> Self {
31 Self(cells)
32 }
33
34 pub fn new_complex(translation: Vec2, rotation: Scalar, scale: Vec2) -> Self {
35 let t = Self::translation(translation);
36 let r = Self::rotation(rotation);
37 let s = Self::scale(scale);
38 t * r * s
39 }
40
41 pub fn translation(value: Vec2) -> Self {
42 Self([1.0, 0.0, 0.0, 1.0, value.x, value.y])
43 }
44
45 pub fn rotation(value: Scalar) -> Self {
46 let (sin, cos) = value.sin_cos();
47 Self([cos, sin, -sin, cos, 0.0, 0.0])
48 }
49
50 pub fn scale(value: Vec2) -> Self {
51 Self([value.x, 0.0, 0.0, value.y, 0.0, 0.0])
52 }
53
54 pub fn skew(value: Vec2) -> Self {
55 Self([1.0, value.y.tan(), value.x.tan(), 1.0, 0.0, 0.0])
56 }
57
58 pub fn inverse(self) -> Option<Self> {
59 !self
60 }
61}
62
63impl Mul for Mat2d {
64 type Output = Self;
65
66 fn mul(self, other: Self) -> Self {
67 Self([
68 self.0[0] * other.0[0] + self.0[2] * other.0[1],
69 self.0[1] * other.0[0] + self.0[3] * other.0[1],
70 self.0[0] * other.0[2] + self.0[2] * other.0[3],
71 self.0[1] * other.0[2] + self.0[3] * other.0[3],
72 self.0[0] * other.0[4] + self.0[2] * other.0[5] + self.0[4],
73 self.0[1] * other.0[4] + self.0[3] * other.0[5] + self.0[5],
74 ])
75 }
76}
77
78impl Mul<Vec2> for Mat2d {
79 type Output = Vec2;
80
81 fn mul(self, other: Vec2) -> Vec2 {
82 other * self
83 }
84}
85
86impl Not for Mat2d {
87 type Output = Option<Self>;
88
89 fn not(self) -> Option<Self> {
90 let det = self.0[0] * self.0[3] - self.0[1] * self.0[2];
91 if det == 0.0 {
92 return None;
93 }
94 let det = 1.0 / det;
95 Some(Self([
96 self.0[3] * det,
97 -self.0[1] * det,
98 -self.0[2] * det,
99 self.0[0] * det,
100 (self.0[2] * self.0[5] - self.0[3] * self.0[4]) * det,
101 (self.0[1] * self.0[4] - self.0[0] * self.0[5]) * det,
102 ]))
103 }
104}
105
106impl From<[Scalar; 6]> for Mat2d {
107 fn from(v: [Scalar; 6]) -> Self {
108 Self(v)
109 }
110}
111
112impl From<Mat2d> for [Scalar; 6] {
113 fn from(v: Mat2d) -> Self {
114 v.0
115 }
116}
117
118impl From<(Scalar, Scalar, Scalar, Scalar, Scalar, Scalar)> for Mat2d {
119 fn from(v: (Scalar, Scalar, Scalar, Scalar, Scalar, Scalar)) -> Self {
120 Self([v.0, v.1, v.2, v.3, v.4, v.5])
121 }
122}
123
124impl From<Mat2d> for (Scalar, Scalar, Scalar, Scalar, Scalar, Scalar) {
125 fn from(v: Mat2d) -> Self {
126 (v.0[0], v.0[1], v.0[2], v.0[3], v.0[4], v.0[5])
127 }
128}
129
130#[derive(Ignite, Debug, Default, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
131pub struct Color {
132 pub r: u8,
133 pub g: u8,
134 pub b: u8,
135 pub a: u8,
136}
137
138impl Color {
139 pub fn rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
140 Self { r, g, b, a }
141 }
142
143 pub fn rgb(r: u8, g: u8, b: u8) -> Self {
144 Self { r, g, b, a: 255 }
145 }
146
147 pub fn transparent() -> Self {
148 Self {
149 r: 0,
150 g: 0,
151 b: 0,
152 a: 0,
153 }
154 }
155
156 pub fn white() -> Self {
157 Self {
158 r: 255,
159 g: 255,
160 b: 255,
161 a: 255,
162 }
163 }
164
165 pub fn black() -> Self {
166 Self {
167 r: 0,
168 g: 0,
169 b: 0,
170 a: 255,
171 }
172 }
173
174 pub fn red() -> Self {
175 Self {
176 r: 255,
177 g: 0,
178 b: 0,
179 a: 255,
180 }
181 }
182
183 pub fn green() -> Self {
184 Self {
185 r: 0,
186 g: 255,
187 b: 0,
188 a: 255,
189 }
190 }
191
192 pub fn blue() -> Self {
193 Self {
194 r: 0,
195 g: 0,
196 b: 255,
197 a: 255,
198 }
199 }
200
201 pub fn yellow() -> Self {
202 Self {
203 r: 255,
204 g: 255,
205 b: 0,
206 a: 255,
207 }
208 }
209
210 pub fn cyan() -> Self {
211 Self {
212 r: 0,
213 g: 255,
214 b: 255,
215 a: 255,
216 }
217 }
218
219 pub fn magenta() -> Self {
220 Self {
221 r: 255,
222 g: 0,
223 b: 255,
224 a: 255,
225 }
226 }
227
228 pub fn r(mut self, value: u8) -> Self {
229 self.r = value;
230 self
231 }
232
233 pub fn g(mut self, value: u8) -> Self {
234 self.g = value;
235 self
236 }
237
238 pub fn b(mut self, value: u8) -> Self {
239 self.b = value;
240 self
241 }
242
243 pub fn a(mut self, value: u8) -> Self {
244 self.a = value;
245 self
246 }
247}
248
249impl From<(u8, u8, u8, u8)> for Color {
250 fn from(value: (u8, u8, u8, u8)) -> Self {
251 Self {
252 r: value.0,
253 g: value.1,
254 b: value.2,
255 a: value.3,
256 }
257 }
258}
259
260impl From<[u8; 4]> for Color {
261 fn from(value: [u8; 4]) -> Self {
262 Self {
263 r: value[0],
264 g: value[1],
265 b: value[2],
266 a: value[3],
267 }
268 }
269}
270
271impl ToString for Color {
272 fn to_string(&self) -> String {
273 format!(
274 "rgba({}, {}, {}, {})",
275 self.r,
276 self.g,
277 self.b,
278 Scalar::from(self.a) / 255.0
279 )
280 }
281}
282
283#[derive(Ignite, Debug, Default, Copy, Clone, PartialEq, Serialize, Deserialize)]
284pub struct Vec2 {
285 pub x: Scalar,
286 pub y: Scalar,
287}
288
289impl Vec2 {
290 #[inline]
291 pub fn new(x: Scalar, y: Scalar) -> Self {
292 Self { x, y }
293 }
294
295 #[inline]
296 pub fn zero() -> Self {
297 Self { x: 0.0, y: 0.0 }
298 }
299
300 #[inline]
301 pub fn one() -> Self {
302 Self { x: 1.0, y: 1.0 }
303 }
304
305 #[inline]
306 pub fn sqr_magnitude(self) -> Scalar {
307 self.x * self.x + self.y * self.y
308 }
309
310 #[inline]
311 pub fn magnitude(self) -> Scalar {
312 self.sqr_magnitude().sqrt()
313 }
314
315 #[inline]
316 pub fn normalized(self) -> Self {
317 self / self.magnitude()
318 }
319
320 #[inline]
321 pub fn dot(self, other: Self) -> Scalar {
322 self.x * other.x + self.y * other.y
323 }
324
325 #[inline]
326 pub fn right(self) -> Vec2 {
327 Self {
328 x: self.y,
329 y: -self.x,
330 }
331 }
332
333 #[inline]
334 pub fn is_clockwise(a: Self, b: Self) -> bool {
335 a.x * b.y - a.y * b.x > 0.0
336 }
337
338 #[inline]
339 pub fn lerp(self, other: Vec2, factor: Scalar) -> Self {
340 Self {
341 x: lerp(self.x, other.x, factor),
342 y: lerp(self.y, other.y, factor),
343 }
344 }
345
346 #[inline]
347 pub fn lerp_clamped(self, other: Vec2, factor: Scalar) -> Self {
348 Self {
349 x: lerp_clamped(self.x, other.x, factor),
350 y: lerp_clamped(self.y, other.y, factor),
351 }
352 }
353
354 #[inline]
355 pub fn project_distance(self, from: Vec2, to: Vec2) -> Scalar {
356 let u = self - from;
357 let v = to - from;
358 u.dot(v) / v.sqr_magnitude()
359 }
360
361 #[inline]
362 pub fn project(self, from: Vec2, to: Vec2) -> Vec2 {
363 (to - from) * self.project_distance(from, to)
364 }
365}
366
367impl Add for Vec2 {
368 type Output = Self;
369
370 fn add(self, other: Self) -> Self {
371 Self {
372 x: self.x + other.x,
373 y: self.y + other.y,
374 }
375 }
376}
377
378impl Add<Scalar> for Vec2 {
379 type Output = Self;
380
381 fn add(self, other: Scalar) -> Self {
382 Self {
383 x: self.x + other,
384 y: self.y + other,
385 }
386 }
387}
388
389impl Sub for Vec2 {
390 type Output = Self;
391
392 fn sub(self, other: Self) -> Self {
393 Self {
394 x: self.x - other.x,
395 y: self.y - other.y,
396 }
397 }
398}
399
400impl Sub<Scalar> for Vec2 {
401 type Output = Self;
402
403 fn sub(self, other: Scalar) -> Self {
404 Self {
405 x: self.x - other,
406 y: self.y - other,
407 }
408 }
409}
410
411impl Mul for Vec2 {
412 type Output = Self;
413
414 fn mul(self, other: Self) -> Self {
415 Self {
416 x: self.x * other.x,
417 y: self.y * other.y,
418 }
419 }
420}
421
422impl Mul<Scalar> for Vec2 {
423 type Output = Self;
424
425 fn mul(self, other: Scalar) -> Self {
426 Self {
427 x: self.x * other,
428 y: self.y * other,
429 }
430 }
431}
432
433impl Mul<Mat2d> for Vec2 {
434 type Output = Self;
435
436 fn mul(self, other: Mat2d) -> Self {
437 Self {
438 x: other.0[0] * self.x + other.0[2] * self.y + other.0[4],
439 y: other.0[1] * self.x + other.0[3] * self.y + other.0[5],
440 }
441 }
442}
443
444impl Div for Vec2 {
445 type Output = Self;
446
447 fn div(self, other: Self) -> Self {
448 Self {
449 x: self.x / other.x,
450 y: self.y / other.y,
451 }
452 }
453}
454
455impl Div<Scalar> for Vec2 {
456 type Output = Self;
457
458 fn div(self, other: Scalar) -> Self {
459 Self {
460 x: self.x / other,
461 y: self.y / other,
462 }
463 }
464}
465
466impl Neg for Vec2 {
467 type Output = Self;
468
469 fn neg(self) -> Self {
470 Self {
471 x: -self.x,
472 y: -self.y,
473 }
474 }
475}
476
477impl From<Scalar> for Vec2 {
478 fn from(value: Scalar) -> Self {
479 Self { x: value, y: value }
480 }
481}
482
483impl From<(Scalar, Scalar)> for Vec2 {
484 fn from(value: (Scalar, Scalar)) -> Self {
485 Self {
486 x: value.0,
487 y: value.1,
488 }
489 }
490}
491
492impl From<[Scalar; 2]> for Vec2 {
493 fn from(value: [Scalar; 2]) -> Self {
494 Self {
495 x: value[0],
496 y: value[1],
497 }
498 }
499}
500
501#[derive(Ignite, Debug, Default, Copy, Clone, PartialEq, Serialize, Deserialize)]
502pub struct Rect {
503 pub x: Scalar,
504 pub y: Scalar,
505 pub w: Scalar,
506 pub h: Scalar,
507}
508
509impl Rect {
510 pub fn raw(x: Scalar, y: Scalar, w: Scalar, h: Scalar) -> Self {
511 Self { x, y, w, h }
512 }
513
514 pub fn new(position: Vec2, size: Vec2) -> Self {
515 Self {
516 x: position.x,
517 y: position.y,
518 w: size.x,
519 h: size.y,
520 }
521 }
522
523 pub fn with_size(size: Vec2) -> Self {
524 Self {
525 x: 0.0,
526 y: 0.0,
527 w: size.x,
528 h: size.y,
529 }
530 }
531
532 pub fn bounding(points: &[Vec2]) -> Option<Self> {
533 points.iter().fold(None, |a, v| {
534 if let Some(a) = a {
535 Some(a.include(*v))
536 } else {
537 Some(Rect::new(*v, Vec2::zero()))
538 }
539 })
540 }
541
542 pub fn align(&self, factor: Vec2) -> Self {
543 Self {
544 x: self.x - self.w * factor.x,
545 y: self.y - self.h * factor.y,
546 w: self.w,
547 h: self.h,
548 }
549 }
550
551 pub fn expand(&self, thickness: Scalar) -> Self {
552 let tt = thickness * 2.0;
553 let mut result = Self {
554 x: self.x - thickness,
555 y: self.y - thickness,
556 w: self.w + tt,
557 h: self.h + tt,
558 };
559 result.validate();
560 result
561 }
562
563 pub fn include(&self, point: Vec2) -> Self {
564 let (x, w) = if point.x < self.x {
565 (point.x, self.w + self.x - point.x)
566 } else if point.x > self.x + self.w {
567 (self.x, point.x - self.x)
568 } else {
569 (self.x, self.w)
570 };
571 let (y, h) = if point.y < self.y {
572 (point.y, self.h + self.y - point.y)
573 } else if point.y > self.y + self.h {
574 (self.y, point.y - self.y)
575 } else {
576 (self.y, self.h)
577 };
578 Self { x, y, w, h }
579 }
580
581 pub fn validate(&mut self) {
582 if self.w < 0.0 {
583 self.x += self.w;
584 self.w = -self.w;
585 }
586 if self.h < 0.0 {
587 self.y += self.h;
588 self.h = -self.h;
589 }
590 }
591
592 pub fn center(&self) -> Vec2 {
593 Vec2::new(self.x + self.w * 0.5, self.y + self.h * 0.5)
594 }
595
596 pub fn size(&self) -> Vec2 {
597 Vec2::new(self.w, self.h)
598 }
599
600 pub fn contains_point(&self, point: Vec2) -> bool {
601 point.x > self.x
602 && point.x < self.x + self.w
603 && point.y > self.y
604 && point.y < self.y + self.h
605 }
606}
607
608impl From<(Scalar, Scalar)> for Rect {
609 fn from(value: (Scalar, Scalar)) -> Self {
610 Self {
611 x: 0.0,
612 y: 0.0,
613 w: value.0,
614 h: value.1,
615 }
616 }
617}
618
619impl From<[Scalar; 2]> for Rect {
620 fn from(value: [Scalar; 2]) -> Self {
621 Self {
622 x: 0.0,
623 y: 0.0,
624 w: value[0],
625 h: value[1],
626 }
627 }
628}
629
630impl From<(Scalar, Scalar, Scalar, Scalar)> for Rect {
631 fn from(value: (Scalar, Scalar, Scalar, Scalar)) -> Self {
632 Self {
633 x: value.0,
634 y: value.1,
635 w: value.2,
636 h: value.3,
637 }
638 }
639}
640
641impl From<[Scalar; 4]> for Rect {
642 fn from(value: [Scalar; 4]) -> Self {
643 Self {
644 x: value[0],
645 y: value[1],
646 w: value[2],
647 h: value[3],
648 }
649 }
650}