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 diagonal(self) -> Vec2<i32> { self.to_vec2() + self.rotated_ccw().to_vec2() }
103
104 pub fn to_vec3(self) -> Vec3<i32> {
105 match self {
106 Dir::X => Vec3::new(1, 0, 0),
107 Dir::NegX => Vec3::new(-1, 0, 0),
108 Dir::Y => Vec3::new(0, 1, 0),
109 Dir::NegY => Vec3::new(0, -1, 0),
110 }
111 }
112
113 pub fn vec2(self, x: i32, y: i32) -> Vec2<i32> {
116 match self {
117 Dir::X => Vec2::new(x, y),
118 Dir::NegX => Vec2::new(-x, -y),
119 Dir::Y => Vec2::new(y, x),
120 Dir::NegY => Vec2::new(-y, -x),
121 }
122 }
123
124 pub fn vec2_abs<T>(self, x: T, y: T) -> Vec2<T> {
127 match self {
128 Dir::X => Vec2::new(x, y),
129 Dir::NegX => Vec2::new(x, y),
130 Dir::Y => Vec2::new(y, x),
131 Dir::NegY => Vec2::new(y, x),
132 }
133 }
134
135 pub fn to_mat3(self) -> Mat3<i32> {
159 match self {
160 Dir::X => Mat3::new(1, 0, 0, 0, 1, 0, 0, 0, 1),
161 Dir::NegX => Mat3::new(-1, 0, 0, 0, -1, 0, 0, 0, 1),
162 Dir::Y => Mat3::new(0, -1, 0, 1, 0, 0, 0, 0, 1),
163 Dir::NegY => Mat3::new(0, 1, 0, -1, 0, 0, 0, 0, 1),
164 }
165 }
166
167 pub fn from_z_mat3(self) -> Mat3<i32> {
170 match self {
171 Dir::X => Mat3::new(0, 0, -1, 0, 1, 0, 1, 0, 0),
172 Dir::NegX => Mat3::new(0, 0, 1, 0, 1, 0, -1, 0, 0),
173 Dir::Y => Mat3::new(1, 0, 0, 0, 0, -1, 0, 1, 0),
174 Dir::NegY => Mat3::new(1, 0, 0, 0, 0, 1, 0, -1, 0),
175 }
176 }
177
178 #[must_use]
181 pub fn relative_to(self, other: Dir) -> Dir {
182 match other {
183 Dir::X => self,
184 Dir::NegX => self.opposite(),
185 Dir::Y => self.rotated_cw(),
186 Dir::NegY => self.rotated_ccw(),
187 }
188 }
189
190 pub fn is_x(self) -> bool { matches!(self, Dir::X | Dir::NegX) }
192
193 pub fn is_y(self) -> bool { matches!(self, Dir::Y | Dir::NegY) }
195
196 pub fn is_positive(self) -> bool { matches!(self, Dir::X | Dir::Y) }
197
198 pub fn is_negative(self) -> bool { !self.is_positive() }
199
200 pub fn select(self, vec: impl Into<Vec2<i32>>) -> i32 {
202 let vec = vec.into();
203 match self {
204 Dir::X | Dir::NegX => vec.x,
205 Dir::Y | Dir::NegY => vec.y,
206 }
207 }
208
209 pub fn select_with(self, vec: impl Into<Vec2<i32>>, other: impl Into<Vec2<i32>>) -> Vec2<i32> {
212 let vec = vec.into();
213 let other = other.into();
214 match self {
215 Dir::X | Dir::NegX => Vec2::new(vec.x, other.y),
216 Dir::Y | Dir::NegY => Vec2::new(other.x, vec.y),
217 }
218 }
219
220 pub fn select_aabr<T>(self, aabr: Aabr<T>) -> T {
222 match self {
223 Dir::X => aabr.max.x,
224 Dir::NegX => aabr.min.x,
225 Dir::Y => aabr.max.y,
226 Dir::NegY => aabr.min.y,
227 }
228 }
229
230 pub fn select_aabr_with<T>(self, aabr: Aabr<T>, other: impl Into<Vec2<T>>) -> Vec2<T> {
233 let other = other.into();
234 match self {
235 Dir::X => Vec2::new(aabr.max.x, other.y),
236 Dir::NegX => Vec2::new(aabr.min.x, other.y),
237 Dir::Y => Vec2::new(other.x, aabr.max.y),
238 Dir::NegY => Vec2::new(other.x, aabr.min.y),
239 }
240 }
241
242 pub fn sprite_ori(self) -> u8 {
244 match self {
245 Dir::X => 0,
246 Dir::Y => 2,
247 Dir::NegX => 4,
248 Dir::NegY => 6,
249 }
250 }
251
252 pub fn from_sprite_ori(ori: u8) -> Option<(Dir, u8)> {
256 let dir = match ori / 2 {
257 0 => Dir::X,
258 1 => Dir::Y,
259 2 => Dir::NegX,
260 3 => Dir::NegY,
261 _ => return None,
262 };
263 let rest = ori % 2;
264
265 Some((dir, rest))
266 }
267
268 pub fn sprite_ori_legacy(self) -> u8 {
270 match self {
271 Dir::X => 2,
272 Dir::NegX => 6,
273 Dir::Y => 4,
274 Dir::NegY => 0,
275 }
276 }
277
278 pub fn split_aabr_offset<T>(self, aabr: Aabr<T>, offset: T) -> [Aabr<T>; 2]
279 where
280 T: Copy + PartialOrd + Add<T, Output = T> + Sub<T, Output = T>,
281 {
282 match self {
283 Dir::X => aabr.split_at_x(aabr.min.x + offset),
284 Dir::Y => aabr.split_at_y(aabr.min.y + offset),
285 Dir::NegX => {
286 let res = aabr.split_at_x(aabr.max.x - offset);
287 [res[1], res[0]]
288 },
289 Dir::NegY => {
290 let res = aabr.split_at_y(aabr.max.y - offset);
291 [res[1], res[0]]
292 },
293 }
294 }
295
296 pub fn trim_aabr(self, aabr: Aabr<i32>, amount: i32) -> Aabr<i32> {
297 (-self).extend_aabr(aabr, -amount)
298 }
299
300 pub fn extend_aabr(self, aabr: Aabr<i32>, amount: i32) -> Aabr<i32> {
301 let offset = self.to_vec2() * amount;
302 match self {
303 _ if self.is_positive() => Aabr {
304 min: aabr.min,
305 max: aabr.max + offset,
306 },
307 _ => Aabr {
308 min: aabr.min + offset,
309 max: aabr.max,
310 },
311 }
312 }
313}
314
315impl std::ops::Neg for Dir {
316 type Output = Dir;
317
318 fn neg(self) -> Self::Output { self.opposite() }
319}
320
321#[derive(Debug, enum_map::Enum, strum::EnumIter, enumset::EnumSetType)]
323pub enum Dir3 {
324 X,
325 Y,
326 Z,
327 NegX,
328 NegY,
329 NegZ,
330}
331
332impl Dir3 {
333 pub const ALL: [Dir; 4] = [Dir::X, Dir::Y, Dir::NegX, Dir::NegY];
334
335 pub fn choose(rng: &mut impl Rng) -> Dir3 {
336 match rng.gen_range(0..6) {
337 0 => Dir3::X,
338 1 => Dir3::Y,
339 2 => Dir3::Z,
340 3 => Dir3::NegX,
341 4 => Dir3::NegY,
342 _ => Dir3::NegZ,
343 }
344 }
345
346 pub fn from_dir(dir: Dir) -> Dir3 {
347 match dir {
348 Dir::X => Dir3::X,
349 Dir::Y => Dir3::Y,
350 Dir::NegX => Dir3::NegX,
351 Dir::NegY => Dir3::NegY,
352 }
353 }
354
355 pub fn to_dir(self) -> Option<Dir> {
356 match self {
357 Dir3::X => Some(Dir::X),
358 Dir3::Y => Some(Dir::Y),
359 Dir3::NegX => Some(Dir::NegX),
360 Dir3::NegY => Some(Dir::NegY),
361 _ => None,
362 }
363 }
364
365 pub fn from_vec3(vec: Vec3<i32>) -> Dir3 {
366 if vec.x.abs() > vec.y.abs() && vec.x.abs() > vec.z.abs() {
367 if vec.x > 0 { Dir3::X } else { Dir3::NegX }
368 } else if vec.y.abs() > vec.z.abs() {
369 if vec.y > 0 { Dir3::Y } else { Dir3::NegY }
370 } else if vec.z > 0 {
371 Dir3::Z
372 } else {
373 Dir3::NegZ
374 }
375 }
376
377 #[must_use]
378 pub fn opposite(self) -> Dir3 {
379 match self {
380 Dir3::X => Dir3::NegX,
381 Dir3::NegX => Dir3::X,
382 Dir3::Y => Dir3::NegY,
383 Dir3::NegY => Dir3::Y,
384 Dir3::Z => Dir3::NegZ,
385 Dir3::NegZ => Dir3::Z,
386 }
387 }
388
389 pub fn rotate_axis_ccw(self, axis: Dir3) -> Dir3 {
391 match axis {
392 Dir3::X | Dir3::NegX => match self {
393 Dir3::Y => Dir3::Z,
394 Dir3::NegY => Dir3::NegZ,
395 Dir3::Z => Dir3::NegY,
396 Dir3::NegZ => Dir3::Y,
397 x => x,
398 },
399 Dir3::Y | Dir3::NegY => match self {
400 Dir3::X => Dir3::Z,
401 Dir3::NegX => Dir3::NegZ,
402 Dir3::Z => Dir3::NegX,
403 Dir3::NegZ => Dir3::X,
404 y => y,
405 },
406 Dir3::Z | Dir3::NegZ => match self {
407 Dir3::X => Dir3::Y,
408 Dir3::NegX => Dir3::NegY,
409 Dir3::Y => Dir3::NegX,
410 Dir3::NegY => Dir3::X,
411 z => z,
412 },
413 }
414 }
415
416 pub fn rotate_axis_cw(self, axis: Dir3) -> Dir3 { self.rotate_axis_ccw(axis).opposite() }
418
419 pub fn cross(self, other: Dir3) -> Dir3 {
422 match (self, other) {
423 (Dir3::X | Dir3::NegX, Dir3::Y | Dir3::NegY)
424 | (Dir3::Y | Dir3::NegY, Dir3::X | Dir3::NegX) => Dir3::Z,
425 (Dir3::X | Dir3::NegX, Dir3::Z | Dir3::NegZ)
426 | (Dir3::Z | Dir3::NegZ, Dir3::X | Dir3::NegX) => Dir3::Y,
427 (Dir3::Z | Dir3::NegZ, Dir3::Y | Dir3::NegY)
428 | (Dir3::Y | Dir3::NegY, Dir3::Z | Dir3::NegZ) => Dir3::X,
429 (Dir3::X | Dir3::NegX, Dir3::X | Dir3::NegX) => Dir3::Y,
430 (Dir3::Y | Dir3::NegY, Dir3::Y | Dir3::NegY) => Dir3::X,
431 (Dir3::Z | Dir3::NegZ, Dir3::Z | Dir3::NegZ) => Dir3::Y,
432 }
433 }
434
435 #[must_use]
436 pub fn abs(self) -> Dir3 {
437 match self {
438 Dir3::X | Dir3::NegX => Dir3::X,
439 Dir3::Y | Dir3::NegY => Dir3::Y,
440 Dir3::Z | Dir3::NegZ => Dir3::Z,
441 }
442 }
443
444 #[must_use]
445 pub fn signum(self) -> i32 {
446 match self {
447 Dir3::X | Dir3::Y | Dir3::Z => 1,
448 Dir3::NegX | Dir3::NegY | Dir3::NegZ => -1,
449 }
450 }
451
452 pub fn to_vec3(self) -> Vec3<i32> {
453 match self {
454 Dir3::X => Vec3::new(1, 0, 0),
455 Dir3::NegX => Vec3::new(-1, 0, 0),
456 Dir3::Y => Vec3::new(0, 1, 0),
457 Dir3::NegY => Vec3::new(0, -1, 0),
458 Dir3::Z => Vec3::new(0, 0, 1),
459 Dir3::NegZ => Vec3::new(0, 0, -1),
460 }
461 }
462
463 pub fn is_x(self) -> bool { matches!(self, Dir3::X | Dir3::NegX) }
465
466 pub fn is_y(self) -> bool { matches!(self, Dir3::Y | Dir3::NegY) }
468
469 pub fn is_z(self) -> bool { matches!(self, Dir3::Z | Dir3::NegZ) }
471
472 pub fn is_positive(self) -> bool { matches!(self, Dir3::X | Dir3::Y | Dir3::Z) }
473
474 pub fn is_negative(self) -> bool { !self.is_positive() }
475
476 pub fn select(self, vec: impl Into<Vec3<i32>>) -> i32 {
478 let vec = vec.into();
479 match self {
480 Dir3::X | Dir3::NegX => vec.x,
481 Dir3::Y | Dir3::NegY => vec.y,
482 Dir3::Z | Dir3::NegZ => vec.z,
483 }
484 }
485
486 pub fn select_with(self, vec: impl Into<Vec3<i32>>, other: impl Into<Vec3<i32>>) -> Vec3<i32> {
489 let vec = vec.into();
490 let other = other.into();
491 match self {
492 Dir3::X | Dir3::NegX => Vec3::new(vec.x, other.y, other.z),
493 Dir3::Y | Dir3::NegY => Vec3::new(other.x, vec.y, other.z),
494 Dir3::Z | Dir3::NegZ => Vec3::new(other.x, other.y, vec.z),
495 }
496 }
497
498 pub fn select_aabb<T>(self, aabb: Aabb<T>) -> T {
500 match self {
501 Dir3::X => aabb.max.x,
502 Dir3::NegX => aabb.min.x,
503 Dir3::Y => aabb.max.y,
504 Dir3::NegY => aabb.min.y,
505 Dir3::Z => aabb.max.z,
506 Dir3::NegZ => aabb.min.z,
507 }
508 }
509
510 pub fn select_aabb_with<T>(self, aabb: Aabb<T>, other: impl Into<Vec3<T>>) -> Vec3<T> {
513 let other = other.into();
514 match self {
515 Dir3::X => Vec3::new(aabb.max.x, other.y, other.z),
516 Dir3::NegX => Vec3::new(aabb.min.x, other.y, other.z),
517 Dir3::Y => Vec3::new(other.x, aabb.max.y, other.z),
518 Dir3::NegY => Vec3::new(other.x, aabb.min.y, other.z),
519 Dir3::Z => Vec3::new(other.x, other.y, aabb.max.z),
520 Dir3::NegZ => Vec3::new(other.x, other.y, aabb.min.z),
521 }
522 }
523
524 pub fn split_aabb_offset<T>(self, aabb: Aabb<T>, offset: T) -> [Aabb<T>; 2]
525 where
526 T: Copy + PartialOrd + Add<T, Output = T> + Sub<T, Output = T>,
527 {
528 match self {
529 Dir3::X => aabb.split_at_x(aabb.min.x + offset),
530 Dir3::NegX => {
531 let res = aabb.split_at_x(aabb.max.x - offset);
532 [res[1], res[0]]
533 },
534 Dir3::Y => aabb.split_at_y(aabb.min.y + offset),
535 Dir3::NegY => {
536 let res = aabb.split_at_y(aabb.max.y - offset);
537 [res[1], res[0]]
538 },
539 Dir3::Z => aabb.split_at_z(aabb.min.z + offset),
540 Dir3::NegZ => {
541 let res = aabb.split_at_z(aabb.max.z - offset);
542 [res[1], res[0]]
543 },
544 }
545 }
546
547 pub fn trim_aabb(self, aabb: Aabb<i32>, amount: i32) -> Aabb<i32> {
548 (-self).extend_aabb(aabb, -amount)
549 }
550
551 pub fn extend_aabb(self, aabb: Aabb<i32>, amount: i32) -> Aabb<i32> {
552 let offset = self.to_vec3() * amount;
553 match self {
554 _ if self.is_positive() => Aabb {
555 min: aabb.min,
556 max: aabb.max + offset,
557 },
558 _ => Aabb {
559 min: aabb.min + offset,
560 max: aabb.max,
561 },
562 }
563 }
564}
565impl std::ops::Neg for Dir3 {
566 type Output = Dir3;
567
568 fn neg(self) -> Self::Output { self.opposite() }
569}