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 cardinal 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    /// The diagonal to the left of `self`, this is equal to this dir plus this
101    /// dir rotated counter clockwise.
102    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    /// Create a vec2 where x is in the direction of `self`, and y is anti
114    /// clockwise of `self`.
115    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    /// Create a vec2 where x is in the direction of `self`, and y is orthogonal
125    /// version of self.
126    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    /// Returns a 3x3 matrix that rotates Vec3(1, 0, 0) to the direction you get
136    /// in to_vec3. Inteded to be used with Primitive::Rotate.
137    ///
138    /// Example:
139    /// ```
140    /// use vek::Vec3;
141    /// use veloren_world::site2::util::Dir;
142    /// let dir = Dir::X;
143    ///
144    /// assert_eq!(dir.to_mat3() * Vec3::new(1, 0, 0), dir.to_vec3());
145    ///
146    /// let dir = Dir::NegX;
147    ///
148    /// assert_eq!(dir.to_mat3() * Vec3::new(1, 0, 0), dir.to_vec3());
149    ///
150    /// let dir = Dir::Y;
151    ///
152    /// assert_eq!(dir.to_mat3() * Vec3::new(1, 0, 0), dir.to_vec3());
153    ///
154    /// let dir = Dir::NegY;
155    ///
156    /// assert_eq!(dir.to_mat3() * Vec3::new(1, 0, 0), dir.to_vec3());
157    /// ```
158    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    /// Creates a matrix that tranforms an upwards facing vector to this
168    /// direction.
169    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    /// Translates this direction to worldspace as if it was relative to the
179    /// other direction
180    #[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    /// Is this direction parallel to x
191    pub fn is_x(self) -> bool { matches!(self, Dir::X | Dir::NegX) }
192
193    /// Is this direction parallel to y
194    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    /// Returns the component that the direction is parallell to
201    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    /// Select one component the direction is parallel to from vec and select
210    /// the other component from other
211    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    /// Returns the side of an aabr that the direction is pointing to
221    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    /// Select one component from the side the direction is pointing to from
231    /// aabr and select the other component from other
232    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    /// The equivelant sprite direction of the direction
243    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    /// Returns (Dir, rest)
253    ///
254    /// Returns None if `ori` isn't a valid sprite Ori.
255    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    /// Legacy version of `sprite_ori`, so prefer using that over this.
269    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/// A 3d direction.
322#[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    /// Rotate counter clockwise around an axis by 90 degrees.
390    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    /// Rotate clockwise around an axis by 90 degrees.
417    pub fn rotate_axis_cw(self, axis: Dir3) -> Dir3 { self.rotate_axis_ccw(axis).opposite() }
418
419    /// Get a direction that is orthogonal to both directions, always a positive
420    /// direction.
421    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    /// Is this direction parallel to x
464    pub fn is_x(self) -> bool { matches!(self, Dir3::X | Dir3::NegX) }
465
466    /// Is this direction parallel to y
467    pub fn is_y(self) -> bool { matches!(self, Dir3::Y | Dir3::NegY) }
468
469    /// Is this direction parallel to z
470    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    /// Returns the component that the direction is parallell to
477    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    /// Select one component the direction is parallel to from vec and select
487    /// the other components from other
488    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    /// Returns the side of an aabb that the direction is pointing to
499    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    /// Select one component from the side the direction is pointing to from
511    /// aabr and select the other components from other
512    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}