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