veloren_world/site2/util/
mod.rs

1pub mod gradient;
2pub mod sprites;
3
4use std::ops::{Add, Sub};
5
6use rand::Rng;
7use vek::*;
8
9/// A 2d direction.
10#[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    /// Rotate the direction anti clock wise
53    #[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    /// Rotate the direction clock wise
64    #[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    /// Create a vec2 where x is in the direction of `self`, and y is anti
110    /// clockwise of `self`.
111    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    /// Create a vec2 where x is in the direction of `self`, and y is orthogonal
121    /// version of self.
122    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    /// Returns a 3x3 matrix that rotates Vec3(1, 0, 0) to the direction you get
132    /// in to_vec3. Inteded to be used with Primitive::Rotate.
133    ///
134    /// Example:
135    /// ```
136    /// use vek::Vec3;
137    /// use veloren_world::site2::util::Dir;
138    /// let dir = Dir::X;
139    ///
140    /// assert_eq!(dir.to_mat3() * Vec3::new(1, 0, 0), dir.to_vec3());
141    ///
142    /// let dir = Dir::NegX;
143    ///
144    /// assert_eq!(dir.to_mat3() * Vec3::new(1, 0, 0), dir.to_vec3());
145    ///
146    /// let dir = Dir::Y;
147    ///
148    /// assert_eq!(dir.to_mat3() * Vec3::new(1, 0, 0), dir.to_vec3());
149    ///
150    /// let dir = Dir::NegY;
151    ///
152    /// assert_eq!(dir.to_mat3() * Vec3::new(1, 0, 0), dir.to_vec3());
153    /// ```
154    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    /// Creates a matrix that tranforms an upwards facing vector to this
164    /// direction.
165    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    /// Translates this direction to worldspace as if it was relative to the
175    /// other direction
176    #[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    /// Is this direction parallel to x
187    pub fn is_x(self) -> bool { matches!(self, Dir::X | Dir::NegX) }
188
189    /// Is this direction parallel to y
190    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    /// Returns the component that the direction is parallell to
197    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    /// Select one component the direction is parallel to from vec and select
206    /// the other component from other
207    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    /// Returns the side of an aabr that the direction is pointing to
217    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    /// Select one component from the side the direction is pointing to from
227    /// aabr and select the other component from other
228    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    /// The equivelant sprite direction of the direction
239    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/// A 3d direction.
292#[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    /// Rotate counter clockwise around an axis by 90 degrees.
360    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    /// Rotate clockwise around an axis by 90 degrees.
387    pub fn rotate_axis_cw(self, axis: Dir3) -> Dir3 { self.rotate_axis_ccw(axis).opposite() }
388
389    /// Get a direction that is orthogonal to both directions, always a positive
390    /// direction.
391    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    /// Is this direction parallel to x
434    pub fn is_x(self) -> bool { matches!(self, Dir3::X | Dir3::NegX) }
435
436    /// Is this direction parallel to y
437    pub fn is_y(self) -> bool { matches!(self, Dir3::Y | Dir3::NegY) }
438
439    /// Is this direction parallel to z
440    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    /// Returns the component that the direction is parallell to
447    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    /// Select one component the direction is parallel to from vec and select
457    /// the other components from other
458    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    /// Returns the side of an aabb that the direction is pointing to
469    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    /// Select one component from the side the direction is pointing to from
481    /// aabr and select the other components from other
482    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}