1use std::ops::{Add, Mul, Sub};
2
3pub trait Components<T, const N: usize>: Copy {
13 fn to_array(self) -> [T; N];
15 fn from_array(a: [T; N]) -> Self;
17}
18
19pub fn componentwise_min<T: PartialOrd + Copy, C: Components<T, N>, const N: usize>(a: C, b: C) -> C {
24 let (a, b) = (a.to_array(), b.to_array());
25 let mut out = a;
26 for i in 0..N {
27 if b[i] < out[i] {
28 out[i] = b[i];
29 }
30 }
31 C::from_array(out)
32}
33
34pub fn componentwise_max<T: PartialOrd + Copy, C: Components<T, N>, const N: usize>(a: C, b: C) -> C {
39 let (a, b) = (a.to_array(), b.to_array());
40 let mut out = a;
41 for i in 0..N {
42 if b[i] > out[i] {
43 out[i] = b[i];
44 }
45 }
46 C::from_array(out)
47}
48
49#[derive(Copy, Clone, Debug, PartialEq)]
61pub struct Size2D {
62 pub w: u32,
63 pub h: u32,
64}
65
66impl Components<u32, 2> for Size2D {
67 fn to_array(self) -> [u32; 2] { [self.w, self.h] }
68 fn from_array(a: [u32; 2]) -> Self { Size2D { w: a[0], h: a[1] } }
69}
70
71impl From<[u32; 2]> for Size2D { fn from(a: [u32; 2]) -> Self { Size2D::from_array(a) } }
72impl From<Size2D> for [u32; 2] { fn from(s: Size2D) -> Self { s.to_array() } }
73impl From<(u32, u32)> for Size2D { fn from(t: (u32, u32)) -> Self { Size2D { w: t.0, h: t.1 } } }
74
75macro_rules! impl_size_ops {
76 ($ty:ty, $n:literal) => {
77 impl Add for $ty {
78 type Output = Self;
79 fn add(self, rhs: Self) -> Self {
80 let (a, b) = (self.to_array(), rhs.to_array());
81 let mut out = [0u32; $n];
82 for i in 0..$n { out[i] = a[i].saturating_add(b[i]); }
83 Self::from_array(out)
84 }
85 }
86 impl Sub for $ty {
87 type Output = Self;
88 fn sub(self, rhs: Self) -> Self {
89 let (a, b) = (self.to_array(), rhs.to_array());
90 let mut out = [0u32; $n];
91 for i in 0..$n { out[i] = a[i].saturating_sub(b[i]); }
92 Self::from_array(out)
93 }
94 }
95 impl Mul<f32> for $ty {
96 type Output = Self;
97 fn mul(self, rhs: f32) -> Self {
98 let a = self.to_array();
99 let mut out = [0u32; $n];
100 for i in 0..$n { out[i] = ((a[i] as f32) * rhs).round().max(0.0) as u32; }
101 Self::from_array(out)
102 }
103 }
104 };
105}
106
107impl_size_ops!(Size2D, 2);
108
109impl Size2D {
110 pub fn empty() -> Size2D {
112 Self { w: 0, h: 0 }
113 }
114 pub fn from(w: u32, h: u32) -> Self {
116 Self { w, h }
117 }
118 pub fn shave(&self, n: u32) -> Size2D {
120 Size2D {
121 w: self.w.saturating_sub(n),
122 h: self.h.saturating_sub(n),
123 }
124 }
125 pub fn aspect_ratio(&self) -> f32 {
127 self.w as f32 / self.h.max(1) as f32
128 }
129 pub fn is_empty(&self) -> bool {
131 self.w == 0 || self.h == 0
132 }
133 pub fn area(&self) -> u64 {
135 self.w as u64 * self.h as u64
136 }
137 pub fn min(&self, other: Size2D) -> Size2D {
139 componentwise_min(*self, other)
140 }
141 pub fn max(&self, other: Size2D) -> Size2D {
143 componentwise_max(*self, other)
144 }
145 pub fn fit_within(&self, max: Size2D) -> Size2D {
149 if self.w <= max.w && self.h <= max.h { return *self; }
150 let scale = (max.w as f32 / self.w as f32).min(max.h as f32 / self.h as f32);
151 *self * scale
152 }
153 pub fn scaled_to_width(&self, w: u32) -> Size2D {
155 let scale = w as f32 / self.w.max(1) as f32;
156 *self * scale
157 }
158 pub fn scaled_to_height(&self, h: u32) -> Size2D {
160 let scale = h as f32 / self.h.max(1) as f32;
161 *self * scale
162 }
163 pub fn to_size3d(&self, depth: u32) -> Size3D {
165 Size3D { w: self.w, h: self.h, d: depth }
166 }
167}
168
169#[derive(Copy, Clone, Debug, PartialEq)]
171pub struct Size3D {
172 pub w: u32,
173 pub h: u32,
174 pub d: u32,
175}
176
177impl Components<u32, 3> for Size3D {
178 fn to_array(self) -> [u32; 3] { [self.w, self.h, self.d] }
179 fn from_array(a: [u32; 3]) -> Self { Size3D { w: a[0], h: a[1], d: a[2] } }
180}
181
182impl From<[u32; 3]> for Size3D { fn from(a: [u32; 3]) -> Self { Size3D::from_array(a) } }
183impl From<Size3D> for [u32; 3] { fn from(s: Size3D) -> Self { s.to_array() } }
184impl From<(u32, u32, u32)> for Size3D { fn from(t: (u32, u32, u32)) -> Self { Size3D { w: t.0, h: t.1, d: t.2 } } }
185
186impl_size_ops!(Size3D, 3);
187
188impl Size3D {
189 pub fn empty() -> Size3D {
191 Self { w: 0, h: 0, d: 0 }
192 }
193 pub fn from(w: u32, h: u32, d: u32) -> Self {
195 Self { w, h, d }
196 }
197 pub fn shave(&self, n: u32) -> Size3D {
199 Size3D {
200 w: self.w.saturating_sub(n),
201 h: self.h.saturating_sub(n),
202 d: self.d.saturating_sub(n),
203 }
204 }
205 pub fn is_empty(&self) -> bool {
207 self.w == 0 || self.h == 0 || self.d == 0
208 }
209 pub fn volume(&self) -> u64 {
211 self.w as u64 * self.h as u64 * self.d as u64
212 }
213 pub fn min(&self, other: Size3D) -> Size3D {
215 componentwise_min(*self, other)
216 }
217 pub fn max(&self, other: Size3D) -> Size3D {
219 componentwise_max(*self, other)
220 }
221 pub fn to_size2d(&self) -> Size2D {
223 Size2D { w: self.w, h: self.h }
224 }
225}
226
227#[derive(Clone, Copy, Debug)]
229pub struct ClipDist {
230 pub near: f32,
231 pub far: f32,
232}
233
234impl Default for ClipDist {
235 fn default() -> Self {
236 ClipDist::from(0.01, 1000.0)
237 }
238}
239
240impl ClipDist {
241 pub fn from(near: f32, far: f32) -> ClipDist {
242 ClipDist { near, far }
243 }
244}
245
246#[derive(Clone, Copy, Debug, PartialEq)]
248pub enum CamProj {
249 Ortho,
250 Persp,
251}