aboutsummaryrefslogtreecommitdiff
path: root/src/core/bound3.rs
blob: 7f54e037d15a52052a54648a09c6a9cdbca687e0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//! Implements 3d axis aligned bounding box
use crate::{Number, Float};
use super::vector3::Vector3;
use crate::core::{min, max};
use crate::core::Ray;

#[derive(Clone)]
pub struct Bound3<T: Number> {
    pub min: Vector3<T>,
    pub max: Vector3<T>
}

pub type Bound3f = Bound3<Float>;

impl<T: Number> Bound3<T> {
    /// Creates a bound from two points
    pub fn new(p0: Vector3<T>, p1: Vector3<T>) -> Self {
        // Elliminate some code duplication here
        let min = Vector3::new_xyz(
            min(p0.x, p1.x),
            min(p0.y, p1.y),
            min(p0.z, p1.z)
            );
        let max = Vector3::new_xyz(
            max(p0.x, p1.x),
            max(p0.y, p1.y),
            max(p0.z, p1.z)
            );

        Self {min, max}
    }
}

impl Bound3f {
    /// Calculate whether there is a intersect between a bounding box and a ray
    ///
    /// # Examples:
    ///
    /// ```
    /// use rendering::core::{Bound3f, Vector3f, Ray};
    /// let b = Bound3f::new(Vector3f::new(7.0), Vector3f::new(10.0));
    /// let r1 = Ray::new_to(Vector3f::new(0.0), Vector3f::new(5.0));
    /// let r3 = Ray::new(Vector3f::new_xyz(-1.0, 0.0, 0.0), Vector3f::new_xyz(1.0, 0.0, 0.0));
    ///
    /// assert!(b.intersect(&r1));
    /// assert!(!b.intersect(&r3));
    /// ```
    pub fn intersect(&self, ray: &Ray) -> bool {
        // Method stolen from Ray tracing the next week.
        // They mention its from pixar
        for i in 0..3 {
            let inv = 1.0 / ray.direction[i];
            let mut t0 = (self.min[i] - ray.origin[i]) * inv;
            let mut t1 = (self.max[i] - ray.origin[i]) * inv;

            if inv < 0.0 {
                let tmp = t0;
                t0 = t1;
                t1 = tmp;
            }

            if t1 <= t0 {
                return false;
            }
        }

        return true;
    }
}