| 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__) | 
| 81 |   template<> __forceinline bool BBox<Vec3fa>::empty() const { | 
| 82 |     return !all(b: le_mask(a: lower,b: upper)); | 
| 83 |   } | 
| 84 |   template<> __forceinline bool BBox<Vec3fx>::empty() const { | 
| 85 |     return !all(b: le_mask(a: lower,b: upper)); | 
| 86 |   } | 
| 87 | #endif | 
| 88 |  | 
| 89 |   /*! tests if box is finite */ | 
| 90 |   __forceinline bool isvalid( const BBox<Vec3fa>& v ) { | 
| 91 |     return all(b: gt_mask(a: v.lower,b: Vec3fa_t(-FLT_LARGE)) & lt_mask(a: v.upper,b: 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(b: gt_mask(a: v.lower,b: Vec3fa_t(-FLT_LARGE)) & lt_mask(a: v.upper,b: Vec3fa_t(+FLT_LARGE)) & le_mask(a: v.lower,b: v.upper)); | 
| 97 |   } | 
| 98 |    | 
| 99 |   /*! tests if box has finite entries */ | 
| 100 |   __forceinline bool is_finite( const BBox<Vec3fa>& b) { | 
| 101 |     return is_finite(a: b.lower) && is_finite(a: b.upper); | 
| 102 |   } | 
| 103 |  | 
| 104 |   /*! test if point contained in box */ | 
| 105 |   __forceinline bool inside ( const BBox<Vec3fa>& b, const Vec3fa& p ) { return all(b: ge_mask(a: p,b: b.lower) & le_mask(a: p,b: 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(v: 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(a: 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(d: 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(d: 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(b: ge_mask(a: a.lower,b: b.lower)) && all(b: le_mask(a: a.upper,b: b.upper)); | 
| 200 |   } | 
| 201 |  | 
| 202 |   template<> __inline bool subset( const BBox<Vec3fx>& a, const BBox<Vec3fx>& b ) { | 
| 203 |     return all(b: ge_mask(a: a.lower,b: b.lower)) && all(b: le_mask(a: a.upper,b: 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__ | 
| 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(r0: (vfloat4&)bounds[0].lower, | 
| 254 |               r1: (vfloat4&)bounds[1].lower, | 
| 255 |               r2: (vfloat4&)bounds[2].lower, | 
| 256 |               r3: (vfloat4&)bounds[3].lower, | 
| 257 |               c0&: dest.lower.x, | 
| 258 |               c1&: dest.lower.y, | 
| 259 |               c2&: dest.lower.z); | 
| 260 |      | 
| 261 |     transpose(r0: (vfloat4&)bounds[0].upper, | 
| 262 |               r1: (vfloat4&)bounds[1].upper, | 
| 263 |               r2: (vfloat4&)bounds[2].upper, | 
| 264 |               r3: (vfloat4&)bounds[3].upper, | 
| 265 |               c0&: dest.upper.x, | 
| 266 |               c1&: dest.upper.y, | 
| 267 |               c2&: 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(a: min(a: bounds[0].lower,b: bounds[1].lower), | 
| 313 |                              b: min(a: bounds[2].lower,b: bounds[3].lower)); | 
| 314 |     const Vec3fa upper = max(a: max(a: bounds[0].upper,b: bounds[1].upper), | 
| 315 |                              b: max(a: bounds[2].upper,b: 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 |  |