Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
BoundingBoxAligned.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2012 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 #include "precompiled.h"
23 
24 #include "BoundingBoxAligned.h"
25 
26 #include "lib/ogl.h"
27 
28 #include <float.h>
29 
30 #include "graphics/Frustum.h"
32 #include "maths/Brush.h"
33 #include "maths/Matrix3D.h"
34 
35 const CBoundingBoxAligned CBoundingBoxAligned::EMPTY = CBoundingBoxAligned(); // initializes to an empty bound
36 
37 ///////////////////////////////////////////////////////////////////////////////
38 // RayIntersect: intersect ray with this bound; return true
39 // if ray hits (and store entry and exit times), or false
40 // otherwise
41 // note: incoming ray direction must be normalised
43  float& tmin,float& tmax) const
44 {
45  float t1,t2;
46  float tnear,tfar;
47 
48  if (dir[0]==0) {
49  if (origin[0]<m_Data[0][0] || origin[0]>m_Data[1][0])
50  return false;
51  else {
52  tnear=(float) -FLT_MAX;
53  tfar=(float) FLT_MAX;
54  }
55  } else {
56  t1=(m_Data[0][0]-origin[0])/dir[0];
57  t2=(m_Data[1][0]-origin[0])/dir[0];
58 
59  if (dir[0]<0) {
60  tnear = t2;
61  tfar = t1;
62  } else {
63  tnear = t1;
64  tfar = t2;
65  }
66 
67  if (tfar<0)
68  return false;
69  }
70 
71  if (dir[1]==0 && (origin[1]<m_Data[0][1] || origin[1]>m_Data[1][1]))
72  return false;
73  else {
74  t1=(m_Data[0][1]-origin[1])/dir[1];
75  t2=(m_Data[1][1]-origin[1])/dir[1];
76 
77  if (dir[1]<0) {
78  if (t2>tnear)
79  tnear = t2;
80  if (t1<tfar)
81  tfar = t1;
82  } else {
83  if (t1>tnear)
84  tnear = t1;
85  if (t2<tfar)
86  tfar = t2;
87  }
88 
89  if (tnear>tfar || tfar<0)
90  return false;
91  }
92 
93  if (dir[2]==0 && (origin[2]<m_Data[0][2] || origin[2]>m_Data[1][2]))
94  return false;
95  else {
96  t1=(m_Data[0][2]-origin[2])/dir[2];
97  t2=(m_Data[1][2]-origin[2])/dir[2];
98 
99  if (dir[2]<0) {
100  if (t2>tnear)
101  tnear = t2;
102  if (t1<tfar)
103  tfar = t1;
104  } else {
105  if (t1>tnear)
106  tnear = t1;
107  if (t2<tfar)
108  tfar = t2;
109  }
110 
111  if (tnear>tfar || tfar<0)
112  return false;
113  }
114 
115  tmin=tnear;
116  tmax=tfar;
117 
118  return true;
119 }
120 
121 ///////////////////////////////////////////////////////////////////////////////
122 // SetEmpty: initialise this bound as empty
124 {
125  m_Data[0]=CVector3D( FLT_MAX, FLT_MAX, FLT_MAX);
126  m_Data[1]=CVector3D(-FLT_MAX,-FLT_MAX,-FLT_MAX);
127 }
128 
129 ///////////////////////////////////////////////////////////////////////////////
130 // IsEmpty: tests whether this bound is empty
132 {
133  return (m_Data[0].X == FLT_MAX && m_Data[0].Y == FLT_MAX && m_Data[0].Z == FLT_MAX
134  && m_Data[1].X == -FLT_MAX && m_Data[1].Y == -FLT_MAX && m_Data[1].Z == -FLT_MAX);
135 }
136 
137 ///////////////////////////////////////////////////////////////////////////////
138 // Transform: transform this bound by given matrix; return transformed bound
139 // in 'result' parameter - slightly modified version of code in Graphic Gems
140 // (can't remember which one it was, though)
142 {
143  ENSURE(this!=&result);
144 
145  for (int i=0;i<3;++i) {
146  // handle translation
147  result[0][i]=result[1][i]=m(i,3);
148 
149  // Now find the extreme points by considering the product of the
150  // min and max with each component of matrix
151  for(int j=0;j<3;j++) {
152  float a=m(i,j)*m_Data[0][j];
153  float b=m(i,j)*m_Data[1][j];
154 
155  if (a<b) {
156  result[0][i]+=a;
157  result[1][i]+=b;
158  } else {
159  result[0][i]+=b;
160  result[1][i]+=a;
161  }
162  }
163  }
164 }
165 
166 void CBoundingBoxAligned::Transform(const CMatrix3D& transform, CBoundingBoxOriented& result) const
167 {
168  const CVector3D& pMin = m_Data[0];
169  const CVector3D& pMax = m_Data[1];
170 
171  // the basis vectors of the OBB are the normalized versions of the transformed AABB basis vectors, which
172  // are the columns of the identity matrix, so the unnormalized OBB basis vectors are the transformation
173  // matrix columns:
174  CVector3D u(transform._11, transform._21, transform._31);
175  CVector3D v(transform._12, transform._22, transform._32);
176  CVector3D w(transform._13, transform._23, transform._33);
177 
178  // the half-sizes are scaled by whatever factor the AABB unit vectors end up scaled by
179  result.m_HalfSizes = CVector3D(
180  (pMax.X - pMin.X) / 2.f * u.Length(),
181  (pMax.Y - pMin.Y) / 2.f * v.Length(),
182  (pMax.Z - pMin.Z) / 2.f * w.Length()
183  );
184 
185  u.Normalize();
186  v.Normalize();
187  w.Normalize();
188 
189  result.m_Basis[0] = u;
190  result.m_Basis[1] = v;
191  result.m_Basis[2] = w;
192 
193  result.m_Center = transform.Transform((pMax + pMin) * 0.5f);
194 }
195 
196 ///////////////////////////////////////////////////////////////////////////////
197 // Intersect with the given frustum in a conservative manner
199 {
200  // if this bound is empty, then the result must be empty (we should not attempt to intersect with
201  // a brush, may cause crashes due to the numeric representation of empty bounds -- see
202  // http://trac.wildfiregames.com/ticket/1027)
203  if (IsEmpty())
204  return;
205 
206  CBrush brush(*this);
207  CBrush buf;
208 
209  brush.Intersect(frustum, buf);
210 
211  buf.Bounds(*this);
212 }
213 
214 
215 ///////////////////////////////////////////////////////////////////////////////
216 void CBoundingBoxAligned::Expand(float amount)
217 {
218  m_Data[0] -= CVector3D(amount, amount, amount);
219  m_Data[1] += CVector3D(amount, amount, amount);
220 }
221 
222 ///////////////////////////////////////////////////////////////////////////////
223 // Render the bounding box
225 {
226  std::vector<float> data;
227 
228 #define ADD_FACE(x, y, z) \
229  ADD_PT(0, 0, x, y, z); ADD_PT(1, 0, x, y, z); ADD_PT(1, 1, x, y, z); \
230  ADD_PT(1, 1, x, y, z); ADD_PT(0, 1, x, y, z); ADD_PT(0, 0, x, y, z);
231 #define ADD_PT(u_, v_, x, y, z) \
232  STMT(int u = u_; int v = v_; \
233  data.push_back(u); \
234  data.push_back(v); \
235  data.push_back(m_Data[x].X); \
236  data.push_back(m_Data[y].Y); \
237  data.push_back(m_Data[z].Z); \
238  )
239 
240  ADD_FACE(u, v, 0);
241  ADD_FACE(0, u, v);
242  ADD_FACE(u, 0, 1-v);
243  ADD_FACE(u, 1-v, 1);
244  ADD_FACE(1, u, 1-v);
245  ADD_FACE(u, 1, v);
246 
247 #undef ADD_FACE
248 
249  shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 5*sizeof(float), &data[0]);
250  shader->VertexPointer(3, GL_FLOAT, 5*sizeof(float), &data[2]);
251 
252  shader->AssertPointersBound();
253  glDrawArrays(GL_TRIANGLES, 0, 6*6);
254 }
255 
257 {
258  std::vector<float> data;
259 
260 #define ADD_FACE(x, y, z) \
261  ADD_PT(0, 0, x, y, z); ADD_PT(1, 0, x, y, z); \
262  ADD_PT(1, 0, x, y, z); ADD_PT(1, 1, x, y, z); \
263  ADD_PT(1, 1, x, y, z); ADD_PT(0, 1, x, y, z); \
264  ADD_PT(0, 1, x, y, z); ADD_PT(0, 0, x, y, z);
265 #define ADD_PT(u_, v_, x, y, z) \
266  STMT(int u = u_; int v = v_; \
267  data.push_back(u); \
268  data.push_back(v); \
269  data.push_back(m_Data[x].X); \
270  data.push_back(m_Data[y].Y); \
271  data.push_back(m_Data[z].Z); \
272  )
273 
274  ADD_FACE(u, v, 0);
275  ADD_FACE(0, u, v);
276  ADD_FACE(u, 0, 1-v);
277  ADD_FACE(u, 1-v, 1);
278  ADD_FACE(1, u, 1-v);
279  ADD_FACE(u, 1, v);
280 
281 #undef ADD_FACE
282 
283  shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 5*sizeof(float), &data[0]);
284  shader->VertexPointer(3, GL_FLOAT, 5*sizeof(float), &data[2]);
285 
286  shader->AssertPointersBound();
287  glDrawArrays(GL_LINES, 0, 6*8);
288 }
float _21
Definition: Matrix3D.h:42
void Transform(const CMatrix3D &m, CBoundingBoxAligned &result) const
Transforms these bounds according to the specified transformation matrix m, and writes the axis-align...
Definition: Decompose.h:22
void RenderOutline(CShaderProgramPtr &shader) const
Render: Render the outline of the bound object as lines.
float _22
Definition: Matrix3D.h:43
float _12
Definition: Matrix3D.h:43
void Intersect(const CFrustum &frustum, CBrush &result) const
Intersect: Intersect the brush with the given frustum.
Definition: Brush.cpp:348
Definition: Decompose.h:22
static const CBoundingBoxAligned EMPTY
CVector3D Transform(const CVector3D &vector) const
Definition: Matrix3D.h:272
#define ADD_FACE(x, y, z)
CVector3D m_Center
Centroid location of the box.
void Normalize()
Definition: Vector3D.cpp:77
float _32
Definition: Matrix3D.h:43
float _11
Definition: Matrix3D.h:42
float _33
Definition: Matrix3D.h:44
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
Class CBrush: Represents a convex object, supports some CSG operations.
Definition: Brush.h:35
float X
Definition: Vector3D.h:31
float Length() const
Definition: Vector3D.cpp:72
CVector3D m_Basis[3]
Basis vectors (u,v,w) of the sides.
float Y
Definition: Vector3D.h:31
void IntersectFrustumConservative(const CFrustum &frustum)
IntersectFrustumConservative: Approximate the intersection of this bounds object with the given frust...
float _13
Definition: Matrix3D.h:44
float _31
Definition: Matrix3D.h:42
CVector3D m_HalfSizes
Half the sizes of the box in each dimension (u,v,w).
bool RayIntersect(const CVector3D &origin, const CVector3D &dir, float &tmin, float &tmax) const
Check if a given ray intersects this AABB.
Definition: Decompose.h:22
void Bounds(CBoundingBoxAligned &result) const
Bounds: Calculate the axis-aligned bounding box for this brush.
Definition: Brush.cpp:63
float _23
Definition: Matrix3D.h:44
void Expand(float amount)
Expand the bounding box by the given amount in every direction.
float Z
Definition: Vector3D.h:31
void Render(CShaderProgramPtr &shader) const
Render: Render the surfaces of the bound object as triangles.
shared_ptr< CShaderProgram > CShaderProgramPtr