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