]> git.localhorst.tv Git - blank.git/blob - src/geometry/primitive.hpp
b9f2187580f5b64e692451553a352c72006e7e42
[blank.git] / src / geometry / primitive.hpp
1 #ifndef BLANK_GEOMETRY_PRIMITIVE_HPP_
2 #define BLANK_GEOMETRY_PRIMITIVE_HPP_
3
4 #include <algorithm>
5 #include <iosfwd>
6 #include <glm/glm.hpp>
7 #include <glm/gtx/norm.hpp>
8
9
10 namespace blank {
11
12 struct AABB {
13         glm::vec3 min;
14         glm::vec3 max;
15
16         void Adjust() noexcept {
17                 if (max.x < min.x) std::swap(max.x, min.x);
18                 if (max.y < min.y) std::swap(max.y, min.y);
19                 if (max.z < min.z) std::swap(max.z, min.z);
20         }
21
22         glm::vec3 Center() const noexcept {
23                 return min + (max - min) * 0.5f;
24         }
25
26         /// return distance between origin and farthest vertex
27         float OriginRadius() const noexcept {
28                 glm::vec3 high(glm::max(abs(min), abs(max)));
29                 return length(high);
30         }
31 };
32
33 std::ostream &operator <<(std::ostream &, const AABB &);
34
35 // TODO: this should really use setters/getters for dir and inv_dir so
36 //       manipulating code doesn't "forget" to call Update()
37 struct Ray {
38         glm::vec3 orig;
39         glm::vec3 dir;
40
41         glm::vec3 inv_dir;
42
43         void Update() noexcept {
44                 inv_dir = 1.0f / dir;
45         }
46
47         /// get shortest distance of this ray's line to given point
48         float Distance(const glm::vec3 &point) const noexcept {
49                 // d = |(x2-x1)×(x1-x0)|/|x2-x1|
50                 // where x0 is point, and x1 and x2 are points on the line
51                 // for derivation, see http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html
52                 // x1 = orig
53                 // x2-x1 = dir, which means |x2-x1| is 1.0
54                 return length(cross(dir, orig - point));
55         }
56         float DistanceSquared(const glm::vec3 &point) const noexcept {
57                 return length2(cross(dir, orig - point));
58         }
59 };
60
61 std::ostream &operator <<(std::ostream &, const Ray &);
62
63 /// axis aligned boolean ray/box intersection test
64 /// if true, dist constains distance from ray's origin to intersection point
65 bool Intersection(
66         const Ray &,
67         const AABB &,
68         float &dist) noexcept;
69
70 /// detailed oriented ray/box intersection test
71 bool Intersection(
72         const Ray &,
73         const AABB &,
74         const glm::mat4 &M,
75         float *dist = nullptr,
76         glm::vec3 *normal = nullptr) noexcept;
77
78 /// matrices may translate and rotate, but must not scale/shear/etc
79 /// (basically the first three columns must have unit length)
80 bool Intersection(
81         const AABB &a_box,
82         const glm::mat4 &a_m,
83         const AABB &b_box,
84         const glm::mat4 &b_m,
85         float &depth,
86         glm::vec3 &normal) noexcept;
87
88
89 struct Plane {
90         glm::vec3 normal;
91         float dist;
92
93         float &A() noexcept { return normal.x; }
94         float &B() noexcept { return normal.y; }
95         float &C() noexcept { return normal.z; }
96         float &D() noexcept { return dist; }
97         float A() const noexcept { return normal.x; }
98         float B() const noexcept { return normal.y; }
99         float C() const noexcept { return normal.z; }
100         float D() const noexcept { return dist; }
101
102         Plane(const glm::vec3 &n, float d)
103         : normal(n), dist(d) { }
104         Plane(const glm::vec4 &abcd)
105         : normal(abcd), dist(abcd.w) { }
106
107         void Normalize() noexcept {
108                 const float l = length(normal);
109                 normal /= l;
110                 dist /= l;
111         }
112 };
113
114 std::ostream &operator <<(std::ostream &, const Plane &);
115
116 struct Frustum {
117         Plane plane[6];
118         Plane &Left() noexcept { return plane[0]; }
119         Plane &Right() noexcept { return plane[1]; }
120         Plane &Bottom() noexcept { return plane[2]; }
121         Plane &Top() noexcept { return plane[3]; }
122         Plane &Near() noexcept { return plane[4]; }
123         Plane &Far() noexcept { return plane[5]; }
124         const Plane &Left() const noexcept { return plane[0]; }
125         const Plane &Right() const noexcept { return plane[1]; }
126         const Plane &Bottom() const noexcept { return plane[2]; }
127         const Plane &Top() const noexcept { return plane[3]; }
128         const Plane &Near() const noexcept { return plane[4]; }
129         const Plane &Far() const noexcept { return plane[5]; }
130
131         /// create frustum from transposed MVP
132         Frustum(const glm::mat4 &mat)
133         : plane{
134                 { mat[3] + mat[0] },
135                 { mat[3] - mat[0] },
136                 { mat[3] + mat[1] },
137                 { mat[3] - mat[1] },
138                 { mat[3] + mat[2] },
139                 { mat[3] - mat[2] },
140         } { }
141
142         void Normalize() noexcept {
143                 for (Plane &p : plane) {
144                         p.Normalize();
145                 }
146         }
147 };
148
149 std::ostream &operator <<(std::ostream &, const Plane &);
150 std::ostream &operator <<(std::ostream &, const Frustum &);
151
152 bool CullTest(const AABB &box, const glm::mat4 &) noexcept;
153 bool CullTest(const AABB &box, const Frustum &) noexcept;
154
155 }
156
157 #endif