1pub type Point2 = cgmath::Point2<f32>;
2pub type Vector2 = cgmath::Vector2<f32>;
3
4use crate::graphics::DrawParam;
5use cgmath::{Matrix4, Transform, Vector4};
6
7#[derive(Debug, Clone)]
8#[repr(C)]
9pub(crate) struct InstanceAttributes {
10 pub source: Vector4<f32>,
11 pub color: Vector4<f32>,
12 pub model: Matrix4<f32>,
13}
14
15impl Default for InstanceAttributes {
16 fn default() -> InstanceAttributes {
17 InstanceAttributes {
18 source: Vector4::new(0., 0., 0., 0.),
19 color: Vector4::new(0., 0., 0., 0.),
20 model: Matrix4::one(),
21 }
22 }
23}
24
25impl From<&DrawParam> for InstanceAttributes {
26 fn from(param: &DrawParam) -> Self {
27 InstanceAttributes {
28 model: param.trans.to_bare_matrix().into(),
29 source: Vector4::new(param.src.x, param.src.y, param.src.w, param.src.h),
30 color: Vector4::new(param.color.r, param.color.g, param.color.b, param.color.a),
31 }
32 }
33}
34
35#[derive(Copy, Clone, PartialEq, Debug, Default, Serialize, Deserialize)]
40pub struct Rect {
41 pub x: f32,
43 pub y: f32,
45 pub w: f32,
47 pub h: f32,
49}
50
51impl Rect {
52 pub const fn new(x: f32, y: f32, w: f32, h: f32) -> Self {
54 Rect { x, y, w, h }
55 }
56
57 pub fn fraction(x: f32, y: f32, w: f32, h: f32, reference: &Rect) -> Rect {
60 Rect {
61 x: x / reference.w,
62 y: y / reference.h,
63 w: w / reference.w,
64 h: h / reference.h,
65 }
66 }
67
68 pub const fn new_i32(x: i32, y: i32, w: i32, h: i32) -> Self {
70 Rect {
71 x: x as f32,
72 y: y as f32,
73 w: w as f32,
74 h: h as f32,
75 }
76 }
77
78 pub const fn zero() -> Self {
80 Self::new(0.0, 0.0, 0.0, 0.0)
81 }
82
83 pub const fn one() -> Self {
85 Self::new(0.0, 0.0, 1.0, 1.0)
86 }
87
88 pub fn point(&self) -> mint::Point2<f32> {
90 mint::Point2 {
91 x: self.x,
92 y: self.y,
93 }
94 }
95
96 pub fn center(&self) -> mint::Point2<f32> {
98 mint::Point2 {
99 x: self.x + self.w / 2.,
100 y: self.y + self.h / 2.,
101 }
102 }
103
104 pub fn left(&self) -> f32 {
106 self.x
107 }
108
109 pub fn right(&self) -> f32 {
111 self.x + self.w
112 }
113
114 pub fn top(&self) -> f32 {
116 self.y
117 }
118
119 pub fn bottom(&self) -> f32 {
121 self.y + self.h
122 }
123
124 pub fn contains<P: Into<mint::Point2<f32>>>(&self, point: P) -> bool {
126 let point: mint::Point2<_> = point.into();
127
128 point.x >= self.left()
129 && point.x <= self.right()
130 && point.y <= self.bottom()
131 && point.y >= self.top()
132 }
133
134 pub fn overlaps(&self, other: &Rect) -> bool {
136 self.left() <= other.right()
137 && self.right() >= other.left()
138 && self.top() <= other.bottom()
139 && self.bottom() >= other.top()
140 }
141
142 pub fn translate<V: Into<mint::Vector2<f32>>>(&mut self, offset: V) {
144 let offset: mint::Vector2<f32> = offset.into();
145
146 self.x += offset.x;
147 self.y += offset.y;
148 }
149
150 pub fn move_to<P: Into<mint::Point2<f32>>>(&mut self, destination: P) {
152 let destination = destination.into();
153
154 self.x = destination.x;
155 self.y = destination.y;
156 }
157
158 pub fn scale(&mut self, sx: f32, sy: f32) {
161 self.w *= sx;
162 self.h *= sy;
163 }
164
165 pub fn combine_with(self, other: Rect) -> Rect {
167 let x = f32::min(self.x, other.x);
168 let y = f32::min(self.y, other.y);
169 let w = f32::max(self.right(), other.right()) - x;
170 let h = f32::max(self.bottom(), other.bottom()) - y;
171 Rect { x, y, w, h }
172 }
173
174 pub fn rotate(&mut self, rotation: f32) {
176 use cgmath::{Basis2, Rotation, Rotation2};
177
178 let rotation: Basis2<f32> = Rotation2::from_angle(cgmath::Rad(rotation));
179 let x0 = self.x;
180 let y0 = self.y;
181 let x1 = self.right();
182 let y1 = self.bottom();
183 let points = [
184 rotation.rotate_point(cgmath::Point2::new(x0, y0)),
185 rotation.rotate_point(cgmath::Point2::new(x0, y1)),
186 rotation.rotate_point(cgmath::Point2::new(x1, y0)),
187 rotation.rotate_point(cgmath::Point2::new(x1, y1)),
188 ];
189 let p0 = points[0];
190 let mut x_max = p0.x;
191 let mut x_min = p0.x;
192 let mut y_max = p0.y;
193 let mut y_min = p0.y;
194 for p in &points {
195 x_max = f32::max(x_max, p.x);
196 x_min = f32::min(x_min, p.x);
197 y_max = f32::max(y_max, p.y);
198 y_min = f32::min(y_min, p.y);
199 }
200 *self = Rect {
201 w: x_max - x_min,
202 h: y_max - y_min,
203 x: x_min,
204 y: y_min,
205 }
206 }
207}
208
209impl approx::AbsDiffEq for Rect {
210 type Epsilon = f32;
211
212 fn default_epsilon() -> Self::Epsilon {
213 f32::default_epsilon()
214 }
215
216 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
217 f32::abs_diff_eq(&self.x, &other.x, epsilon)
218 && f32::abs_diff_eq(&self.y, &other.y, epsilon)
219 && f32::abs_diff_eq(&self.w, &other.w, epsilon)
220 && f32::abs_diff_eq(&self.h, &other.h, epsilon)
221 }
222}
223
224impl approx::RelativeEq for Rect {
225 fn default_max_relative() -> Self::Epsilon {
226 f32::default_max_relative()
227 }
228
229 fn relative_eq(
230 &self,
231 other: &Self,
232 epsilon: Self::Epsilon,
233 max_relative: Self::Epsilon,
234 ) -> bool {
235 f32::relative_eq(&self.x, &other.x, epsilon, max_relative)
236 && f32::relative_eq(&self.y, &other.y, epsilon, max_relative)
237 && f32::relative_eq(&self.w, &other.w, epsilon, max_relative)
238 && f32::relative_eq(&self.h, &other.h, epsilon, max_relative)
239 }
240}
241
242impl From<[f32; 4]> for Rect {
243 fn from(val: [f32; 4]) -> Self {
244 Rect::new(val[0], val[1], val[2], val[3])
245 }
246}
247
248impl From<Rect> for [f32; 4] {
249 fn from(val: Rect) -> Self {
250 [val.x, val.y, val.w, val.h]
251 }
252}
253
254#[derive(Copy, Clone, PartialEq, Debug)]
258pub struct Color {
259 pub r: f32,
261 pub g: f32,
263 pub b: f32,
265 pub a: f32,
267}
268
269impl Color {
270 pub const WHITE: Color = Color {
272 r: 1.0,
273 g: 1.0,
274 b: 1.0,
275 a: 1.0,
276 };
277
278 pub const BLACK: Color = Color {
280 r: 0.0,
281 g: 0.0,
282 b: 0.0,
283 a: 1.0,
284 };
285
286 pub const RED: Color = Color {
288 r: 1.0,
289 g: 0.0,
290 b: 0.0,
291 a: 1.0,
292 };
293
294 pub const GREEN: Color = Color {
296 r: 0.0,
297 g: 1.0,
298 b: 0.0,
299 a: 1.0,
300 };
301
302 pub const BLUE: Color = Color {
304 r: 0.0,
305 g: 0.0,
306 b: 1.0,
307 a: 1.0,
308 };
309
310 pub const CYAN: Color = Color {
312 r: 0.0,
313 g: 1.0,
314 b: 1.0,
315 a: 1.0,
316 };
317
318 pub const MAGENTA: Color = Color {
320 r: 1.0,
321 g: 0.0,
322 b: 1.0,
323 a: 1.0,
324 };
325
326 pub const YELLOW: Color = Color {
328 r: 1.0,
329 g: 1.0,
330 b: 0.0,
331 a: 1.0,
332 };
333
334 pub const fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
336 Color { r, g, b, a }
337 }
338
339 pub fn from_rgba(r: u8, g: u8, b: u8, a: u8) -> Color {
341 Color::from((r, g, b, a))
342 }
343
344 pub fn from_rgb(r: u8, g: u8, b: u8) -> Color {
347 Color::from((r, g, b))
348 }
349
350 pub fn to_rgba(self) -> (u8, u8, u8, u8) {
353 self.into()
354 }
355
356 pub fn to_rgb(self) -> (u8, u8, u8) {
359 self.into()
360 }
361
362 pub fn from_rgba_u32(c: u32) -> Color {
364 let c = c.to_be_bytes();
365
366 Color::from((c[0], c[1], c[2], c[3]))
367 }
368
369 pub fn from_rgb_u32(c: u32) -> Color {
372 let c = c.to_be_bytes();
373
374 Color::from((c[1], c[2], c[3]))
375 }
376
377 pub fn to_rgba_u32(self) -> u32 {
379 let (r, g, b, a): (u8, u8, u8, u8) = self.into();
380
381 u32::from_be_bytes([r, g, b, a])
382 }
383
384 pub fn to_rgb_u32(self) -> u32 {
386 let (r, g, b, _a): (u8, u8, u8, u8) = self.into();
387
388 u32::from_be_bytes([0, r, g, b])
389 }
390}
391
392impl From<(u8, u8, u8, u8)> for Color {
393 fn from(val: (u8, u8, u8, u8)) -> Self {
395 let (r, g, b, a) = val;
396 let rf = (f32::from(r)) / 255.0;
397 let gf = (f32::from(g)) / 255.0;
398 let bf = (f32::from(b)) / 255.0;
399 let af = (f32::from(a)) / 255.0;
400 Color::new(rf, gf, bf, af)
401 }
402}
403
404impl From<(u8, u8, u8)> for Color {
405 fn from(val: (u8, u8, u8)) -> Self {
408 let (r, g, b) = val;
409 Color::from((r, g, b, 255))
410 }
411}
412
413impl From<[f32; 4]> for Color {
414 fn from(val: [f32; 4]) -> Self {
417 Color::new(val[0], val[1], val[2], val[3])
418 }
419}
420
421impl From<(f32, f32, f32)> for Color {
422 fn from(val: (f32, f32, f32)) -> Self {
425 let (r, g, b) = val;
426 Color::new(r, g, b, 1.0)
427 }
428}
429
430impl From<(f32, f32, f32, f32)> for Color {
431 fn from(val: (f32, f32, f32, f32)) -> Self {
433 let (r, g, b, a) = val;
434 Color::new(r, g, b, a)
435 }
436}
437
438impl From<Color> for (u8, u8, u8, u8) {
439 fn from(color: Color) -> Self {
441 let r = (color.r * 255.0) as u8;
442 let g = (color.g * 255.0) as u8;
443 let b = (color.b * 255.0) as u8;
444 let a = (color.a * 255.0) as u8;
445 (r, g, b, a)
446 }
447}
448
449impl From<Color> for (u8, u8, u8) {
450 fn from(color: Color) -> Self {
453 let (r, g, b, _) = color.into();
454 (r, g, b)
455 }
456}
457
458impl From<Color> for [f32; 4] {
459 fn from(color: Color) -> Self {
461 [color.r, color.g, color.b, color.a]
462 }
463}
464
465#[allow(clippy::from_over_into)]
466impl Into<String> for Color {
467 fn into(self) -> String {
468 format!(
469 "#{:02x}{:02x}{:02x}{:02x}",
470 (self.r * 255.) as i32,
471 (self.g * 255.) as i32,
472 (self.b * 255.) as i32,
473 (self.a * 255.) as i32
474 )
475 }
476}
477
478#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize)]
481pub(crate) struct LinearColor {
482 pub r: f32,
484 pub g: f32,
486 pub b: f32,
488 pub a: f32,
490}
491
492impl From<Color> for LinearColor {
493 fn from(c: Color) -> Self {
496 fn f(component: f32) -> f32 {
497 let a = 0.055;
498 if component <= 0.04045 {
499 component / 12.92
500 } else {
501 ((component + a) / (1.0 + a)).powf(2.4)
502 }
503 }
504 LinearColor {
505 r: f(c.r),
506 g: f(c.g),
507 b: f(c.b),
508 a: c.a,
509 }
510 }
511}
512
513impl From<LinearColor> for Color {
514 fn from(c: LinearColor) -> Self {
515 fn f(component: f32) -> f32 {
516 let a = 0.055;
517 if component <= 0.003_130_8 {
518 component * 12.92
519 } else {
520 (1.0 + a) * component.powf(1.0 / 2.4)
521 }
522 }
523 Color {
524 r: f(c.r),
525 g: f(c.g),
526 b: f(c.b),
527 a: c.a,
528 }
529 }
530}
531
532impl From<LinearColor> for [f32; 4] {
533 fn from(color: LinearColor) -> Self {
534 [color.r, color.g, color.b, color.a]
535 }
536}
537
538#[cfg(feature = "mesh")]
539mod draw_mode {
540 use crate::graphics::{FillOptions, StrokeOptions};
541
542 #[derive(Debug, Copy, Clone)]
545 pub enum DrawMode {
546 Stroke(crate::graphics::StrokeOptions),
548 Fill(crate::graphics::FillOptions),
550 }
551
552 impl DrawMode {
553 pub fn stroke(width: f32) -> DrawMode {
555 DrawMode::Stroke(StrokeOptions::default().with_line_width(width))
556 }
557
558 pub fn fill() -> DrawMode {
560 DrawMode::Fill(FillOptions::default())
561 }
562 }
563}
564
565#[cfg(feature = "mesh")]
566pub use draw_mode::*;