1 | /* Copyright (C) 2019 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 | CBoundingBoxAligned() { SetEmpty(); }
|
---|
39 | CBoundingBoxAligned(const CVector3D& min, const CVector3D& max)
|
---|
40 | {
|
---|
41 | m_Data[0] = min;
|
---|
42 | m_Data[1] = max;
|
---|
43 | }
|
---|
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 | void Translate(const CVector3D& v, CBoundingBoxAligned& result) const
|
---|
62 | {
|
---|
63 | result.m_Data[0] = m_Data[0] + v;
|
---|
64 | result.m_Data[1] = m_Data[1] + v;
|
---|
65 | }
|
---|
66 |
|
---|
67 | CVector3D& operator[](int index) { return m_Data[index]; }
|
---|
68 | const CVector3D& operator[](int index) const { return m_Data[index]; }
|
---|
69 |
|
---|
70 | void SetEmpty();
|
---|
71 | bool IsEmpty() const;
|
---|
72 |
|
---|
73 | void Extend(const CVector3D& min, const CVector3D& max)
|
---|
74 | {
|
---|
75 | if (min.X < m_Data[0].X) m_Data[0].X = min.X;
|
---|
76 | if (min.Y < m_Data[0].Y) m_Data[0].Y = min.Y;
|
---|
77 | if (min.Z < m_Data[0].Z) m_Data[0].Z = min.Z;
|
---|
78 | if (max.X > m_Data[1].X) m_Data[1].X = max.X;
|
---|
79 | if (max.Y > m_Data[1].Y) m_Data[1].Y = max.Y;
|
---|
80 | if (max.Z > m_Data[1].Z) m_Data[1].Z = max.Z;
|
---|
81 | }
|
---|
82 |
|
---|
83 | // operator+=: extend this bound to include given bound
|
---|
84 | CBoundingBoxAligned& operator+=(const CBoundingBoxAligned& b)
|
---|
85 | {
|
---|
86 | Extend(b.m_Data[0], b.m_Data[1]);
|
---|
87 | return *this;
|
---|
88 | }
|
---|
89 |
|
---|
90 | // operator+=: extend this bound to include given point
|
---|
91 | CBoundingBoxAligned& operator+=(const CVector3D& pt)
|
---|
92 | {
|
---|
93 | Extend(pt, pt);
|
---|
94 | 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 | // return the volume of this bounding box
|
---|
111 | float GetVolume() const
|
---|
112 | {
|
---|
113 | CVector3D v = m_Data[1] - m_Data[0];
|
---|
114 | return (std::max(v.X, 0.0f) * std::max(v.Y, 0.0f) * std::max(v.Z, 0.0f));
|
---|
115 | }
|
---|
116 |
|
---|
117 | // return the center of this bounding box
|
---|
118 | void GetCenter(CVector3D& center) const
|
---|
119 | {
|
---|
120 | center = (m_Data[0] + m_Data[1]) * 0.5f;
|
---|
121 | }
|
---|
122 |
|
---|
123 | /**
|
---|
124 | * Expand the bounding box by the given amount in every direction.
|
---|
125 | */
|
---|
126 | void Expand(float amount);
|
---|
127 |
|
---|
128 | /**
|
---|
129 | * IntersectFrustumConservative: Approximate the intersection of this bounds object
|
---|
130 | * with the given frustum. The bounds object is overwritten with the results.
|
---|
131 | *
|
---|
132 | * The approximation is conservative in the sense that the result will always contain
|
---|
133 | * the actual intersection, but it may be larger than the intersection itself.
|
---|
134 | * The result will always be fully contained within the original bounds.
|
---|
135 | *
|
---|
136 | * @note While not in the spirit of this function's purpose, a no-op would be a correct
|
---|
137 | * implementation of this function.
|
---|
138 | * @note If this bound is empty, the result is the empty bound.
|
---|
139 | *
|
---|
140 | * @param frustum the frustum to intersect with
|
---|
141 | */
|
---|
142 | void IntersectFrustumConservative(const CFrustum& frustum);
|
---|
143 |
|
---|
144 | /**
|
---|
145 | * Construct a CFrustum that describes the same volume as this bounding box.
|
---|
146 | * Only valid for non-empty bounding boxes - check IsEmpty() first.
|
---|
147 | */
|
---|
148 | CFrustum ToFrustum() const;
|
---|
149 |
|
---|
150 | /**
|
---|
151 | * Render the surfaces of the bound object as triangles.
|
---|
152 | */
|
---|
153 | void Render(CShaderProgramPtr& shader) const;
|
---|
154 |
|
---|
155 | /**
|
---|
156 | * Render the outline of the bound object as lines.
|
---|
157 | */
|
---|
158 | void RenderOutline(CShaderProgramPtr& shader) const;
|
---|
159 |
|
---|
160 | private:
|
---|
161 | // Holds the minimal and maximal coordinate points in m_Data[0] and m_Data[1], respectively.
|
---|
162 | CVector3D m_Data[2];
|
---|
163 | };
|
---|
164 |
|
---|
165 | #endif // INCLUDED_BOUND
|
---|