1// Copyright 2009-2021 Intel Corporation
2// SPDX-License-Identifier: Apache-2.0
3
4#pragma once
5
6#include "vec2.h"
7#include "vec3.h"
8
9namespace embree
10{
11 namespace internal {
12
13 template <typename T> __forceinline T divideByTwo(const T& v) { return v / T(2); }
14 template <> __forceinline float divideByTwo<float>(const float& v) { return v * 0.5f; }
15 template <> __forceinline double divideByTwo<double>(const double& v) { return v * 0.5; }
16
17 } // namespace internal
18 template<typename T>
19 struct BBox
20 {
21 T lower, upper;
22
23 ////////////////////////////////////////////////////////////////////////////////
24 /// Construction
25 ////////////////////////////////////////////////////////////////////////////////
26
27 __forceinline BBox ( ) { }
28 template<typename T1>
29 __forceinline BBox ( const BBox<T1>& other ) : lower(other.lower), upper(other.upper) {}
30 __forceinline BBox& operator=( const BBox& other ) { lower = other.lower; upper = other.upper; return *this; }
31
32 __forceinline BBox ( const T& v ) : lower(v), upper(v) {}
33 __forceinline BBox ( const T& lower, const T& upper ) : lower(lower), upper(upper) {}
34
35 ////////////////////////////////////////////////////////////////////////////////
36 /// Extending Bounds
37 ////////////////////////////////////////////////////////////////////////////////
38
39 __forceinline const BBox& extend(const BBox& other) { lower = min(lower,other.lower); upper = max(upper,other.upper); return *this; }
40 __forceinline const BBox& extend(const T & other) { lower = min(lower,other ); upper = max(upper,other ); return *this; }
41
42 /*! tests if box is empty */
43 __forceinline bool empty() const { for (int i=0; i<T::N; i++) if (lower[i] > upper[i]) return true; return false; }
44
45 /*! computes the size of the box */
46 __forceinline T size() const { return upper - lower; }
47
48 /*! computes the center of the box */
49 __forceinline T center() const { return internal::divideByTwo<T>(lower+upper); }
50
51 /*! computes twice the center of the box */
52 __forceinline T center2() const { return lower+upper; }
53
54 /*! merges two boxes */
55 __forceinline static const BBox merge (const BBox& a, const BBox& b) {
56 return BBox(min(a.lower, b.lower), max(a.upper, b.upper));
57 }
58
59 /*! enlarge box by some scaling factor */
60 __forceinline BBox enlarge_by(const float a) const {
61 return BBox(lower - T(a)*abs(lower), upper + T(a)*abs(upper));
62 }
63
64 ////////////////////////////////////////////////////////////////////////////////
65 /// Constants
66 ////////////////////////////////////////////////////////////////////////////////
67
68 __forceinline BBox( EmptyTy ) : lower(pos_inf), upper(neg_inf) {}
69 __forceinline BBox( FullTy ) : lower(neg_inf), upper(pos_inf) {}
70 __forceinline BBox( FalseTy ) : lower(pos_inf), upper(neg_inf) {}
71 __forceinline BBox( TrueTy ) : lower(neg_inf), upper(pos_inf) {}
72 __forceinline BBox( NegInfTy ): lower(pos_inf), upper(neg_inf) {}
73 __forceinline BBox( PosInfTy ): lower(neg_inf), upper(pos_inf) {}
74 };
75
76 template<> __forceinline bool BBox<float>::empty() const {
77 return lower > upper;
78 }
79
80#if defined(__SSE__) || defined(__ARM_NEON)
81 template<> __forceinline bool BBox<Vec3fa>::empty() const {
82 return !all(le_mask(lower,upper));
83 }
84 template<> __forceinline bool BBox<Vec3fx>::empty() const {
85 return !all(le_mask(lower,upper));
86 }
87#endif
88
89 /*! tests if box is finite */
90 __forceinline bool isvalid( const BBox<Vec3fa>& v ) {
91 return all(gt_mask(v.lower,Vec3fa_t(-FLT_LARGE)) & lt_mask(v.upper,Vec3fa_t(+FLT_LARGE)));
92 }
93
94 /*! tests if box is finite and non-empty*/
95 __forceinline bool isvalid_non_empty( const BBox<Vec3fa>& v ) {
96 return all(gt_mask(v.lower,Vec3fa_t(-FLT_LARGE)) & lt_mask(v.upper,Vec3fa_t(+FLT_LARGE)) & le_mask(v.lower,v.upper));
97 }
98
99 /*! tests if box has finite entries */
100 __forceinline bool is_finite( const BBox<Vec3fa>& b) {
101 return is_finite(b.lower) && is_finite(b.upper);
102 }
103
104 /*! test if point contained in box */
105 __forceinline bool inside ( const BBox<Vec3fa>& b, const Vec3fa& p ) { return all(ge_mask(p,b.lower) & le_mask(p,b.upper)); }
106
107 /*! computes the center of the box */
108 template<typename T> __forceinline const T center2(const BBox<T>& box) { return box.lower + box.upper; }
109 template<typename T> __forceinline const T center (const BBox<T>& box) { return internal::divideByTwo<T>(center2(box)); }
110
111 /*! computes the volume of a bounding box */
112 __forceinline float volume ( const BBox<Vec3fa>& b ) { return reduce_mul(b.size()); }
113 __forceinline float safeVolume( const BBox<Vec3fa>& b ) { if (b.empty()) return 0.0f; else return volume(b); }
114
115 /*! computes the volume of a bounding box */
116 __forceinline float volume( const BBox<Vec3f>& b ) { return reduce_mul(b.size()); }
117
118 /*! computes the surface area of a bounding box */
119 template<typename T> __forceinline const T area( const BBox<Vec2<T> >& b ) { const Vec2<T> d = b.size(); return d.x*d.y; }
120
121 template<typename T> __forceinline const T halfArea( const BBox<Vec3<T> >& b ) { return halfArea(b.size()); }
122 template<typename T> __forceinline const T area( const BBox<Vec3<T> >& b ) { return T(2)*halfArea(b); }
123
124 __forceinline float halfArea( const BBox<Vec3fa>& b ) { return halfArea(b.size()); }
125 __forceinline float area( const BBox<Vec3fa>& b ) { return 2.0f*halfArea(b); }
126
127 __forceinline float halfArea( const BBox<Vec3fx>& b ) { return halfArea(b.size()); }
128 __forceinline float area( const BBox<Vec3fx>& b ) { return 2.0f*halfArea(b); }
129
130 template<typename Vec> __forceinline float safeArea( const BBox<Vec>& b ) { if (b.empty()) return 0.0f; else return area(b); }
131
132 template<typename T> __forceinline float expectedApproxHalfArea(const BBox<T>& box) {
133 return halfArea(box);
134 }
135
136 /*! merges bounding boxes and points */
137 template<typename T> __forceinline const BBox<T> merge( const BBox<T>& a, const T& b ) { return BBox<T>(min(a.lower, b ), max(a.upper, b )); }
138 template<typename T> __forceinline const BBox<T> merge( const T& a, const BBox<T>& b ) { return BBox<T>(min(a , b.lower), max(a , b.upper)); }
139 template<typename T> __forceinline const BBox<T> merge( const BBox<T>& a, const BBox<T>& b ) { return BBox<T>(min(a.lower, b.lower), max(a.upper, b.upper)); }
140
141 /*! Merges three boxes. */
142 template<typename T> __forceinline const BBox<T> merge( const BBox<T>& a, const BBox<T>& b, const BBox<T>& c ) { return merge(a,merge(b,c)); }
143
144 /*! Merges four boxes. */
145 template<typename T> __forceinline BBox<T> merge(const BBox<T>& a, const BBox<T>& b, const BBox<T>& c, const BBox<T>& d) {
146 return merge(merge(a,b),merge(c,d));
147 }
148
149 /*! Comparison Operators */
150 template<typename T> __forceinline bool operator==( const BBox<T>& a, const BBox<T>& b ) { return a.lower == b.lower && a.upper == b.upper; }
151 template<typename T> __forceinline bool operator!=( const BBox<T>& a, const BBox<T>& b ) { return a.lower != b.lower || a.upper != b.upper; }
152
153 /*! scaling */
154 template<typename T> __forceinline BBox<T> operator *( const float& a, const BBox<T>& b ) { return BBox<T>(a*b.lower,a*b.upper); }
155 template<typename T> __forceinline BBox<T> operator *( const T& a, const BBox<T>& b ) { return BBox<T>(a*b.lower,a*b.upper); }
156
157 /*! translations */
158 template<typename T> __forceinline BBox<T> operator +( const BBox<T>& a, const BBox<T>& b ) { return BBox<T>(a.lower+b.lower,a.upper+b.upper); }
159 template<typename T> __forceinline BBox<T> operator -( const BBox<T>& a, const BBox<T>& b ) { return BBox<T>(a.lower-b.lower,a.upper-b.upper); }
160 template<typename T> __forceinline BBox<T> operator +( const BBox<T>& a, const T & b ) { return BBox<T>(a.lower+b ,a.upper+b ); }
161 template<typename T> __forceinline BBox<T> operator -( const BBox<T>& a, const T & b ) { return BBox<T>(a.lower-b ,a.upper-b ); }
162
163 /*! extension */
164 template<typename T> __forceinline BBox<T> enlarge(const BBox<T>& a, const T& b) { return BBox<T>(a.lower-b, a.upper+b); }
165
166 /*! intersect bounding boxes */
167 template<typename T> __forceinline const BBox<T> intersect( const BBox<T>& a, const BBox<T>& b ) { return BBox<T>(max(a.lower, b.lower), min(a.upper, b.upper)); }
168 template<typename T> __forceinline const BBox<T> intersect( const BBox<T>& a, const BBox<T>& b, const BBox<T>& c ) { return intersect(a,intersect(b,c)); }
169 template<typename T> __forceinline const BBox<T> intersect( const BBox<T>& a, const BBox<T>& b, const BBox<T>& c, const BBox<T>& d ) { return intersect(intersect(a,b),intersect(c,d)); }
170
171 /*! subtract bounds from each other */
172 template<typename T> __forceinline void subtract(const BBox<T>& a, const BBox<T>& b, BBox<T>& c, BBox<T>& d)
173 {
174 c.lower = a.lower;
175 c.upper = min(a.upper,b.lower);
176 d.lower = max(a.lower,b.upper);
177 d.upper = a.upper;
178 }
179
180 /*! tests if bounding boxes (and points) are disjoint (empty intersection) */
181 template<typename T> __inline bool disjoint( const BBox<T>& a, const BBox<T>& b ) { return intersect(a,b).empty(); }
182 template<typename T> __inline bool disjoint( const BBox<T>& a, const T& b ) { return disjoint(a,BBox<T>(b)); }
183 template<typename T> __inline bool disjoint( const T& a, const BBox<T>& b ) { return disjoint(BBox<T>(a),b); }
184
185 /*! tests if bounding boxes (and points) are conjoint (non-empty intersection) */
186 template<typename T> __inline bool conjoint( const BBox<T>& a, const BBox<T>& b ) { return !intersect(a,b).empty(); }
187 template<typename T> __inline bool conjoint( const BBox<T>& a, const T& b ) { return conjoint(a,BBox<T>(b)); }
188 template<typename T> __inline bool conjoint( const T& a, const BBox<T>& b ) { return conjoint(BBox<T>(a),b); }
189
190 /*! subset relation */
191 template<typename T> __inline bool subset( const BBox<T>& a, const BBox<T>& b )
192 {
193 for ( size_t i = 0; i < T::N; i++ ) if ( a.lower[i] < b.lower[i] ) return false;
194 for ( size_t i = 0; i < T::N; i++ ) if ( a.upper[i] > b.upper[i] ) return false;
195 return true;
196 }
197
198 template<> __inline bool subset( const BBox<Vec3fa>& a, const BBox<Vec3fa>& b ) {
199 return all(ge_mask(a.lower,b.lower)) && all(le_mask(a.upper,b.upper));
200 }
201
202 template<> __inline bool subset( const BBox<Vec3fx>& a, const BBox<Vec3fx>& b ) {
203 return all(ge_mask(a.lower,b.lower)) && all(le_mask(a.upper,b.upper));
204 }
205
206 /*! blending */
207 template<typename T>
208 __forceinline BBox<T> lerp(const BBox<T>& b0, const BBox<T>& b1, const float t) {
209 return BBox<T>(lerp(b0.lower,b1.lower,t),lerp(b0.upper,b1.upper,t));
210 }
211
212 /*! output operator */
213 template<typename T> __forceinline embree_ostream operator<<(embree_ostream cout, const BBox<T>& box) {
214 return cout << "[" << box.lower << "; " << box.upper << "]";
215 }
216
217 /*! default template instantiations */
218 typedef BBox<float> BBox1f;
219 typedef BBox<Vec2f> BBox2f;
220 typedef BBox<Vec2fa> BBox2fa;
221 typedef BBox<Vec3f> BBox3f;
222 typedef BBox<Vec3fa> BBox3fa;
223 typedef BBox<Vec3fx> BBox3fx;
224 typedef BBox<Vec3ff> BBox3ff;
225}
226
227////////////////////////////////////////////////////////////////////////////////
228/// SSE / AVX / MIC specializations
229////////////////////////////////////////////////////////////////////////////////
230
231#if defined (__SSE__) || defined(__ARM_NEON)
232#include "../simd/sse.h"
233#endif
234
235#if defined (__AVX__)
236#include "../simd/avx.h"
237#endif
238
239#if defined(__AVX512F__)
240#include "../simd/avx512.h"
241#endif
242
243namespace embree
244{
245 template<int N>
246 __forceinline BBox<Vec3<vfloat<N>>> transpose(const BBox3fa* bounds);
247
248 template<>
249 __forceinline BBox<Vec3<vfloat4>> transpose<4>(const BBox3fa* bounds)
250 {
251 BBox<Vec3<vfloat4>> dest;
252
253 transpose((vfloat4&)bounds[0].lower,
254 (vfloat4&)bounds[1].lower,
255 (vfloat4&)bounds[2].lower,
256 (vfloat4&)bounds[3].lower,
257 dest.lower.x,
258 dest.lower.y,
259 dest.lower.z);
260
261 transpose((vfloat4&)bounds[0].upper,
262 (vfloat4&)bounds[1].upper,
263 (vfloat4&)bounds[2].upper,
264 (vfloat4&)bounds[3].upper,
265 dest.upper.x,
266 dest.upper.y,
267 dest.upper.z);
268
269 return dest;
270 }
271
272#if defined(__AVX__)
273 template<>
274 __forceinline BBox<Vec3<vfloat8>> transpose<8>(const BBox3fa* bounds)
275 {
276 BBox<Vec3<vfloat8>> dest;
277
278 transpose((vfloat4&)bounds[0].lower,
279 (vfloat4&)bounds[1].lower,
280 (vfloat4&)bounds[2].lower,
281 (vfloat4&)bounds[3].lower,
282 (vfloat4&)bounds[4].lower,
283 (vfloat4&)bounds[5].lower,
284 (vfloat4&)bounds[6].lower,
285 (vfloat4&)bounds[7].lower,
286 dest.lower.x,
287 dest.lower.y,
288 dest.lower.z);
289
290 transpose((vfloat4&)bounds[0].upper,
291 (vfloat4&)bounds[1].upper,
292 (vfloat4&)bounds[2].upper,
293 (vfloat4&)bounds[3].upper,
294 (vfloat4&)bounds[4].upper,
295 (vfloat4&)bounds[5].upper,
296 (vfloat4&)bounds[6].upper,
297 (vfloat4&)bounds[7].upper,
298 dest.upper.x,
299 dest.upper.y,
300 dest.upper.z);
301
302 return dest;
303 }
304#endif
305
306 template<int N>
307 __forceinline BBox3fa merge(const BBox3fa* bounds);
308
309 template<>
310 __forceinline BBox3fa merge<4>(const BBox3fa* bounds)
311 {
312 const Vec3fa lower = min(min(bounds[0].lower,bounds[1].lower),
313 min(bounds[2].lower,bounds[3].lower));
314 const Vec3fa upper = max(max(bounds[0].upper,bounds[1].upper),
315 max(bounds[2].upper,bounds[3].upper));
316 return BBox3fa(lower,upper);
317 }
318
319#if defined(__AVX__)
320 template<>
321 __forceinline BBox3fa merge<8>(const BBox3fa* bounds)
322 {
323 const Vec3fa lower = min(min(min(bounds[0].lower,bounds[1].lower),min(bounds[2].lower,bounds[3].lower)),
324 min(min(bounds[4].lower,bounds[5].lower),min(bounds[6].lower,bounds[7].lower)));
325 const Vec3fa upper = max(max(max(bounds[0].upper,bounds[1].upper),max(bounds[2].upper,bounds[3].upper)),
326 max(max(bounds[4].upper,bounds[5].upper),max(bounds[6].upper,bounds[7].upper)));
327 return BBox3fa(lower,upper);
328 }
329#endif
330}
331
332