Simulant  21.12-194
A portable game engine for Windows, OSX, Linux, Dreamcast, and PSP
aabb.h
1 #pragma once
2 
3 #include <cmath>
4 #include <array>
5 #include "vec3.h"
6 
7 namespace smlt {
8 
9 class VertexData;
10 
11 enum AABBCorner {
12  AABB_CORNER_NEG_X_NEG_Y_NEG_Z = 0,
13  AABB_CORNER_POS_X_NEG_Y_NEG_Z = 1,
14  AABB_CORNER_POS_X_NEG_Y_POS_Z = 2,
15  AABB_CORNER_NEG_X_NEG_Y_POS_Z = 3,
16  AABB_CORNER_NEG_X_POS_Y_NEG_Z = 4,
17  AABB_CORNER_POS_X_POS_Y_NEG_Z = 5,
18  AABB_CORNER_POS_X_POS_Y_POS_Z = 6,
19  AABB_CORNER_NEG_X_POS_Y_POS_Z = 7
20 };
21 
22 class AABB {
23  /* This was originally a basic struct but for performance reasons it's now a class
24  * so that we can store things like pre-calculate corners and know they are kept up-to-date
25  * with setters */
26 
27  Vec3 min_;
28  Vec3 max_;
29 
30  mutable std::array<Vec3, 8> corners_;
31  mutable bool corners_dirty_ = true;
32 
33  void rebuild_corners() const {
34  corners_[AABB_CORNER_NEG_X_NEG_Y_NEG_Z] = {min_.x, min_.y, min_.z};
35  corners_[AABB_CORNER_POS_X_NEG_Y_NEG_Z] = {max_.x, min_.y, min_.z};
36  corners_[AABB_CORNER_POS_X_NEG_Y_POS_Z] = {max_.x, min_.y, max_.z};
37  corners_[AABB_CORNER_NEG_X_NEG_Y_POS_Z] = {min_.x, min_.y, max_.z};
38 
39  corners_[AABB_CORNER_NEG_X_POS_Y_NEG_Z] = {min_.x, max_.y, min_.z};
40  corners_[AABB_CORNER_POS_X_POS_Y_NEG_Z] = {max_.x, max_.y, min_.z};
41  corners_[AABB_CORNER_POS_X_POS_Y_POS_Z] = {max_.x, max_.y, max_.z};
42  corners_[AABB_CORNER_NEG_X_POS_Y_POS_Z] = {min_.x, max_.y, max_.z};
43 
44  corners_dirty_ = false;
45  }
46 
47 public:
48  void set_min(const Vec3& min) {
49  if(min_ != min) {
50  min_ = min;
51  corners_dirty_ = true;
52  }
53  }
54 
55  void set_min_x(float x) {
56  if(x != min_.x) {
57  min_.x = x;
58  corners_dirty_ = true;
59  }
60  }
61 
62  void set_min_y(float y) {
63  if(y != min_.y) {
64  min_.y = y;
65  corners_dirty_ = true;
66  }
67  }
68 
69  void set_min_z(float z) {
70  if(z != min_.z) {
71  min_.z = z;
72  corners_dirty_ = true;
73  }
74  }
75 
76 
77  void set_max_x(float x) {
78  if(x != max_.x) {
79  max_.x = x;
80  corners_dirty_ = true;
81  }
82  }
83 
84  void set_max_y(float y) {
85  if(y != max_.y) {
86  max_.y = y;
87  corners_dirty_ = true;
88  }
89  }
90 
91  void set_max_z(float z) {
92  if(z != max_.z) {
93  max_.z = z;
94  corners_dirty_ = true;
95  }
96  }
97 
98  void set_max(const Vec3& max) {
99  if(max_ != max) {
100  max_ = max;
101  corners_dirty_ = true;
102  }
103  }
104 
105  const Vec3& min() const { return min_; }
106  const Vec3& max() const { return max_; }
107 
108  AABB() {
109  rebuild_corners();
110  }
111 
112  AABB(const Vec3& min, const Vec3& max);
113  AABB(const Vec3& centre, float width);
114  AABB(const Vec3& centre, float xsize, float ysize, float zsize);
115  AABB(const Vec3* vertices, const std::size_t count);
116  AABB(const VertexData& vertex_data);
117 
118  float width() const {
119  return std::abs(max_.x - min_.x);
120  }
121 
122  float height() const {
123  return std::abs(max_.y - min_.y);
124  }
125 
126  float depth() const {
127  return std::abs(max_.z - min_.z);
128  }
129 
130  const Vec3 dimensions() const {
131  return Vec3(width(), height(), depth());
132  }
133 
134  float max_dimension() const {
135  return std::max(width(), std::max(height(), depth()));
136  }
137 
138  float min_dimension() const {
139  return std::min(width(), std::min(height(), depth()));
140  }
141 
142  bool intersects_aabb(const AABB& other) const;
143  bool intersects_sphere(const smlt::Vec3& center, float radius) const;
144 
145  Vec3 centre() const {
146  return Vec3(min_) + ((Vec3(max_) - Vec3(min_)) * 0.5f);
147  }
148 
149  bool has_zero_area() const {
150  /*
151  * Returns True if the AABB has two or more zero dimensions
152  */
153  bool empty_x = width() == 0.0f;
154  bool empty_y = height() == 0.0f;
155  bool empty_z = depth() == 0.0f;
156 
157  return (empty_x && empty_y) || (empty_x && empty_z) || (empty_y && empty_z);
158  }
159 
160  bool contains_point(const Vec3& p) const {
161  if(p.x >= min_.x && p.x <= max_.x &&
162  p.y >= min_.y && p.y <= max_.y &&
163  p.z >= min_.z && p.z <= max_.z) {
164  return true;
165  }
166 
167  return false;
168  }
169 
170  bool contains_points(const Vec3* vertices, std::size_t count) const {
171  for(std::size_t i = 0; i < count; ++i) {
172  if(!contains_point(vertices[i])) {
173  return false;
174  }
175  }
176 
177  return true;
178  }
179 
180  bool contains_points(const std::vector<Vec3>& points) const {
181  return contains_points(&points[0], points.size());
182  }
183 
184  /* NOTE: The corners are recalculated when called, so don't hold onto a reference for long */
185  const std::array<Vec3, 8>& corners() const {
186  if(corners_dirty_) {
187  rebuild_corners();
188  }
189 
190  return corners_;
191  }
192 
193  void encapsulate(const AABB& other);
194 
195  bool operator==(const AABB& rhs) const {
196  return min().equals(rhs.min()) && max().equals(rhs.max());
197  }
198 
199  bool operator!=(const AABB& rhs) const {
200  return !(*this == rhs);
201  }
202 
203  friend std::ostream& operator<<(std::ostream& stream, const AABB& aabb);
204 };
205 
206 std::ostream& operator<<(std::ostream& stream, const AABB& aabb);
207 
208 }
smlt::VertexData
Definition: vertex_data.h:57
smlt::Vec3
Definition: vec3.h:23
smlt
Definition: animation.cpp:25
smlt::AABB
Definition: aabb.h:22