[8901] Implement rage save part of talent 29723 buff and ranks.
[getmangos.git] / dep / src / g3dlite / Box.cpp
blobb99104ff28b0ac07683743da24de0027b7ea263f
1 /**
2 @file Box.cpp
3 Box class
5 @maintainer Morgan McGuire, matrix@graphics3d.com
7 @created 2001-06-02
8 @edited 2006-02-05
9 */
11 #include "G3D/Box.h"
12 #include "G3D/debug.h"
13 #include "G3D/Plane.h"
14 #include "G3D/AABox.h"
15 #include "G3D/CoordinateFrame.h"
17 namespace G3D {
19 /**
20 Sets a field on four vertices. Used by the constructor.
22 #define setMany(i0, i1, i2, i3, field, extreme) \
23 _corner[i0].field = _corner[i1].field = \
24 _corner[i2].field = _corner[i3].field = \
25 (extreme).field
27 Box::Box() {
31 Box::Box(const AABox& b) {
32 init(b.low(), b.high());
36 Box::Box(
37 const Vector3& min,
38 const Vector3& max) {
40 init(min.min(max), min.max(max));
44 void Box::init(
45 const Vector3& min,
46 const Vector3& max) {
48 setMany(0, 1, 2, 3, z, max);
49 setMany(4, 5, 6, 7, z, min);
51 setMany(1, 2, 5, 6, x, max);
52 setMany(0, 3, 4, 7, x, min);
54 setMany(3, 2, 6, 7, y, max);
55 setMany(0, 1, 5, 4, y, min);
57 _extent = max - min;
59 _axis[0] = Vector3::unitX();
60 _axis[1] = Vector3::unitY();
61 _axis[2] = Vector3::unitZ();
63 _volume = _extent.x * _extent.y * _extent.z;
64 _area = 2 *
65 (_extent.x * _extent.y +
66 _extent.y * _extent.z +
67 _extent.z * _extent.x);
69 _center = (max + min) / 2;
73 float Box::volume() const {
74 return _volume;
78 float Box::surfaceArea() const {
79 return _area;
83 void Box::getLocalFrame(CoordinateFrame& frame) const {
85 frame.rotation = Matrix3(
86 _axis[0][0], _axis[1][0], _axis[2][0],
87 _axis[0][1], _axis[1][1], _axis[2][1],
88 _axis[0][2], _axis[1][2], _axis[2][2]);
90 frame.translation = _center;
94 CoordinateFrame Box::localFrame() const {
95 CoordinateFrame out;
96 getLocalFrame(out);
97 return out;
101 void Box::getFaceCorners(int f, Vector3& v0, Vector3& v1, Vector3& v2, Vector3& v3) const {
102 switch (f) {
103 case 0:
104 v0 = _corner[0]; v1 = _corner[1]; v2 = _corner[2]; v3 = _corner[3];
105 break;
107 case 1:
108 v0 = _corner[1]; v1 = _corner[5]; v2 = _corner[6]; v3 = _corner[2];
109 break;
111 case 2:
112 v0 = _corner[7]; v1 = _corner[6]; v2 = _corner[5]; v3 = _corner[4];
113 break;
115 case 3:
116 v0 = _corner[2]; v1 = _corner[6]; v2 = _corner[7]; v3 = _corner[3];
117 break;
119 case 4:
120 v0 = _corner[3]; v1 = _corner[7]; v2 = _corner[4]; v3 = _corner[0];
121 break;
123 case 5:
124 v0 = _corner[1]; v1 = _corner[0]; v2 = _corner[4]; v3 = _corner[5];
125 break;
127 default:
128 debugAssert((f >= 0) && (f < 6));
133 bool Box::culledBy(
134 const Array<Plane>& plane,
135 int& cullingPlaneIndex,
136 const uint32 inMask,
137 uint32& outMask) const {
139 return culledBy(plane.getCArray(), plane.size(), cullingPlaneIndex, inMask, outMask);
143 bool Box::culledBy(
144 const Array<Plane>& plane,
145 int& cullingPlaneIndex,
146 const uint32 inMask) const {
148 return culledBy(plane.getCArray(), plane.size(), cullingPlaneIndex, inMask);
152 int32 Box::dummy = 0;
154 bool Box::culledBy(
155 const class Plane* plane,
156 int numPlanes,
157 int& cullingPlane,
158 const uint32 _inMask,
159 uint32& childMask) const {
161 uint32 inMask = _inMask;
162 assert(numPlanes < 31);
164 childMask = 0;
166 // See if there is one plane for which all of the
167 // vertices are in the negative half space.
168 for (int p = 0; p < numPlanes; p++) {
170 // Only test planes that are not masked
171 if ((inMask & 1) != 0) {
173 Vector3 corner;
175 int numContained = 0;
176 int v = 0;
178 // We can early-out only if we have found one point on each
179 // side of the plane (i.e. if we are straddling). That
180 // occurs when (numContained < v) && (numContained > 0)
181 for (v = 0; (v < 8) && ((numContained == v) || (numContained == 0)); ++v) {
182 if (plane[p].halfSpaceContains(getCorner(v))) {
183 ++numContained;
187 if (numContained == 0) {
188 // Plane p culled the box
189 cullingPlane = p;
191 // The caller should not recurse into the children,
192 // since the parent is culled. If they do recurse,
193 // make them only test against this one plane, which
194 // will immediately cull the volume.
195 childMask = 1 << p;
196 return true;
198 } else if (numContained < v) {
199 // The bounding volume straddled the plane; we have
200 // to keep testing against this plane
201 childMask |= (1 << p);
205 // Move on to the next bit.
206 inMask = inMask >> 1;
209 // None of the planes could cull this box
210 cullingPlane = -1;
211 return false;
215 bool Box::culledBy(
216 const class Plane* plane,
217 int numPlanes,
218 int& cullingPlane,
219 const uint32 _inMask) const {
221 uint32 inMask = _inMask;
222 assert(numPlanes < 31);
224 // See if there is one plane for which all of the
225 // vertices are in the negative half space.
226 for (int p = 0; p < numPlanes; p++) {
228 // Only test planes that are not masked
229 if ((inMask & 1) != 0) {
231 bool culled = true;
233 int v;
235 // Assume this plane culls all points. See if there is a point
236 // not culled by the plane... early out when at least one point
237 // is in the positive half space.
238 for (v = 0; (v < 8) && culled; ++v) {
239 culled = ! plane[p].halfSpaceContains(getCorner(v));
242 if (culled) {
243 // Plane p culled the box
244 cullingPlane = p;
246 return true;
250 // Move on to the next bit.
251 inMask = inMask >> 1;
254 // None of the planes could cull this box
255 cullingPlane = -1;
256 return false;
260 bool Box::contains(
261 const Vector3& point) const {
263 // Form axes from three edges, transform the point into that
264 // space, and perform 3 interval tests
266 Vector3 u = _corner[4] - _corner[0];
267 Vector3 v = _corner[3] - _corner[0];
268 Vector3 w = _corner[1] - _corner[0];
270 Matrix3 M = Matrix3(u.x, v.x, w.x,
271 u.y, v.y, w.y,
272 u.z, v.z, w.z);
274 // M^-1 * (point - _corner[0]) = point in unit cube's object space
275 // compute the inverse of M
276 Vector3 osPoint = M.inverse() * (point - _corner[0]);
278 return
279 (osPoint.x >= 0) &&
280 (osPoint.y >= 0) &&
281 (osPoint.z >= 0) &&
282 (osPoint.x <= 1) &&
283 (osPoint.y <= 1) &&
284 (osPoint.z <= 1);
287 #undef setMany
289 #if 0
290 void Box::getRandomSurfacePoint(Vector3& P, Vector3& N) const {
291 float aXY = _extent.x * _extent.y;
292 float aYZ = _extent.y * _extent.z;
293 float aZX = _extent.z * _extent.x;
295 float r = (float)random(0, aXY + aYZ + aZX);
297 // Choose evenly between positive and negative face planes
298 float d = (random(0, 1) < 0.5f) ? -1.0f : 1.0f;
300 // The probability of choosing a given face is proportional to
301 // its area.
302 if (r < aXY) {
303 P = _axis[0] * (float)random(-0.5, 0.5) * _extent.x +
304 _axis[1] * (float)random(-0.5, 0.5) * _extent.y +
305 _center + _axis[2] * d * _extent.z * 0.5f;
306 N = _axis[2] * d;
307 } else if (r < aYZ) {
308 P = _axis[1] * (float)random(-0.5, 0.5) * _extent.y +
309 _axis[2] * (float)random(-0.5, 0.5) * _extent.z +
310 _center + _axis[0] * d * _extent.x * 0.5f;
311 N = _axis[0] * d;
312 } else {
313 P = _axis[2] * (float)random(-0.5, 0.5) * _extent.z +
314 _axis[0] *(float) random(-0.5, 0.5) * _extent.x +
315 _center + _axis[1] * d * _extent.y * 0.5f;
316 N = _axis[1] * d;
321 Vector3 Box::randomInteriorPoint() const {
322 Vector3 sum = _center;
324 for (int a = 0; a < 3; ++a) {
325 sum += _axis[a] * (float)random(-0.5, 0.5) * _extent[a];
328 return sum;
330 #endif
333 void Box::getBounds(class AABox& aabb) const {
335 Vector3 lo = _corner[0];
336 Vector3 hi = lo;
338 for (int v = 1; v < 8; ++v) {
339 const Vector3& C = _corner[v];
340 lo = lo.min(C);
341 hi = hi.max(C);
344 aabb = AABox(lo, hi);
348 } // namespace