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