| 1 | // Copyright 2009-2021 Intel Corporation | 
| 2 | // SPDX-License-Identifier: Apache-2.0 | 
| 3 |  | 
| 4 | #pragma once | 
| 5 |  | 
| 6 | #include "bvh_node_base.h" | 
| 7 |  | 
| 8 | namespace embree | 
| 9 | { | 
| 10 |   /*! BVHN AABBNode */ | 
| 11 |   template<typename NodeRef, int N> | 
| 12 |     struct AABBNode_t : public BaseNode_t<NodeRef, N> | 
| 13 |   { | 
| 14 |     using BaseNode_t<NodeRef,N>::children; | 
| 15 |      | 
| 16 |     struct Create | 
| 17 |     { | 
| 18 |       __forceinline NodeRef operator() (const FastAllocator::CachedAllocator& alloc, size_t numChildren = 0) const | 
| 19 |       { | 
| 20 |         AABBNode_t* node = (AABBNode_t*) alloc.malloc0(bytes: sizeof(AABBNode_t),align: NodeRef::byteNodeAlignment); node->clear(); | 
| 21 |         return NodeRef::encodeNode(node); | 
| 22 |       } | 
| 23 |     }; | 
| 24 |      | 
| 25 |     struct Set | 
| 26 |     { | 
| 27 |       __forceinline void operator() (NodeRef node, size_t i, NodeRef child, const BBox3fa& bounds) const { | 
| 28 |         node.getAABBNode()->setRef(i,child); | 
| 29 |         node.getAABBNode()->setBounds(i,bounds); | 
| 30 |       } | 
| 31 |     }; | 
| 32 |      | 
| 33 |     struct Create2 | 
| 34 |     { | 
| 35 |       template<typename BuildRecord> | 
| 36 |       __forceinline NodeRef operator() (BuildRecord* children, const size_t num, const FastAllocator::CachedAllocator& alloc) const | 
| 37 |       { | 
| 38 |         AABBNode_t* node = (AABBNode_t*) alloc.malloc0(bytes: sizeof(AABBNode_t), align: NodeRef::byteNodeAlignment); node->clear(); | 
| 39 |         for (size_t i=0; i<num; i++) node->setBounds(i,children[i].bounds()); | 
| 40 |         return NodeRef::encodeNode(node); | 
| 41 |       } | 
| 42 |     }; | 
| 43 |      | 
| 44 |     struct Set2 | 
| 45 |     { | 
| 46 |       template<typename BuildRecord> | 
| 47 |       __forceinline NodeRef operator() (const BuildRecord& precord, const BuildRecord* crecords, NodeRef ref, NodeRef* children, const size_t num) const | 
| 48 |       { | 
| 49 | #if defined(DEBUG) | 
| 50 |         // check that empty children are only at the end of the child list | 
| 51 |         bool emptyChild = false; | 
| 52 |         for (size_t i=0; i<num; i++) { | 
| 53 |           emptyChild |= (children[i] == NodeRef::emptyNode); | 
| 54 |           assert(emptyChild == (children[i] == NodeRef::emptyNode)); | 
| 55 |         } | 
| 56 | #endif | 
| 57 |         AABBNode_t* node = ref.getAABBNode(); | 
| 58 |         for (size_t i=0; i<num; i++) node->setRef(i,children[i]); | 
| 59 |         return ref; | 
| 60 |       } | 
| 61 |     }; | 
| 62 |      | 
| 63 |     struct Set3 | 
| 64 |     { | 
| 65 |       Set3 (FastAllocator* allocator, PrimRef* prims) | 
| 66 |       : allocator(allocator), prims(prims) {} | 
| 67 |        | 
| 68 |       template<typename BuildRecord> | 
| 69 |       __forceinline NodeRef operator() (const BuildRecord& precord, const BuildRecord* crecords, NodeRef ref, NodeRef* children, const size_t num) const | 
| 70 |       { | 
| 71 | #if defined(DEBUG) | 
| 72 |         // check that empty children are only at the end of the child list | 
| 73 |         bool emptyChild = false; | 
| 74 |         for (size_t i=0; i<num; i++) { | 
| 75 |           emptyChild |= (children[i] == NodeRef::emptyNode); | 
| 76 |           assert(emptyChild == (children[i] == NodeRef::emptyNode)); | 
| 77 |         } | 
| 78 | #endif | 
| 79 |         AABBNode_t* node = ref.getAABBNode(); | 
| 80 |         for (size_t i=0; i<num; i++) node->setRef(i,children[i]); | 
| 81 |          | 
| 82 |         if (unlikely(precord.alloc_barrier)) | 
| 83 |         { | 
| 84 |           PrimRef* begin = &prims[precord.prims.begin()]; | 
| 85 |           PrimRef* end   = &prims[precord.prims.end()]; // FIXME: extended end for spatial split builder!!!!! | 
| 86 |           size_t bytes = (size_t)end - (size_t)begin; | 
| 87 |           allocator->addBlock(ptr: begin,bytes); | 
| 88 |         } | 
| 89 |          | 
| 90 |         return ref; | 
| 91 |       } | 
| 92 |        | 
| 93 |       FastAllocator* const allocator; | 
| 94 |       PrimRef* const prims; | 
| 95 |     }; | 
| 96 |      | 
| 97 |     /*! Clears the node. */ | 
| 98 |     __forceinline void clear() { | 
| 99 |       lower_x = lower_y = lower_z = pos_inf; | 
| 100 |       upper_x = upper_y = upper_z = neg_inf; | 
| 101 |       BaseNode_t<NodeRef,N>::clear(); | 
| 102 |     } | 
| 103 |      | 
| 104 |     /*! Sets bounding box and ID of child. */ | 
| 105 |     __forceinline void setRef(size_t i, const NodeRef& ref) { | 
| 106 |       assert(i < N); | 
| 107 |       children[i] = ref; | 
| 108 |     } | 
| 109 |      | 
| 110 |     /*! Sets bounding box of child. */ | 
| 111 |     __forceinline void setBounds(size_t i, const BBox3fa& bounds) | 
| 112 |     { | 
| 113 |       assert(i < N); | 
| 114 |       lower_x[i] = bounds.lower.x; lower_y[i] = bounds.lower.y; lower_z[i] = bounds.lower.z; | 
| 115 |       upper_x[i] = bounds.upper.x; upper_y[i] = bounds.upper.y; upper_z[i] = bounds.upper.z; | 
| 116 |     } | 
| 117 |      | 
| 118 |     /*! Sets bounding box and ID of child. */ | 
| 119 |     __forceinline void set(size_t i, const NodeRef& ref, const BBox3fa& bounds) { | 
| 120 |       setBounds(i,bounds); | 
| 121 |       children[i] = ref; | 
| 122 |     } | 
| 123 |      | 
| 124 |     /*! Returns bounds of node. */ | 
| 125 |     __forceinline BBox3fa bounds() const { | 
| 126 |       const Vec3fa lower(reduce_min(lower_x),reduce_min(lower_y),reduce_min(lower_z)); | 
| 127 |       const Vec3fa upper(reduce_max(upper_x),reduce_max(upper_y),reduce_max(upper_z)); | 
| 128 |       return BBox3fa(lower,upper); | 
| 129 |     } | 
| 130 |      | 
| 131 |     /*! Returns bounds of specified child. */ | 
| 132 |     __forceinline BBox3fa bounds(size_t i) const | 
| 133 |     { | 
| 134 |       assert(i < N); | 
| 135 |       const Vec3fa lower(lower_x[i],lower_y[i],lower_z[i]); | 
| 136 |       const Vec3fa upper(upper_x[i],upper_y[i],upper_z[i]); | 
| 137 |       return BBox3fa(lower,upper); | 
| 138 |     } | 
| 139 |      | 
| 140 |     /*! Returns extent of bounds of specified child. */ | 
| 141 |     __forceinline Vec3fa extend(size_t i) const { | 
| 142 |       return bounds(i).size(); | 
| 143 |     } | 
| 144 |      | 
| 145 |     /*! Returns bounds of all children (implemented later as specializations) */ | 
| 146 |     __forceinline void bounds(BBox<vfloat4>& bounds0, BBox<vfloat4>& bounds1, BBox<vfloat4>& bounds2, BBox<vfloat4>& bounds3) const; | 
| 147 |      | 
| 148 |     /*! swap two children of the node */ | 
| 149 |     __forceinline void swap(size_t i, size_t j) | 
| 150 |     { | 
| 151 |       assert(i<N && j<N); | 
| 152 |       std::swap(children[i],children[j]); | 
| 153 |       std::swap(lower_x[i],lower_x[j]); | 
| 154 |       std::swap(lower_y[i],lower_y[j]); | 
| 155 |       std::swap(lower_z[i],lower_z[j]); | 
| 156 |       std::swap(upper_x[i],upper_x[j]); | 
| 157 |       std::swap(upper_y[i],upper_y[j]); | 
| 158 |       std::swap(upper_z[i],upper_z[j]); | 
| 159 |     } | 
| 160 |  | 
| 161 |     /*! swap the children of two nodes */ | 
| 162 |     __forceinline static void swap(AABBNode_t* a, size_t i, AABBNode_t* b, size_t j) | 
| 163 |     { | 
| 164 |       assert(i<N && j<N); | 
| 165 |       std::swap(a->children[i],b->children[j]); | 
| 166 |       std::swap(a->lower_x[i],b->lower_x[j]); | 
| 167 |       std::swap(a->lower_y[i],b->lower_y[j]); | 
| 168 |       std::swap(a->lower_z[i],b->lower_z[j]); | 
| 169 |       std::swap(a->upper_x[i],b->upper_x[j]); | 
| 170 |       std::swap(a->upper_y[i],b->upper_y[j]); | 
| 171 |       std::swap(a->upper_z[i],b->upper_z[j]); | 
| 172 |     } | 
| 173 |  | 
| 174 |     /*! compacts a node (moves empty children to the end) */ | 
| 175 |     __forceinline static void compact(AABBNode_t* a) | 
| 176 |     { | 
| 177 |       /* find right most filled node */ | 
| 178 |       ssize_t j=N; | 
| 179 |       for (j=j-1; j>=0; j--) | 
| 180 |         if (a->child(j) != NodeRef::emptyNode) | 
| 181 |           break; | 
| 182 |  | 
| 183 |       /* replace empty nodes with filled nodes */ | 
| 184 |       for (ssize_t i=0; i<j; i++) { | 
| 185 |         if (a->child(i) == NodeRef::emptyNode) { | 
| 186 |           a->swap(i,j); | 
| 187 |           for (j=j-1; j>i; j--) | 
| 188 |             if (a->child(j) != NodeRef::emptyNode) | 
| 189 |               break; | 
| 190 |         } | 
| 191 |       } | 
| 192 |     } | 
| 193 |      | 
| 194 |     /*! Returns reference to specified child */ | 
| 195 |     __forceinline       NodeRef& child(size_t i)       { assert(i<N); return children[i]; } | 
| 196 |     __forceinline const NodeRef& child(size_t i) const { assert(i<N); return children[i]; } | 
| 197 |      | 
| 198 |     /*! output operator */ | 
| 199 |     friend embree_ostream operator<<(embree_ostream o, const AABBNode_t& n) | 
| 200 |     { | 
| 201 |       o << "AABBNode { "  << embree_endl; | 
| 202 |       o << "  lower_x "  << n.lower_x << embree_endl; | 
| 203 |       o << "  upper_x "  << n.upper_x << embree_endl; | 
| 204 |       o << "  lower_y "  << n.lower_y << embree_endl; | 
| 205 |       o << "  upper_y "  << n.upper_y << embree_endl; | 
| 206 |       o << "  lower_z "  << n.lower_z << embree_endl; | 
| 207 |       o << "  upper_z "  << n.upper_z << embree_endl; | 
| 208 |       o << "  children = " ; | 
| 209 |       for (size_t i=0; i<N; i++) o << n.children[i] << " " ; | 
| 210 |       o << embree_endl; | 
| 211 |       o << "}"  << embree_endl; | 
| 212 |       return o; | 
| 213 |     } | 
| 214 |      | 
| 215 |   public: | 
| 216 |     vfloat<N> lower_x;           //!< X dimension of lower bounds of all N children. | 
| 217 |     vfloat<N> upper_x;           //!< X dimension of upper bounds of all N children. | 
| 218 |     vfloat<N> lower_y;           //!< Y dimension of lower bounds of all N children. | 
| 219 |     vfloat<N> upper_y;           //!< Y dimension of upper bounds of all N children. | 
| 220 |     vfloat<N> lower_z;           //!< Z dimension of lower bounds of all N children. | 
| 221 |     vfloat<N> upper_z;           //!< Z dimension of upper bounds of all N children. | 
| 222 |   }; | 
| 223 |  | 
| 224 |   template<> | 
| 225 |     __forceinline void AABBNode_t<NodeRefPtr<4>,4>::bounds(BBox<vfloat4>& bounds0, BBox<vfloat4>& bounds1, BBox<vfloat4>& bounds2, BBox<vfloat4>& bounds3) const { | 
| 226 |     transpose(r0: lower_x,r1: lower_y,r2: lower_z,r3: vfloat4(zero),c0&: bounds0.lower,c1&: bounds1.lower,c2&: bounds2.lower,c3&: bounds3.lower); | 
| 227 |     transpose(r0: upper_x,r1: upper_y,r2: upper_z,r3: vfloat4(zero),c0&: bounds0.upper,c1&: bounds1.upper,c2&: bounds2.upper,c3&: bounds3.upper); | 
| 228 |   } | 
| 229 | } | 
| 230 |  |