1pub mod gradient;
2pub mod sprites;
3
4use std::ops::{Add, Sub};
5
6use rand::Rng;
7use vek::*;
8
9#[derive(Debug, enum_map::Enum, strum::EnumIter, enumset::EnumSetType)]
11pub enum Dir {
12 X,
13 Y,
14 NegX,
15 NegY,
16}
17
18impl Dir {
19 pub const ALL: [Dir; 4] = [Dir::X, Dir::Y, Dir::NegX, Dir::NegY];
20
21 pub fn choose(rng: &mut impl Rng) -> Dir {
22 match rng.gen_range(0..4) {
23 0 => Dir::X,
24 1 => Dir::Y,
25 2 => Dir::NegX,
26 _ => Dir::NegY,
27 }
28 }
29
30 pub fn from_vec2(vec: Vec2<i32>) -> Dir {
31 if vec.x.abs() > vec.y.abs() {
32 if vec.x > 0 { Dir::X } else { Dir::NegX }
33 } else if vec.y > 0 {
34 Dir::Y
35 } else {
36 Dir::NegY
37 }
38 }
39
40 pub fn to_dir3(self) -> Dir3 { Dir3::from_dir(self) }
41
42 #[must_use]
43 pub fn opposite(self) -> Dir {
44 match self {
45 Dir::X => Dir::NegX,
46 Dir::NegX => Dir::X,
47 Dir::Y => Dir::NegY,
48 Dir::NegY => Dir::Y,
49 }
50 }
51
52 #[must_use]
54 pub fn rotated_ccw(self) -> Dir {
55 match self {
56 Dir::X => Dir::Y,
57 Dir::NegX => Dir::NegY,
58 Dir::Y => Dir::NegX,
59 Dir::NegY => Dir::X,
60 }
61 }
62
63 #[must_use]
65 pub fn rotated_cw(self) -> Dir { self.rotated_ccw().opposite() }
66
67 #[must_use]
68 pub fn orthogonal(self) -> Dir {
69 match self {
70 Dir::X | Dir::NegX => Dir::Y,
71 Dir::Y | Dir::NegY => Dir::X,
72 }
73 }
74
75 #[must_use]
76 pub fn abs(self) -> Dir {
77 match self {
78 Dir::X | Dir::NegX => Dir::X,
79 Dir::Y | Dir::NegY => Dir::Y,
80 }
81 }
82
83 #[must_use]
84 pub fn signum(self) -> i32 {
85 match self {
86 Dir::X | Dir::Y => 1,
87 Dir::NegX | Dir::NegY => -1,
88 }
89 }
90
91 pub fn to_vec2(self) -> Vec2<i32> {
92 match self {
93 Dir::X => Vec2::new(1, 0),
94 Dir::NegX => Vec2::new(-1, 0),
95 Dir::Y => Vec2::new(0, 1),
96 Dir::NegY => Vec2::new(0, -1),
97 }
98 }
99
100 pub fn to_vec3(self) -> Vec3<i32> {
101 match self {
102 Dir::X => Vec3::new(1, 0, 0),
103 Dir::NegX => Vec3::new(-1, 0, 0),
104 Dir::Y => Vec3::new(0, 1, 0),
105 Dir::NegY => Vec3::new(0, -1, 0),
106 }
107 }
108
109 pub fn vec2(self, x: i32, y: i32) -> Vec2<i32> {
112 match self {
113 Dir::X => Vec2::new(x, y),
114 Dir::NegX => Vec2::new(-x, -y),
115 Dir::Y => Vec2::new(y, x),
116 Dir::NegY => Vec2::new(-y, -x),
117 }
118 }
119
120 pub fn vec2_abs<T>(self, x: T, y: T) -> Vec2<T> {
123 match self {
124 Dir::X => Vec2::new(x, y),
125 Dir::NegX => Vec2::new(x, y),
126 Dir::Y => Vec2::new(y, x),
127 Dir::NegY => Vec2::new(y, x),
128 }
129 }
130
131 pub fn to_mat3(self) -> Mat3<i32> {
155 match self {
156 Dir::X => Mat3::new(1, 0, 0, 0, 1, 0, 0, 0, 1),
157 Dir::NegX => Mat3::new(-1, 0, 0, 0, -1, 0, 0, 0, 1),
158 Dir::Y => Mat3::new(0, -1, 0, 1, 0, 0, 0, 0, 1),
159 Dir::NegY => Mat3::new(0, 1, 0, -1, 0, 0, 0, 0, 1),
160 }
161 }
162
163 pub fn from_z_mat3(self) -> Mat3<i32> {
166 match self {
167 Dir::X => Mat3::new(0, 0, -1, 0, 1, 0, 1, 0, 0),
168 Dir::NegX => Mat3::new(0, 0, 1, 0, 1, 0, -1, 0, 0),
169 Dir::Y => Mat3::new(1, 0, 0, 0, 0, -1, 0, 1, 0),
170 Dir::NegY => Mat3::new(1, 0, 0, 0, 0, 1, 0, -1, 0),
171 }
172 }
173
174 #[must_use]
177 pub fn relative_to(self, other: Dir) -> Dir {
178 match other {
179 Dir::X => self,
180 Dir::NegX => self.opposite(),
181 Dir::Y => self.rotated_cw(),
182 Dir::NegY => self.rotated_ccw(),
183 }
184 }
185
186 pub fn is_x(self) -> bool { matches!(self, Dir::X | Dir::NegX) }
188
189 pub fn is_y(self) -> bool { matches!(self, Dir::Y | Dir::NegY) }
191
192 pub fn is_positive(self) -> bool { matches!(self, Dir::X | Dir::Y) }
193
194 pub fn is_negative(self) -> bool { !self.is_positive() }
195
196 pub fn select(self, vec: impl Into<Vec2<i32>>) -> i32 {
198 let vec = vec.into();
199 match self {
200 Dir::X | Dir::NegX => vec.x,
201 Dir::Y | Dir::NegY => vec.y,
202 }
203 }
204
205 pub fn select_with(self, vec: impl Into<Vec2<i32>>, other: impl Into<Vec2<i32>>) -> Vec2<i32> {
208 let vec = vec.into();
209 let other = other.into();
210 match self {
211 Dir::X | Dir::NegX => Vec2::new(vec.x, other.y),
212 Dir::Y | Dir::NegY => Vec2::new(other.x, vec.y),
213 }
214 }
215
216 pub fn select_aabr<T>(self, aabr: Aabr<T>) -> T {
218 match self {
219 Dir::X => aabr.max.x,
220 Dir::NegX => aabr.min.x,
221 Dir::Y => aabr.max.y,
222 Dir::NegY => aabr.min.y,
223 }
224 }
225
226 pub fn select_aabr_with<T>(self, aabr: Aabr<T>, other: impl Into<Vec2<T>>) -> Vec2<T> {
229 let other = other.into();
230 match self {
231 Dir::X => Vec2::new(aabr.max.x, other.y),
232 Dir::NegX => Vec2::new(aabr.min.x, other.y),
233 Dir::Y => Vec2::new(other.x, aabr.max.y),
234 Dir::NegY => Vec2::new(other.x, aabr.min.y),
235 }
236 }
237
238 pub fn sprite_ori(self) -> u8 {
240 match self {
241 Dir::X => 2,
242 Dir::NegX => 6,
243 Dir::Y => 4,
244 Dir::NegY => 0,
245 }
246 }
247
248 pub fn split_aabr_offset<T>(self, aabr: Aabr<T>, offset: T) -> [Aabr<T>; 2]
249 where
250 T: Copy + PartialOrd + Add<T, Output = T> + Sub<T, Output = T>,
251 {
252 match self {
253 Dir::X => aabr.split_at_x(aabr.min.x + offset),
254 Dir::Y => aabr.split_at_y(aabr.min.y + offset),
255 Dir::NegX => {
256 let res = aabr.split_at_x(aabr.max.x - offset);
257 [res[1], res[0]]
258 },
259 Dir::NegY => {
260 let res = aabr.split_at_y(aabr.max.y - offset);
261 [res[1], res[0]]
262 },
263 }
264 }
265
266 pub fn trim_aabr(self, aabr: Aabr<i32>, amount: i32) -> Aabr<i32> {
267 (-self).extend_aabr(aabr, -amount)
268 }
269
270 pub fn extend_aabr(self, aabr: Aabr<i32>, amount: i32) -> Aabr<i32> {
271 let offset = self.to_vec2() * amount;
272 match self {
273 _ if self.is_positive() => Aabr {
274 min: aabr.min,
275 max: aabr.max + offset,
276 },
277 _ => Aabr {
278 min: aabr.min + offset,
279 max: aabr.max,
280 },
281 }
282 }
283}
284
285impl std::ops::Neg for Dir {
286 type Output = Dir;
287
288 fn neg(self) -> Self::Output { self.opposite() }
289}
290
291#[derive(Debug, enum_map::Enum, strum::EnumIter, enumset::EnumSetType)]
293pub enum Dir3 {
294 X,
295 Y,
296 Z,
297 NegX,
298 NegY,
299 NegZ,
300}
301
302impl Dir3 {
303 pub const ALL: [Dir; 4] = [Dir::X, Dir::Y, Dir::NegX, Dir::NegY];
304
305 pub fn choose(rng: &mut impl Rng) -> Dir3 {
306 match rng.gen_range(0..6) {
307 0 => Dir3::X,
308 1 => Dir3::Y,
309 2 => Dir3::Z,
310 3 => Dir3::NegX,
311 4 => Dir3::NegY,
312 _ => Dir3::NegZ,
313 }
314 }
315
316 pub fn from_dir(dir: Dir) -> Dir3 {
317 match dir {
318 Dir::X => Dir3::X,
319 Dir::Y => Dir3::Y,
320 Dir::NegX => Dir3::NegX,
321 Dir::NegY => Dir3::NegY,
322 }
323 }
324
325 pub fn to_dir(self) -> Option<Dir> {
326 match self {
327 Dir3::X => Some(Dir::X),
328 Dir3::Y => Some(Dir::Y),
329 Dir3::NegX => Some(Dir::NegX),
330 Dir3::NegY => Some(Dir::NegY),
331 _ => None,
332 }
333 }
334
335 pub fn from_vec3(vec: Vec3<i32>) -> Dir3 {
336 if vec.x.abs() > vec.y.abs() && vec.x.abs() > vec.z.abs() {
337 if vec.x > 0 { Dir3::X } else { Dir3::NegX }
338 } else if vec.y.abs() > vec.z.abs() {
339 if vec.y > 0 { Dir3::Y } else { Dir3::NegY }
340 } else if vec.z > 0 {
341 Dir3::Z
342 } else {
343 Dir3::NegZ
344 }
345 }
346
347 #[must_use]
348 pub fn opposite(self) -> Dir3 {
349 match self {
350 Dir3::X => Dir3::NegX,
351 Dir3::NegX => Dir3::X,
352 Dir3::Y => Dir3::NegY,
353 Dir3::NegY => Dir3::Y,
354 Dir3::Z => Dir3::NegZ,
355 Dir3::NegZ => Dir3::Z,
356 }
357 }
358
359 pub fn rotate_axis_ccw(self, axis: Dir3) -> Dir3 {
361 match axis {
362 Dir3::X | Dir3::NegX => match self {
363 Dir3::Y => Dir3::Z,
364 Dir3::NegY => Dir3::NegZ,
365 Dir3::Z => Dir3::NegY,
366 Dir3::NegZ => Dir3::Y,
367 x => x,
368 },
369 Dir3::Y | Dir3::NegY => match self {
370 Dir3::X => Dir3::Z,
371 Dir3::NegX => Dir3::NegZ,
372 Dir3::Z => Dir3::NegX,
373 Dir3::NegZ => Dir3::X,
374 y => y,
375 },
376 Dir3::Z | Dir3::NegZ => match self {
377 Dir3::X => Dir3::Y,
378 Dir3::NegX => Dir3::NegY,
379 Dir3::Y => Dir3::NegX,
380 Dir3::NegY => Dir3::X,
381 z => z,
382 },
383 }
384 }
385
386 pub fn rotate_axis_cw(self, axis: Dir3) -> Dir3 { self.rotate_axis_ccw(axis).opposite() }
388
389 pub fn cross(self, other: Dir3) -> Dir3 {
392 match (self, other) {
393 (Dir3::X | Dir3::NegX, Dir3::Y | Dir3::NegY)
394 | (Dir3::Y | Dir3::NegY, Dir3::X | Dir3::NegX) => Dir3::Z,
395 (Dir3::X | Dir3::NegX, Dir3::Z | Dir3::NegZ)
396 | (Dir3::Z | Dir3::NegZ, Dir3::X | Dir3::NegX) => Dir3::Y,
397 (Dir3::Z | Dir3::NegZ, Dir3::Y | Dir3::NegY)
398 | (Dir3::Y | Dir3::NegY, Dir3::Z | Dir3::NegZ) => Dir3::X,
399 (Dir3::X | Dir3::NegX, Dir3::X | Dir3::NegX) => Dir3::Y,
400 (Dir3::Y | Dir3::NegY, Dir3::Y | Dir3::NegY) => Dir3::X,
401 (Dir3::Z | Dir3::NegZ, Dir3::Z | Dir3::NegZ) => Dir3::Y,
402 }
403 }
404
405 #[must_use]
406 pub fn abs(self) -> Dir3 {
407 match self {
408 Dir3::X | Dir3::NegX => Dir3::X,
409 Dir3::Y | Dir3::NegY => Dir3::Y,
410 Dir3::Z | Dir3::NegZ => Dir3::Z,
411 }
412 }
413
414 #[must_use]
415 pub fn signum(self) -> i32 {
416 match self {
417 Dir3::X | Dir3::Y | Dir3::Z => 1,
418 Dir3::NegX | Dir3::NegY | Dir3::NegZ => -1,
419 }
420 }
421
422 pub fn to_vec3(self) -> Vec3<i32> {
423 match self {
424 Dir3::X => Vec3::new(1, 0, 0),
425 Dir3::NegX => Vec3::new(-1, 0, 0),
426 Dir3::Y => Vec3::new(0, 1, 0),
427 Dir3::NegY => Vec3::new(0, -1, 0),
428 Dir3::Z => Vec3::new(0, 0, 1),
429 Dir3::NegZ => Vec3::new(0, 0, -1),
430 }
431 }
432
433 pub fn is_x(self) -> bool { matches!(self, Dir3::X | Dir3::NegX) }
435
436 pub fn is_y(self) -> bool { matches!(self, Dir3::Y | Dir3::NegY) }
438
439 pub fn is_z(self) -> bool { matches!(self, Dir3::Z | Dir3::NegZ) }
441
442 pub fn is_positive(self) -> bool { matches!(self, Dir3::X | Dir3::Y | Dir3::Z) }
443
444 pub fn is_negative(self) -> bool { !self.is_positive() }
445
446 pub fn select(self, vec: impl Into<Vec3<i32>>) -> i32 {
448 let vec = vec.into();
449 match self {
450 Dir3::X | Dir3::NegX => vec.x,
451 Dir3::Y | Dir3::NegY => vec.y,
452 Dir3::Z | Dir3::NegZ => vec.z,
453 }
454 }
455
456 pub fn select_with(self, vec: impl Into<Vec3<i32>>, other: impl Into<Vec3<i32>>) -> Vec3<i32> {
459 let vec = vec.into();
460 let other = other.into();
461 match self {
462 Dir3::X | Dir3::NegX => Vec3::new(vec.x, other.y, other.z),
463 Dir3::Y | Dir3::NegY => Vec3::new(other.x, vec.y, other.z),
464 Dir3::Z | Dir3::NegZ => Vec3::new(other.x, other.y, vec.z),
465 }
466 }
467
468 pub fn select_aabb<T>(self, aabb: Aabb<T>) -> T {
470 match self {
471 Dir3::X => aabb.max.x,
472 Dir3::NegX => aabb.min.x,
473 Dir3::Y => aabb.max.y,
474 Dir3::NegY => aabb.min.y,
475 Dir3::Z => aabb.max.z,
476 Dir3::NegZ => aabb.min.z,
477 }
478 }
479
480 pub fn select_aabb_with<T>(self, aabb: Aabb<T>, other: impl Into<Vec3<T>>) -> Vec3<T> {
483 let other = other.into();
484 match self {
485 Dir3::X => Vec3::new(aabb.max.x, other.y, other.z),
486 Dir3::NegX => Vec3::new(aabb.min.x, other.y, other.z),
487 Dir3::Y => Vec3::new(other.x, aabb.max.y, other.z),
488 Dir3::NegY => Vec3::new(other.x, aabb.min.y, other.z),
489 Dir3::Z => Vec3::new(other.x, other.y, aabb.max.z),
490 Dir3::NegZ => Vec3::new(other.x, other.y, aabb.min.z),
491 }
492 }
493
494 pub fn split_aabb_offset<T>(self, aabb: Aabb<T>, offset: T) -> [Aabb<T>; 2]
495 where
496 T: Copy + PartialOrd + Add<T, Output = T> + Sub<T, Output = T>,
497 {
498 match self {
499 Dir3::X => aabb.split_at_x(aabb.min.x + offset),
500 Dir3::NegX => {
501 let res = aabb.split_at_x(aabb.max.x - offset);
502 [res[1], res[0]]
503 },
504 Dir3::Y => aabb.split_at_y(aabb.min.y + offset),
505 Dir3::NegY => {
506 let res = aabb.split_at_y(aabb.max.y - offset);
507 [res[1], res[0]]
508 },
509 Dir3::Z => aabb.split_at_z(aabb.min.z + offset),
510 Dir3::NegZ => {
511 let res = aabb.split_at_z(aabb.max.z - offset);
512 [res[1], res[0]]
513 },
514 }
515 }
516
517 pub fn trim_aabb(self, aabb: Aabb<i32>, amount: i32) -> Aabb<i32> {
518 (-self).extend_aabb(aabb, -amount)
519 }
520
521 pub fn extend_aabb(self, aabb: Aabb<i32>, amount: i32) -> Aabb<i32> {
522 let offset = self.to_vec3() * amount;
523 match self {
524 _ if self.is_positive() => Aabb {
525 min: aabb.min,
526 max: aabb.max + offset,
527 },
528 _ => Aabb {
529 min: aabb.min + offset,
530 max: aabb.max,
531 },
532 }
533 }
534}
535impl std::ops::Neg for Dir3 {
536 type Output = Dir3;
537
538 fn neg(self) -> Self::Output { self.opposite() }
539}