Line data Source code
1 : /* Copyright (C) 2021 Wildfire Games.
2 : * This file is part of 0 A.D.
3 : *
4 : * 0 A.D. is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 2 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * 0 A.D. is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16 : */
17 :
18 : /*
19 : * Axis-aligned bounding box
20 : */
21 :
22 : #ifndef INCLUDED_BOUND
23 : #define INCLUDED_BOUND
24 :
25 : #include "maths/Vector3D.h"
26 : #include "graphics/ShaderProgramPtr.h"
27 :
28 : class CFrustum;
29 : class CMatrix3D;
30 : class CBoundingBoxOriented;
31 :
32 : // Basic axis aligned bounding box (AABB) class
33 : class CBoundingBoxAligned
34 : {
35 : public:
36 : static const CBoundingBoxAligned EMPTY;
37 :
38 400 : CBoundingBoxAligned() { SetEmpty(); }
39 34 : CBoundingBoxAligned(const CVector3D& min, const CVector3D& max)
40 34 : {
41 34 : m_Data[0] = min;
42 34 : m_Data[1] = max;
43 34 : }
44 :
45 : /**
46 : * Transforms these bounds according to the specified transformation matrix @p m, and writes the axis-aligned bounds
47 : * of that result to @p result.
48 : */
49 : void Transform(const CMatrix3D& m, CBoundingBoxAligned& result) const;
50 :
51 : /**
52 : * Transform these bounds using the matrix @p transform, and write out the result as an oriented (i.e. non-axis-aligned) box.
53 : * The difference with @ref Transform(const CMatrix3D&, CBoundingBoxAligned&) is that that method is equivalent to first
54 : * computing this result, and then taking the axis-aligned bounding boxes from the result again.
55 : */
56 : void Transform(const CMatrix3D& m, CBoundingBoxOriented& result) const;
57 :
58 : /**
59 : * Translates these bounds by @p v, and writes the result to @p result.
60 : */
61 1 : void Translate(const CVector3D& v, CBoundingBoxAligned& result) const
62 : {
63 1 : result.m_Data[0] = m_Data[0] + v;
64 1 : result.m_Data[1] = m_Data[1] + v;
65 1 : }
66 :
67 1572 : CVector3D& operator[](int index) { return m_Data[index]; }
68 516 : const CVector3D& operator[](int index) const { return m_Data[index]; }
69 :
70 : void SetEmpty();
71 : bool IsEmpty() const;
72 :
73 296015 : void Extend(const CVector3D& min, const CVector3D& max)
74 : {
75 296015 : if (min.X < m_Data[0].X) m_Data[0].X = min.X;
76 296015 : if (min.Y < m_Data[0].Y) m_Data[0].Y = min.Y;
77 296015 : if (min.Z < m_Data[0].Z) m_Data[0].Z = min.Z;
78 296015 : if (max.X > m_Data[1].X) m_Data[1].X = max.X;
79 296015 : if (max.Y > m_Data[1].Y) m_Data[1].Y = max.Y;
80 296015 : if (max.Z > m_Data[1].Z) m_Data[1].Z = max.Z;
81 296015 : }
82 :
83 : // operator+=: extend this bound to include given bound
84 1 : CBoundingBoxAligned& operator+=(const CBoundingBoxAligned& b)
85 : {
86 1 : Extend(b.m_Data[0], b.m_Data[1]);
87 1 : return *this;
88 : }
89 :
90 : // operator+=: extend this bound to include given point
91 296014 : CBoundingBoxAligned& operator+=(const CVector3D& pt)
92 : {
93 296014 : Extend(pt, pt);
94 296014 : return *this;
95 : }
96 :
97 : /**
98 : * Check if a given ray intersects this AABB.
99 : * See also Real-Time Rendering, Third Edition by T. Akenine-Moller, p. 741--742.
100 : *
101 : * @param[in] origin Origin of the ray.
102 : * @param[in] dir Direction vector of the ray, defining the positive direction of the ray. Must be of unit length.
103 : * @param[out] tmin,tmax distance in the positive direction from the origin of the ray to the entry and exit points in
104 : * the bounding box. If the origin is inside the box, then this is counted as an intersection and one of @p tMin and @p tMax may be negative.
105 : *
106 : * @return true if the ray originating in @p origin and with unit direction vector @p dir intersects this AABB, false otherwise.
107 : */
108 : bool RayIntersect(const CVector3D& origin, const CVector3D& dir, float& tmin, float& tmax) const;
109 :
110 : bool IsPointInside(const CVector3D& point) const;
111 :
112 : // return the volume of this bounding box
113 0 : float GetVolume() const
114 : {
115 0 : CVector3D v = m_Data[1] - m_Data[0];
116 0 : return (std::max(v.X, 0.0f) * std::max(v.Y, 0.0f) * std::max(v.Z, 0.0f));
117 : }
118 :
119 : // return the center of this bounding box
120 3 : void GetCenter(CVector3D& center) const
121 : {
122 3 : center = (m_Data[0] + m_Data[1]) * 0.5f;
123 3 : }
124 :
125 : /**
126 : * Expand the bounding box by the given amount in every direction.
127 : */
128 : void Expand(float amount);
129 :
130 : /**
131 : * IntersectFrustumConservative: Approximate the intersection of this bounds object
132 : * with the given frustum. The bounds object is overwritten with the results.
133 : *
134 : * The approximation is conservative in the sense that the result will always contain
135 : * the actual intersection, but it may be larger than the intersection itself.
136 : * The result will always be fully contained within the original bounds.
137 : *
138 : * @note While not in the spirit of this function's purpose, a no-op would be a correct
139 : * implementation of this function.
140 : * @note If this bound is empty, the result is the empty bound.
141 : *
142 : * @param frustum the frustum to intersect with
143 : */
144 : void IntersectFrustumConservative(const CFrustum& frustum);
145 :
146 : /**
147 : * Construct a CFrustum that describes the same volume as this bounding box.
148 : * Only valid for non-empty bounding boxes - check IsEmpty() first.
149 : */
150 : CFrustum ToFrustum() const;
151 :
152 : private:
153 : // Holds the minimal and maximal coordinate points in m_Data[0] and m_Data[1], respectively.
154 : CVector3D m_Data[2];
155 : };
156 :
157 : #endif // INCLUDED_BOUND
|