BoundingBox.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. //
  2. // Copyright (c) 2008-2020 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #pragma once
  23. #include "../Math/Rect.h"
  24. #include "../Math/Vector3.h"
  25. #ifdef URHO3D_SSE
  26. #include <xmmintrin.h>
  27. #endif
  28. namespace Urho3D
  29. {
  30. class Polyhedron;
  31. class Frustum;
  32. class Matrix3;
  33. class Matrix4;
  34. class Matrix3x4;
  35. class Sphere;
  36. /// Three-dimensional axis-aligned bounding box.
  37. /// @allfloats
  38. class URHO3D_API BoundingBox
  39. {
  40. public:
  41. /// Construct with zero size.
  42. BoundingBox() noexcept :
  43. min_(M_INFINITY, M_INFINITY, M_INFINITY),
  44. max_(-M_INFINITY, -M_INFINITY, -M_INFINITY)
  45. {
  46. }
  47. /// Copy-construct from another bounding box.
  48. BoundingBox(const BoundingBox& box) noexcept :
  49. min_(box.min_),
  50. max_(box.max_)
  51. {
  52. }
  53. /// Construct from a rect, with the Z dimension left zero.
  54. explicit BoundingBox(const Rect& rect) noexcept :
  55. min_(Vector3(rect.min_, 0.0f)),
  56. max_(Vector3(rect.max_, 0.0f))
  57. {
  58. }
  59. /// Construct from minimum and maximum vectors.
  60. BoundingBox(const Vector3& min, const Vector3& max) noexcept :
  61. min_(min),
  62. max_(max)
  63. {
  64. }
  65. /// Construct from minimum and maximum floats (all dimensions same).
  66. BoundingBox(float min, float max) noexcept :
  67. min_(Vector3(min, min, min)),
  68. max_(Vector3(max, max, max))
  69. {
  70. }
  71. #ifdef URHO3D_SSE
  72. /// @nobind
  73. BoundingBox(__m128 min, __m128 max) noexcept
  74. {
  75. _mm_storeu_ps(&min_.x_, min);
  76. _mm_storeu_ps(&max_.x_, max);
  77. }
  78. #endif
  79. /// Construct from an array of vertices.
  80. BoundingBox(const Vector3* vertices, unsigned count) :
  81. min_(M_INFINITY, M_INFINITY, M_INFINITY),
  82. max_(-M_INFINITY, -M_INFINITY, -M_INFINITY)
  83. {
  84. Define(vertices, count);
  85. }
  86. /// Construct from a frustum.
  87. explicit BoundingBox(const Frustum& frustum) :
  88. min_(M_INFINITY, M_INFINITY, M_INFINITY),
  89. max_(-M_INFINITY, -M_INFINITY, -M_INFINITY)
  90. {
  91. Define(frustum);
  92. }
  93. /// Construct from a polyhedron.
  94. explicit BoundingBox(const Polyhedron& poly) :
  95. min_(M_INFINITY, M_INFINITY, M_INFINITY),
  96. max_(-M_INFINITY, -M_INFINITY, -M_INFINITY)
  97. {
  98. Define(poly);
  99. }
  100. /// Construct from a sphere.
  101. explicit BoundingBox(const Sphere& sphere) :
  102. min_(M_INFINITY, M_INFINITY, M_INFINITY),
  103. max_(-M_INFINITY, -M_INFINITY, -M_INFINITY)
  104. {
  105. Define(sphere);
  106. }
  107. /// Assign from another bounding box.
  108. BoundingBox& operator =(const BoundingBox& rhs) noexcept
  109. {
  110. min_ = rhs.min_;
  111. max_ = rhs.max_;
  112. return *this;
  113. }
  114. /// Assign from a Rect, with the Z dimension left zero.
  115. BoundingBox& operator =(const Rect& rhs) noexcept
  116. {
  117. min_ = Vector3(rhs.min_, 0.0f);
  118. max_ = Vector3(rhs.max_, 0.0f);
  119. return *this;
  120. }
  121. /// Test for equality with another bounding box.
  122. bool operator ==(const BoundingBox& rhs) const { return (min_ == rhs.min_ && max_ == rhs.max_); }
  123. /// Test for inequality with another bounding box.
  124. bool operator !=(const BoundingBox& rhs) const { return (min_ != rhs.min_ || max_ != rhs.max_); }
  125. /// Define from another bounding box.
  126. void Define(const BoundingBox& box)
  127. {
  128. Define(box.min_, box.max_);
  129. }
  130. /// Define from a Rect.
  131. void Define(const Rect& rect)
  132. {
  133. Define(Vector3(rect.min_, 0.0f), Vector3(rect.max_, 0.0f));
  134. }
  135. /// Define from minimum and maximum vectors.
  136. void Define(const Vector3& min, const Vector3& max)
  137. {
  138. min_ = min;
  139. max_ = max;
  140. }
  141. /// Define from minimum and maximum floats (all dimensions same).
  142. void Define(float min, float max)
  143. {
  144. min_ = Vector3(min, min, min);
  145. max_ = Vector3(max, max, max);
  146. }
  147. /// Define from a point.
  148. void Define(const Vector3& point)
  149. {
  150. min_ = max_ = point;
  151. }
  152. /// Merge a point.
  153. void Merge(const Vector3& point)
  154. {
  155. #ifdef URHO3D_SSE
  156. __m128 vec = _mm_set_ps(1.f, point.z_, point.y_, point.x_);
  157. _mm_storeu_ps(&min_.x_, _mm_min_ps(_mm_loadu_ps(&min_.x_), vec));
  158. _mm_storeu_ps(&max_.x_, _mm_max_ps(_mm_loadu_ps(&max_.x_), vec));
  159. #else
  160. if (point.x_ < min_.x_)
  161. min_.x_ = point.x_;
  162. if (point.y_ < min_.y_)
  163. min_.y_ = point.y_;
  164. if (point.z_ < min_.z_)
  165. min_.z_ = point.z_;
  166. if (point.x_ > max_.x_)
  167. max_.x_ = point.x_;
  168. if (point.y_ > max_.y_)
  169. max_.y_ = point.y_;
  170. if (point.z_ > max_.z_)
  171. max_.z_ = point.z_;
  172. #endif
  173. }
  174. /// Merge another bounding box.
  175. void Merge(const BoundingBox& box)
  176. {
  177. #ifdef URHO3D_SSE
  178. _mm_storeu_ps(&min_.x_, _mm_min_ps(_mm_loadu_ps(&min_.x_), _mm_loadu_ps(&box.min_.x_)));
  179. _mm_storeu_ps(&max_.x_, _mm_max_ps(_mm_loadu_ps(&max_.x_), _mm_loadu_ps(&box.max_.x_)));
  180. #else
  181. if (box.min_.x_ < min_.x_)
  182. min_.x_ = box.min_.x_;
  183. if (box.min_.y_ < min_.y_)
  184. min_.y_ = box.min_.y_;
  185. if (box.min_.z_ < min_.z_)
  186. min_.z_ = box.min_.z_;
  187. if (box.max_.x_ > max_.x_)
  188. max_.x_ = box.max_.x_;
  189. if (box.max_.y_ > max_.y_)
  190. max_.y_ = box.max_.y_;
  191. if (box.max_.z_ > max_.z_)
  192. max_.z_ = box.max_.z_;
  193. #endif
  194. }
  195. /// Define from an array of vertices.
  196. void Define(const Vector3* vertices, unsigned count);
  197. /// Define from a frustum.
  198. void Define(const Frustum& frustum);
  199. /// Define from a polyhedron.
  200. void Define(const Polyhedron& poly);
  201. /// Define from a sphere.
  202. void Define(const Sphere& sphere);
  203. /// Merge an array of vertices.
  204. void Merge(const Vector3* vertices, unsigned count);
  205. /// Merge a frustum.
  206. void Merge(const Frustum& frustum);
  207. /// Merge a polyhedron.
  208. void Merge(const Polyhedron& poly);
  209. /// Merge a sphere.
  210. void Merge(const Sphere& sphere);
  211. /// Clip with another bounding box. The box can become degenerate (undefined) as a result.
  212. void Clip(const BoundingBox& box);
  213. /// Transform with a 3x3 matrix.
  214. void Transform(const Matrix3& transform);
  215. /// Transform with a 3x4 matrix.
  216. void Transform(const Matrix3x4& transform);
  217. /// Clear to undefined state.
  218. void Clear()
  219. {
  220. #ifdef URHO3D_SSE
  221. _mm_storeu_ps(&min_.x_, _mm_set1_ps(M_INFINITY));
  222. _mm_storeu_ps(&max_.x_, _mm_set1_ps(-M_INFINITY));
  223. #else
  224. min_ = Vector3(M_INFINITY, M_INFINITY, M_INFINITY);
  225. max_ = Vector3(-M_INFINITY, -M_INFINITY, -M_INFINITY);
  226. #endif
  227. }
  228. /// Return true if this bounding box is defined via a previous call to Define() or Merge().
  229. bool Defined() const
  230. {
  231. return min_.x_ != M_INFINITY;
  232. }
  233. /// Return center.
  234. /// @property
  235. Vector3 Center() const { return (max_ + min_) * 0.5f; }
  236. /// Return size.
  237. /// @property
  238. Vector3 Size() const { return max_ - min_; }
  239. /// Return half-size.
  240. /// @property
  241. Vector3 HalfSize() const { return (max_ - min_) * 0.5f; }
  242. /// Return transformed by a 3x3 matrix.
  243. BoundingBox Transformed(const Matrix3& transform) const;
  244. /// Return transformed by a 3x4 matrix.
  245. BoundingBox Transformed(const Matrix3x4& transform) const;
  246. /// Return projected by a 4x4 projection matrix.
  247. Rect Projected(const Matrix4& projection) const;
  248. /// Return distance to point.
  249. float DistanceToPoint(const Vector3& point) const;
  250. /// Test if a point is inside.
  251. Intersection IsInside(const Vector3& point) const
  252. {
  253. if (point.x_ < min_.x_ || point.x_ > max_.x_ || point.y_ < min_.y_ || point.y_ > max_.y_ ||
  254. point.z_ < min_.z_ || point.z_ > max_.z_)
  255. return OUTSIDE;
  256. else
  257. return INSIDE;
  258. }
  259. /// Test if another bounding box is inside, outside or intersects.
  260. Intersection IsInside(const BoundingBox& box) const
  261. {
  262. if (box.max_.x_ < min_.x_ || box.min_.x_ > max_.x_ || box.max_.y_ < min_.y_ || box.min_.y_ > max_.y_ ||
  263. box.max_.z_ < min_.z_ || box.min_.z_ > max_.z_)
  264. return OUTSIDE;
  265. else if (box.min_.x_ < min_.x_ || box.max_.x_ > max_.x_ || box.min_.y_ < min_.y_ || box.max_.y_ > max_.y_ ||
  266. box.min_.z_ < min_.z_ || box.max_.z_ > max_.z_)
  267. return INTERSECTS;
  268. else
  269. return INSIDE;
  270. }
  271. /// Test if another bounding box is (partially) inside or outside.
  272. Intersection IsInsideFast(const BoundingBox& box) const
  273. {
  274. if (box.max_.x_ < min_.x_ || box.min_.x_ > max_.x_ || box.max_.y_ < min_.y_ || box.min_.y_ > max_.y_ ||
  275. box.max_.z_ < min_.z_ || box.min_.z_ > max_.z_)
  276. return OUTSIDE;
  277. else
  278. return INSIDE;
  279. }
  280. /// Test if a sphere is inside, outside or intersects.
  281. Intersection IsInside(const Sphere& sphere) const;
  282. /// Test if a sphere is (partially) inside or outside.
  283. Intersection IsInsideFast(const Sphere& sphere) const;
  284. /// Return as string.
  285. String ToString() const;
  286. /// Minimum vector.
  287. Vector3 min_;
  288. float dummyMin_{}; // This is never used, but exists to pad the min_ value to four floats.
  289. /// Maximum vector.
  290. Vector3 max_;
  291. float dummyMax_{}; // This is never used, but exists to pad the max_ value to four floats.
  292. };
  293. }