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 | |
9 | namespace 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 | |
243 | namespace 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 | |