34 #ifndef __HDK_UT_BVHImpl_h__
35 #define __HDK_UT_BVHImpl_h__
47 namespace HDK_Sample {
51 template<
typename T,u
int NAXES>
55 for (
uint axis = 1; axis < NAXES; ++axis)
60 return has_nan_or_inf;
64 const int32 *pboxints =
reinterpret_cast<const int32*
>(&box);
66 bool has_nan_or_inf = ((pboxints[0] & 0x7F800000) == 0x7F800000);
67 has_nan_or_inf |= ((pboxints[1] & 0x7F800000) == 0x7F800000);
68 for (
uint axis = 1; axis < NAXES; ++axis)
70 has_nan_or_inf |= ((pboxints[2*axis] & 0x7F800000) == 0x7F800000);
71 has_nan_or_inf |= ((pboxints[2*axis + 1] & 0x7F800000) == 0x7F800000);
73 return has_nan_or_inf;
75 template<
typename T,u
int NAXES>
77 const T*
v = box.vals[axis];
84 template<
typename T,u
int NAXES>
87 for (
uint axis = 1; axis < NAXES; ++axis)
89 return has_nan_or_inf;
95 bool has_nan_or_inf = ((ppositionints[0] & 0x7F800000) == 0x7F800000);
96 for (
uint axis = 1; axis < NAXES; ++axis)
97 has_nan_or_inf |= ((ppositionints[axis] & 0x7F800000) == 0x7F800000);
98 return has_nan_or_inf;
100 template<
typename T,u
int NAXES>
104 template<
typename T,u
int NAXES>
124 bool has_nan_or_inf = ((ppositionints[0] & 0x7F800000) == 0x7F800000);
125 has_nan_or_inf |= ((ppositionints[1] & 0x7F800000) == 0x7F800000);
126 return has_nan_or_inf;
132 bool has_nan_or_inf = ((ppositionints[0] & 0x7F800000) == 0x7F800000);
133 has_nan_or_inf |= ((ppositionints[1] & 0x7F800000) == 0x7F800000);
134 has_nan_or_inf |= ((ppositionints[2] & 0x7F800000) == 0x7F800000);
135 return has_nan_or_inf;
141 bool has_nan_or_inf = ((ppositionints[0] & 0x7F800000) == 0x7F800000);
142 has_nan_or_inf |= ((ppositionints[1] & 0x7F800000) == 0x7F800000);
143 has_nan_or_inf |= ((ppositionints[2] & 0x7F800000) == 0x7F800000);
144 has_nan_or_inf |= ((ppositionints[3] & 0x7F800000) == 0x7F800000);
145 return has_nan_or_inf;
172 template<
typename BOX_TYPE,
typename SRC_INT_TYPE,
typename INT_TYPE>
175 constexpr INT_TYPE PARALLEL_THRESHOLD = 65536;
177 if (nboxes >= PARALLEL_THRESHOLD)
180 ntasks = (nprocessors > 1) ?
SYSmin(4*nprocessors, nboxes/(PARALLEL_THRESHOLD/2)) : 1;
186 const SRC_INT_TYPE* indices_end =
indices + nboxes;
189 SRC_INT_TYPE* psrc_index =
indices;
190 for (; psrc_index != indices_end; ++psrc_index)
196 if (psrc_index == indices_end)
200 SRC_INT_TYPE* nan_start = psrc_index;
201 for (++psrc_index; psrc_index != indices_end; ++psrc_index)
206 *nan_start = *psrc_index;
211 return indices_end - nan_start;
224 for (INT_TYPE taski = r.begin(), task_end = r.end(); taski < task_end; ++taski)
226 SRC_INT_TYPE* indices_start =
indices + (taski*
exint(nboxes))/ntasks;
227 const SRC_INT_TYPE* indices_end =
indices + ((taski+1)*
exint(nboxes))/ntasks;
228 SRC_INT_TYPE* psrc_index = indices_start;
229 for (; psrc_index != indices_end; ++psrc_index)
235 if (psrc_index == indices_end)
237 nexcluded[taski] = 0;
242 SRC_INT_TYPE* nan_start = psrc_index;
243 for (++psrc_index; psrc_index != indices_end; ++psrc_index)
248 *nan_start = *psrc_index;
252 nexcluded[taski] = indices_end - nan_start;
257 INT_TYPE total_excluded = nexcluded[0];
258 for (INT_TYPE taski = 1; taski < ntasks; ++taski)
260 total_excluded += nexcluded[taski];
263 if (total_excluded == 0)
269 while (nexcluded[taski] == 0)
274 SRC_INT_TYPE* dest_indices =
indices + ((taski+1)*
exint(nboxes))/ntasks - nexcluded[taski];
276 SRC_INT_TYPE* dest_end =
indices + nboxes - total_excluded;
277 for (++taski; taski < ntasks && dest_indices < dest_end; ++taski)
279 const SRC_INT_TYPE* psrc_index =
indices + (taski*
exint(nboxes))/ntasks;
280 const SRC_INT_TYPE* psrc_end =
indices + ((taski+1)*
exint(nboxes))/ntasks - nexcluded[taski];
281 INT_TYPE
count = psrc_end - psrc_index;
283 memmove(dest_indices, psrc_index,
sizeof(SRC_INT_TYPE)*count);
284 dest_indices += count;
286 nboxes -= total_excluded;
287 return total_excluded;
291 template<BVH_Heuristic H,
typename T,u
int NAXES,
typename BOX_TYPE,
typename SRC_INT_TYPE>
294 computeFullBoundingBox(axes_minmax, boxes, nboxes,
indices);
296 init<H>(axes_minmax, boxes, nboxes,
indices, reorder_indices, max_items_per_leaf);
300 template<BVH_Heuristic H,
typename T,u
int NAXES,
typename BOX_TYPE,
typename SRC_INT_TYPE>
314 createTrivialIndices(
indices, nboxes);
320 if (nexcluded != 0) {
325 computeFullBoundingBox(axes_minmax, boxes, nboxes,
indices);
333 initNodeReorder<H>(nodes, nodes[0], axes_minmax, boxes,
indices, nboxes, 0, max_items_per_leaf);
335 initNode<H>(nodes, nodes[0], axes_minmax, boxes,
indices, nboxes);
338 if (8*nodes.capacity() > 9*nodes.size()) {
339 nodes.setCapacity(nodes.size());
342 myRoot.reset(nodes.array());
344 nodes.unsafeClearData();
348 template<
typename LOCAL_DATA,
typename FUNCTORS>
351 LOCAL_DATA* data_for_parent)
const noexcept
357 traverseHelper(0,
INT_TYPE(-1), functors, data_for_parent);
360 template<
typename LOCAL_DATA,
typename FUNCTORS>
363 INT_TYPE parent_nodei,
365 LOCAL_DATA* data_for_parent)
const noexcept
368 bool descend = functors.pre(nodei, data_for_parent);
371 LOCAL_DATA local_data[
N];
373 for (s = 0; s <
N; ++
s) {
374 const INT_TYPE node_int = node.child[
s];
375 if (Node::isInternal(node_int)) {
376 if (node_int == Node::EMPTY) {
380 traverseHelper(Node::getInternalNum(node_int), nodei, functors, &local_data[s]);
383 functors.item(node_int, nodei, local_data[s]);
387 functors.post(nodei, parent_nodei, data_for_parent, s, local_data);
391 template<
typename LOCAL_DATA,
typename FUNCTORS>
395 LOCAL_DATA* data_for_parent)
const noexcept
401 traverseParallelHelper(0,
INT_TYPE(-1), parallel_threshold,
myNumNodes, functors, data_for_parent);
404 template<
typename LOCAL_DATA,
typename FUNCTORS>
407 INT_TYPE parent_nodei,
408 INT_TYPE parallel_threshold,
409 INT_TYPE next_node_id,
411 LOCAL_DATA* data_for_parent)
const noexcept
414 bool descend = functors.pre(nodei, data_for_parent);
420 INT_TYPE next_nodes[
N];
422 INT_TYPE nchildren =
N;
423 INT_TYPE nparallel = 0;
428 const INT_TYPE node_int = node.child[
s];
429 if (node_int == Node::EMPTY) {
433 next_nodes[
s] = next_node_id;
434 if (Node::isInternal(node_int)) {
437 INT_TYPE child_node_id = Node::getInternalNum(node_int);
438 nnodes[
s] = next_node_id - child_node_id;
439 next_node_id = child_node_id;
444 nparallel += (nnodes[
s] >= parallel_threshold);
447 LOCAL_DATA local_data[
N];
448 if (nparallel >= 2) {
450 if (nparallel < nchildren) {
451 for (INT_TYPE s = 0; s <
N; ++
s) {
452 if (nnodes[s] >= parallel_threshold) {
455 const INT_TYPE node_int = node.child[
s];
456 if (Node::isInternal(node_int)) {
457 if (node_int == Node::EMPTY) {
461 traverseHelper(Node::getInternalNum(node_int), nodei, functors, &local_data[s]);
464 functors.item(node_int, nodei, local_data[s]);
470 for (INT_TYPE taski = r.begin(); taski < r.end(); ++taski) {
471 INT_TYPE parallel_count = 0;
475 for (s = 0; s <
N; ++
s) {
476 if (nnodes[s] < parallel_threshold) {
479 if (parallel_count == taski) {
484 const INT_TYPE node_int = node.child[
s];
485 if (Node::isInternal(node_int)) {
486 UT_ASSERT_MSG_P(node_int != Node::EMPTY,
"Empty entries should have been excluded above.");
487 traverseParallelHelper(Node::getInternalNum(node_int), nodei, parallel_threshold, next_nodes[s], functors, &local_data[s]);
490 functors.item(node_int, nodei, local_data[s]);
497 for (INT_TYPE s = 0; s <
N; ++
s) {
498 const INT_TYPE node_int = node.child[
s];
499 if (Node::isInternal(node_int)) {
500 if (node_int == Node::EMPTY) {
504 traverseHelper(Node::getInternalNum(node_int), nodei, functors, &local_data[s]);
507 functors.item(node_int, nodei, local_data[s]);
511 functors.post(nodei, parent_nodei, data_for_parent, nchildren, local_data);
515 template<
typename LOCAL_DATA,
typename FUNCTORS>
518 LOCAL_DATA* data_for_parent)
const noexcept
524 traverseVectorHelper(0,
INT_TYPE(-1), functors, data_for_parent);
527 template<
typename LOCAL_DATA,
typename FUNCTORS>
530 INT_TYPE parent_nodei,
532 LOCAL_DATA* data_for_parent)
const noexcept
535 INT_TYPE descend = functors.pre(nodei, data_for_parent);
538 LOCAL_DATA local_data[
N];
540 for (s = 0; s <
N; ++
s) {
541 if ((descend>>s) & 1) {
542 const INT_TYPE node_int = node.child[
s];
543 if (Node::isInternal(node_int)) {
544 if (node_int == Node::EMPTY) {
546 descend &= (INT_TYPE(1)<<
s)-1;
549 traverseVectorHelper(Node::getInternalNum(node_int), nodei, functors, &local_data[s]);
552 functors.item(node_int, nodei, local_data[s]);
557 functors.post(nodei, parent_nodei, data_for_parent, s, local_data, descend);
561 template<
typename SRC_INT_TYPE>
563 constexpr
INT_TYPE PARALLEL_THRESHOLD = 65536;
565 if (
n >= PARALLEL_THRESHOLD) {
567 ntasks = (nprocessors > 1) ?
SYSmin(4*nprocessors,
n/(PARALLEL_THRESHOLD/2)) : 1;
576 for (
INT_TYPE taski = r.begin(), taskend = r.end(); taski != taskend; ++taski) {
588 template<
typename T,u
int NAXES,
typename BOX_TYPE,
typename SRC_INT_TYPE>
591 axes_minmax.initBounds();
595 if (nboxes >= 2*4096) {
597 ntasks = (nprocessors > 1) ?
SYSmin(4*nprocessors, nboxes/4096) : 1;
602 box.initBounds(boxes[
indices[0]]);
603 for (INT_TYPE i = 1; i < nboxes; ++i) {
604 box.combine(boxes[indices[i]]);
608 box.initBounds(boxes[0]);
609 for (INT_TYPE i = 1; i < nboxes; ++i) {
610 box.combine(boxes[i]);
618 parallel_boxes.
setSize(ntasks);
620 for (INT_TYPE taski = r.begin(),
end = r.end(); taski <
end; ++taski) {
621 const INT_TYPE startbox = (taski*
uint64(nboxes))/ntasks;
622 const INT_TYPE endbox = ((taski+1)*
uint64(nboxes))/ntasks;
625 box.initBounds(boxes[indices[startbox]]);
626 for (INT_TYPE i = startbox+1; i < endbox; ++i) {
627 box.combine(boxes[indices[i]]);
631 box.initBounds(boxes[startbox]);
632 for (INT_TYPE i = startbox+1; i < endbox; ++i) {
633 box.combine(boxes[i]);
636 parallel_boxes[taski] = box;
642 for (INT_TYPE i = 1; i < ntasks; ++i) {
643 box.combine(parallel_boxes[i]);
651 template<BVH_Heuristic H,
typename T,u
int NAXES,
typename BOX_TYPE,
typename SRC_INT_TYPE>
652 void BVH<N>::initNode(
UT_Array<Node>& nodes,
Node &node,
const Box<T,NAXES>& axes_minmax,
const BOX_TYPE* boxes, SRC_INT_TYPE* indices, INT_TYPE nboxes) noexcept {
655 for (INT_TYPE i = 0; i < nboxes; ++i) {
656 node.child[i] = indices[i];
658 for (INT_TYPE i = nboxes; i <
N; ++i) {
659 node.child[i] = Node::EMPTY;
664 SRC_INT_TYPE* sub_indices[N+1];
669 sub_indices[2] = indices+nboxes;
670 split<H>(axes_minmax, boxes,
indices, nboxes, sub_indices[1], &sub_boxes[0]);
673 multiSplit<H>(axes_minmax, boxes,
indices, nboxes, sub_indices, sub_boxes);
677 INT_TYPE nparallel = 0;
678 static constexpr INT_TYPE PARALLEL_THRESHOLD = 1024;
679 for (INT_TYPE i = 0; i <
N; ++i) {
680 INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i];
681 if (sub_nboxes == 1) {
682 node.child[i] = sub_indices[i][0];
684 else if (sub_nboxes >= PARALLEL_THRESHOLD) {
695 if (nparallel >= 2) {
701 parallel_nodes.
setSize(nparallel);
703 parallel_parent_nodes.
setSize(nparallel);
705 for (INT_TYPE taski = r.begin(), end = r.end(); taski <
end; ++taski) {
707 INT_TYPE counted_parallel = 0;
710 for (childi = 0; childi <
N; ++childi) {
711 sub_nboxes = sub_indices[childi+1]-sub_indices[childi];
712 if (sub_nboxes >= PARALLEL_THRESHOLD) {
713 if (counted_parallel == taski) {
728 Node& parent_node = parallel_parent_nodes[taski];
731 initNode<H>(local_nodes, parent_node, sub_boxes[childi], boxes, sub_indices[childi], sub_nboxes);
735 INT_TYPE counted_parallel = 0;
736 for (INT_TYPE i = 0; i <
N; ++i) {
737 INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i];
738 if (sub_nboxes != 1) {
739 INT_TYPE local_nodes_start = nodes.size();
740 node.child[i] = Node::markInternal(local_nodes_start);
741 if (sub_nboxes >= PARALLEL_THRESHOLD) {
743 Node child_node = parallel_parent_nodes[counted_parallel];
745 for (INT_TYPE childi = 0; childi <
N; ++childi) {
746 INT_TYPE child_child = child_node.child[childi];
747 if (Node::isInternal(child_child) && child_child != Node::EMPTY) {
748 child_child += local_nodes_start;
749 child_node.child[childi] = child_child;
754 const UT_Array<Node>& local_nodes = parallel_nodes[counted_parallel];
756 INT_TYPE
n = local_nodes.
size();
757 nodes.bumpCapacity(local_nodes_start + n);
758 nodes.setSizeNoInit(local_nodes_start + n);
759 nodes[local_nodes_start-1] = child_node;
762 nodes.bumpCapacity(local_nodes_start + 1);
763 nodes.setSizeNoInit(local_nodes_start + 1);
764 initNode<H>(nodes, nodes[local_nodes_start], sub_boxes[i], boxes, sub_indices[i], sub_nboxes);
770 adjustParallelChildNodes<PARALLEL_THRESHOLD>(nparallel, nodes, node, parallel_nodes.
array(), sub_indices);
773 for (INT_TYPE i = 0; i <
N; ++i) {
774 INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i];
775 if (sub_nboxes != 1) {
776 INT_TYPE local_nodes_start = nodes.size();
777 node.child[i] = Node::markInternal(local_nodes_start);
778 nodes.bumpCapacity(local_nodes_start + 1);
779 nodes.setSizeNoInit(local_nodes_start + 1);
780 initNode<H>(nodes, nodes[local_nodes_start], sub_boxes[i], boxes, sub_indices[i], sub_nboxes);
787 template<BVH_Heuristic H,
typename T,u
int NAXES,
typename BOX_TYPE,
typename SRC_INT_TYPE>
788 void BVH<N>::initNodeReorder(
UT_Array<Node>& nodes,
Node &node,
const Box<T,NAXES>& axes_minmax,
const BOX_TYPE* boxes, SRC_INT_TYPE* indices, INT_TYPE nboxes,
const INT_TYPE indices_offset,
const INT_TYPE max_items_per_leaf) noexcept {
791 for (INT_TYPE i = 0; i < nboxes; ++i) {
792 node.child[i] = indices_offset+i;
794 for (INT_TYPE i = nboxes; i <
N; ++i) {
795 node.child[i] = Node::EMPTY;
800 SRC_INT_TYPE* sub_indices[N+1];
805 sub_indices[2] = indices+nboxes;
806 split<H>(axes_minmax, boxes,
indices, nboxes, sub_indices[1], &sub_boxes[0]);
809 multiSplit<H>(axes_minmax, boxes,
indices, nboxes, sub_indices, sub_boxes);
814 INT_TYPE nleaves = 0;
816 SRC_INT_TYPE leaf_sizes[
N];
817 INT_TYPE sub_nboxes0 = sub_indices[1]-sub_indices[0];
818 if (sub_nboxes0 <= max_items_per_leaf) {
819 leaf_sizes[0] = sub_nboxes0;
820 for (
int j = 0;
j < sub_nboxes0; ++
j)
821 leaf_indices.
append(sub_indices[0][
j]);
824 INT_TYPE sub_nboxes1 = sub_indices[2]-sub_indices[1];
825 if (sub_nboxes1 <= max_items_per_leaf) {
826 leaf_sizes[nleaves] = sub_nboxes1;
827 for (
int j = 0;
j < sub_nboxes1; ++
j)
828 leaf_indices.
append(sub_indices[1][
j]);
831 for (INT_TYPE i = 2; i <
N; ++i) {
832 INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i];
833 if (sub_nboxes <= max_items_per_leaf) {
834 leaf_sizes[nleaves] = sub_nboxes;
835 for (
int j = 0;
j < sub_nboxes; ++
j)
836 leaf_indices.
append(sub_indices[i][
j]);
843 INT_TYPE move_distance = 0;
844 INT_TYPE index_move_distance = 0;
846 INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i];
847 if (sub_nboxes <= max_items_per_leaf) {
849 index_move_distance += sub_nboxes;
851 else if (move_distance > 0) {
852 SRC_INT_TYPE *start_src_index = sub_indices[i];
853 for (SRC_INT_TYPE *src_index = sub_indices[i+1]-1; src_index >= start_src_index; --src_index) {
854 src_index[index_move_distance] = src_index[0];
856 sub_indices[i+move_distance] = sub_indices[i]+index_move_distance;
859 index_move_distance = 0;
860 for (INT_TYPE i = 0; i < nleaves; ++i) {
861 INT_TYPE sub_nboxes = leaf_sizes[i];
862 sub_indices[i] = indices+index_move_distance;
863 for (
int j = 0;
j < sub_nboxes; ++
j)
864 indices[index_move_distance+
j] = leaf_indices[index_move_distance+
j];
865 index_move_distance += sub_nboxes;
870 INT_TYPE nparallel = 0;
871 static constexpr INT_TYPE PARALLEL_THRESHOLD = 1024;
872 for (INT_TYPE i = 0; i <
N; ++i) {
873 INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i];
874 if (sub_nboxes <= max_items_per_leaf) {
875 node.child[i] = indices_offset+(sub_indices[i]-sub_indices[0]);
877 else if (sub_nboxes >= PARALLEL_THRESHOLD) {
888 if (nparallel >= 2) {
894 parallel_nodes.
setSize(nparallel);
896 parallel_parent_nodes.
setSize(nparallel);
898 for (INT_TYPE taski = r.begin(), end = r.end(); taski <
end; ++taski) {
900 INT_TYPE counted_parallel = 0;
903 for (childi = 0; childi <
N; ++childi) {
904 sub_nboxes = sub_indices[childi+1]-sub_indices[childi];
905 if (sub_nboxes >= PARALLEL_THRESHOLD) {
906 if (counted_parallel == taski) {
921 Node& parent_node = parallel_parent_nodes[taski];
924 initNodeReorder<H>(local_nodes, parent_node, sub_boxes[childi], boxes, sub_indices[childi], sub_nboxes,
925 indices_offset+(sub_indices[childi]-sub_indices[0]), max_items_per_leaf);
929 INT_TYPE counted_parallel = 0;
930 for (INT_TYPE i = 0; i <
N; ++i) {
931 INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i];
932 if (sub_nboxes > max_items_per_leaf) {
933 INT_TYPE local_nodes_start = nodes.size();
934 node.child[i] = Node::markInternal(local_nodes_start);
935 if (sub_nboxes >= PARALLEL_THRESHOLD) {
937 Node child_node = parallel_parent_nodes[counted_parallel];
939 for (INT_TYPE childi = 0; childi <
N; ++childi) {
940 INT_TYPE child_child = child_node.child[childi];
941 if (Node::isInternal(child_child) && child_child != Node::EMPTY) {
942 child_child += local_nodes_start;
943 child_node.child[childi] = child_child;
948 const UT_Array<Node>& local_nodes = parallel_nodes[counted_parallel];
950 INT_TYPE n = local_nodes.
size();
951 nodes.bumpCapacity(local_nodes_start + n);
952 nodes.setSizeNoInit(local_nodes_start + n);
953 nodes[local_nodes_start-1] = child_node;
956 nodes.bumpCapacity(local_nodes_start + 1);
957 nodes.setSizeNoInit(local_nodes_start + 1);
958 initNodeReorder<H>(nodes, nodes[local_nodes_start], sub_boxes[i], boxes, sub_indices[i], sub_nboxes,
959 indices_offset+(sub_indices[i]-sub_indices[0]), max_items_per_leaf);
965 adjustParallelChildNodes<PARALLEL_THRESHOLD>(nparallel, nodes, node, parallel_nodes.
array(), sub_indices);
968 for (INT_TYPE i = 0; i <
N; ++i) {
969 INT_TYPE sub_nboxes = sub_indices[i+1]-sub_indices[i];
970 if (sub_nboxes > max_items_per_leaf) {
971 INT_TYPE local_nodes_start = nodes.size();
972 node.child[i] = Node::markInternal(local_nodes_start);
973 nodes.bumpCapacity(local_nodes_start + 1);
974 nodes.setSizeNoInit(local_nodes_start + 1);
975 initNodeReorder<H>(nodes, nodes[local_nodes_start], sub_boxes[i], boxes, sub_indices[i], sub_nboxes,
976 indices_offset+(sub_indices[i]-sub_indices[0]), max_items_per_leaf);
983 template<BVH_Heuristic H,
typename T,u
int NAXES,
typename BOX_TYPE,
typename SRC_INT_TYPE>
984 void BVH<N>::multiSplit(
const Box<T,NAXES>& axes_minmax,
const BOX_TYPE* boxes, SRC_INT_TYPE* indices, INT_TYPE nboxes, SRC_INT_TYPE* sub_indices[N+1],
Box<T,NAXES> sub_boxes[N]) noexcept {
986 sub_indices[2] = indices+nboxes;
987 split<H>(axes_minmax, boxes,
indices, nboxes, sub_indices[1], &sub_boxes[0]);
994 SRC_INT_TYPE* sub_indices_startend[2*
N];
996 sub_boxes_unsorted[0] = sub_boxes[0];
997 sub_boxes_unsorted[1] = sub_boxes[1];
998 sub_indices_startend[0] = sub_indices[0];
999 sub_indices_startend[1] = sub_indices[1];
1000 sub_indices_startend[2] = sub_indices[1];
1001 sub_indices_startend[3] = sub_indices[2];
1002 for (INT_TYPE nsub = 2; nsub <
N; ++nsub) {
1003 SRC_INT_TYPE* selected_start = sub_indices_startend[0];
1004 SRC_INT_TYPE* selected_end = sub_indices_startend[1];
1008 for (INT_TYPE i = 0; i < nsub-1; ++i) {
1009 sub_indices_startend[2*i ] = sub_indices_startend[2*i+2];
1010 sub_indices_startend[2*i+1] = sub_indices_startend[2*i+3];
1012 for (INT_TYPE i = 0; i < nsub-1; ++i) {
1013 sub_boxes_unsorted[i] = sub_boxes_unsorted[i-1];
1017 split<H>(sub_box, boxes, selected_start, selected_end-selected_start, sub_indices_startend[2*nsub-1], &sub_boxes_unsorted[nsub]);
1018 sub_indices_startend[2*nsub-2] = selected_start;
1019 sub_indices_startend[2*nsub] = sub_indices_startend[2*nsub-1];
1020 sub_indices_startend[2*nsub+1] = selected_end;
1023 sub_indices[
N] = indices+nboxes;
1024 for (INT_TYPE i = 0; i <
N; ++i) {
1025 SRC_INT_TYPE* prev_pointer = (i != 0) ? sub_indices[i-1] :
nullptr;
1026 SRC_INT_TYPE* min_pointer =
nullptr;
1028 for (INT_TYPE
j = 0;
j <
N; ++
j) {
1029 SRC_INT_TYPE* cur_pointer = sub_indices_startend[2*
j];
1030 if ((cur_pointer > prev_pointer) && (!min_pointer || (cur_pointer < min_pointer))) {
1031 min_pointer = cur_pointer;
1032 box = sub_boxes_unsorted[
j];
1036 sub_indices[i] = min_pointer;
1043 sub_box_areas[0] = unweightedHeuristic<H>(sub_boxes[0]);
1044 sub_box_areas[1] = unweightedHeuristic<H>(sub_boxes[1]);
1045 for (INT_TYPE nsub = 2; nsub <
N; ++nsub) {
1047 INT_TYPE split_choice = INT_TYPE(-1);
1049 for (INT_TYPE i = 0; i < nsub; ++i) {
1050 const INT_TYPE index_count = (sub_indices[i+1]-sub_indices[i]);
1051 if (index_count > 1) {
1052 const T heuristic = sub_box_areas[i]*index_count;
1053 if (split_choice == INT_TYPE(-1) || heuristic > max_heuristic) {
1055 max_heuristic = heuristic;
1059 UT_ASSERT_MSG_P(split_choice != INT_TYPE(-1),
"There should always be at least one that can be split!");
1061 SRC_INT_TYPE* selected_start = sub_indices[split_choice];
1062 SRC_INT_TYPE* selected_end = sub_indices[split_choice+1];
1065 for (INT_TYPE i = nsub; i > split_choice; --i) {
1066 sub_indices[i+1] = sub_indices[i];
1068 for (INT_TYPE i = nsub-1; i > split_choice; --i) {
1069 sub_boxes[i+1] = sub_boxes[i];
1071 for (INT_TYPE i = nsub-1; i > split_choice; --i) {
1072 sub_box_areas[i+1] = sub_box_areas[i];
1076 split<H>(sub_boxes[split_choice], boxes, selected_start, selected_end-selected_start, sub_indices[split_choice+1], &sub_boxes[split_choice]);
1077 sub_box_areas[split_choice] = unweightedHeuristic<H>(sub_boxes[split_choice]);
1078 sub_box_areas[split_choice+1] = unweightedHeuristic<H>(sub_boxes[split_choice+1]);
1084 template<BVH_Heuristic H,
typename T,u
int NAXES,
typename BOX_TYPE,
typename SRC_INT_TYPE>
1085 void BVH<N>::split(
const Box<T,NAXES>& axes_minmax,
const BOX_TYPE* boxes, SRC_INT_TYPE* indices, INT_TYPE nboxes, SRC_INT_TYPE*& split_indices,
Box<T,NAXES>* split_boxes) noexcept {
1087 split_boxes[0].initBounds(boxes[indices[0]]);
1088 split_boxes[1].initBounds(boxes[indices[1]]);
1089 split_indices = indices+1;
1092 UT_ASSERT_MSG_P(nboxes > 2,
"Cases with less than 3 boxes should have already been handled!");
1098 constexpr INT_TYPE SMALL_LIMIT = 6;
1099 if (nboxes <= SMALL_LIMIT) {
1104 for (INT_TYPE box = 0; box < nboxes; ++box) {
1105 local_boxes[box].initBounds(boxes[indices[box]]);
1108 const INT_TYPE partition_limit = (INT_TYPE(1)<<(nboxes-1));
1109 INT_TYPE best_partition = INT_TYPE(-1);
1111 for (INT_TYPE partition_bits = 1; partition_bits < partition_limit; ++partition_bits) {
1113 sub_boxes[0] = local_boxes[0];
1114 sub_boxes[1].initBounds();
1115 INT_TYPE sub_counts[2] = {1,0};
1116 for (INT_TYPE bit = 0; bit < nboxes-1; ++bit) {
1117 INT_TYPE dest = (partition_bits>>bit)&1;
1118 sub_boxes[dest].combine(local_boxes[bit+1]);
1124 unweightedHeuristic<H>(sub_boxes[0])*sub_counts[0] +
1125 unweightedHeuristic<H>(sub_boxes[1])*sub_counts[1];
1127 if (best_partition == INT_TYPE(-1) || heuristic < best_heuristic) {
1129 best_partition = partition_bits;
1130 best_heuristic = heuristic;
1131 split_boxes[0] = sub_boxes[0];
1132 split_boxes[1] = sub_boxes[1];
1136 #if 0 // This isn't actually necessary with the current design, because I changed how the number of subtree nodes is determined.
1142 if (best_partition == partition_limit - 1) {
1144 SRC_INT_TYPE last_index = indices[0];
1145 SRC_INT_TYPE* dest_indices =
indices;
1146 SRC_INT_TYPE* local_split_indices = indices + nboxes-1;
1147 for (; dest_indices != local_split_indices; ++dest_indices) {
1148 dest_indices[0] = dest_indices[1];
1150 *local_split_indices = last_index;
1151 split_indices = local_split_indices;
1155 sub_boxes[0] = sub_boxes[1];
1156 sub_boxes[1] = temp_box;
1163 SRC_INT_TYPE local_indices[SMALL_LIMIT-1];
1164 for (INT_TYPE box = 0; box < nboxes-1; ++box) {
1165 local_indices[box] = indices[box+1];
1167 SRC_INT_TYPE* dest_indices = indices+1;
1168 SRC_INT_TYPE* src_indices = local_indices;
1170 for (INT_TYPE bit = 0; bit < nboxes-1; ++bit, ++src_indices) {
1171 if (!((best_partition>>bit)&1)) {
1173 *dest_indices = *src_indices;
1177 split_indices = dest_indices;
1179 src_indices = local_indices;
1180 for (INT_TYPE bit = 0; bit < nboxes-1; ++bit, ++src_indices) {
1181 if ((best_partition>>bit)&1) {
1183 *dest_indices = *src_indices;
1191 T max_axis_length = axes_minmax.vals[0][1] - axes_minmax.vals[0][0];
1192 for (
uint axis = 1; axis < NAXES; ++axis) {
1193 const T axis_length = axes_minmax.vals[axis][1] - axes_minmax.vals[axis][0];
1194 if (axis_length > max_axis_length) {
1196 max_axis_length = axis_length;
1200 if (!(max_axis_length >
T(0))) {
1203 split_indices = indices + nboxes/2;
1204 split_boxes[0] = axes_minmax;
1205 split_boxes[1] = axes_minmax;
1209 const INT_TYPE axis = max_axis;
1211 constexpr INT_TYPE MID_LIMIT = 2*NSPANS;
1212 if (nboxes <= MID_LIMIT) {
1217 T midpointsx2[MID_LIMIT];
1218 for (INT_TYPE i = 0; i < nboxes; ++i) {
1219 midpointsx2[i] =
utBoxCenter(boxes[indices[i]], axis);
1221 SRC_INT_TYPE local_indices[MID_LIMIT];
1222 for (INT_TYPE i = 0; i < nboxes; ++i) {
1223 local_indices[i] = i;
1226 const INT_TYPE chunk_starts[5] = {0, nboxes/4, nboxes/2, INT_TYPE((3*
uint64(nboxes))/4), nboxes};
1229 for (INT_TYPE chunk = 0; chunk < 4; ++chunk) {
1230 const INT_TYPE
start = chunk_starts[chunk];
1231 const INT_TYPE end = chunk_starts[chunk+1];
1232 for (INT_TYPE i = start+1; i <
end; ++i) {
1233 SRC_INT_TYPE indexi = local_indices[i];
1234 T vi = midpointsx2[indexi];
1235 for (INT_TYPE
j = start;
j < i; ++
j) {
1236 SRC_INT_TYPE indexj = local_indices[
j];
1237 T vj = midpointsx2[indexj];
1240 local_indices[
j] = indexi;
1244 local_indices[
j] = indexi;
1247 indexj = local_indices[
j];
1255 SRC_INT_TYPE local_indices_temp[MID_LIMIT];
1256 std::merge(local_indices, local_indices+chunk_starts[1],
1257 local_indices+chunk_starts[1], local_indices+chunk_starts[2],
1258 local_indices_temp, [&midpointsx2](
const SRC_INT_TYPE
a,
const SRC_INT_TYPE
b)->
bool {
1259 return midpointsx2[
a] < midpointsx2[
b];
1261 std::merge(local_indices+chunk_starts[2], local_indices+chunk_starts[3],
1262 local_indices+chunk_starts[3], local_indices+chunk_starts[4],
1263 local_indices_temp+chunk_starts[2], [&midpointsx2](
const SRC_INT_TYPE a,
const SRC_INT_TYPE b)->
bool {
1264 return midpointsx2[
a] < midpointsx2[
b];
1266 std::merge(local_indices_temp, local_indices_temp+chunk_starts[2],
1267 local_indices_temp+chunk_starts[2], local_indices_temp+chunk_starts[4],
1268 local_indices, [&midpointsx2](
const SRC_INT_TYPE a,
const SRC_INT_TYPE b)->
bool {
1269 return midpointsx2[
a] < midpointsx2[
b];
1273 for (INT_TYPE i = 0; i < nboxes; ++i) {
1274 local_indices[i] = indices[local_indices[i]];
1277 for (INT_TYPE i = 0; i < nboxes; ++i) {
1278 indices[i] = local_indices[i];
1281 std::stable_sort(indices, indices+nboxes, [boxes,max_axis](SRC_INT_TYPE a, SRC_INT_TYPE b)->
bool {
1289 const INT_TYPE nsplits = nboxes-1;
1291 left_boxes[0] = box_accumulator;
1292 for (INT_TYPE i = 1; i < nsplits; ++i) {
1293 box_accumulator.combine(boxes[local_indices[i]]);
1294 left_boxes[i] = box_accumulator;
1296 box_accumulator.initBounds(boxes[local_indices[nsplits-1]]);
1297 right_boxes[nsplits-1] = box_accumulator;
1298 for (INT_TYPE i = nsplits-1; i > 0; --i) {
1299 box_accumulator.combine(boxes[local_indices[i]]);
1300 right_boxes[i-1] = box_accumulator;
1303 INT_TYPE best_split = 0;
1304 T best_local_heuristic =
1305 unweightedHeuristic<H>(left_boxes[0]) +
1306 unweightedHeuristic<H>(right_boxes[0])*(nboxes-1);
1309 unweightedHeuristic<H>(left_boxes[
split])*(
split+1) +
1310 unweightedHeuristic<H>(right_boxes[
split])*(nboxes-(
split+1));
1311 if (heuristic < best_local_heuristic) {
1313 best_local_heuristic = heuristic;
1316 split_indices = indices+best_split+1;
1317 split_boxes[0] = left_boxes[best_split];
1318 split_boxes[1] = right_boxes[best_split];
1322 const T axis_min = axes_minmax.vals[max_axis][0];
1323 const T axis_length = max_axis_length;
1325 for (INT_TYPE i = 0; i < NSPANS; ++i) {
1326 span_boxes[i].initBounds();
1328 INT_TYPE span_counts[NSPANS];
1329 for (INT_TYPE i = 0; i < NSPANS; ++i) {
1336 constexpr INT_TYPE BOX_SPANS_PARALLEL_THRESHOLD = 2048;
1337 INT_TYPE ntasks = 1;
1338 if (nboxes >= BOX_SPANS_PARALLEL_THRESHOLD) {
1340 ntasks = (nprocessors > 1) ?
SYSmin(4*nprocessors, nboxes/(BOX_SPANS_PARALLEL_THRESHOLD/2)) : 1;
1343 for (INT_TYPE indexi = 0; indexi < nboxes; ++indexi) {
1344 const auto& box = boxes[indices[indexi]];
1346 const uint span_index =
SYSclamp(
int((sum-axis_min_x2)*axis_index_scale),
int(0),
int(NSPANS-1));
1347 ++span_counts[span_index];
1349 span_box.combine(box);
1355 parallel_boxes.
setSize(NSPANS*ntasks);
1357 parallel_counts.
setSize(NSPANS*ntasks);
1358 UTparallelFor(
UT_BlockedRange<INT_TYPE>(0,ntasks), [¶llel_boxes,¶llel_counts,ntasks,boxes,nboxes,indices,axis,axis_min_x2,axis_index_scale](
const UT_BlockedRange<INT_TYPE>& r) {
1359 for (INT_TYPE taski = r.begin(), end = r.end(); taski <
end; ++taski) {
1361 for (INT_TYPE i = 0; i < NSPANS; ++i) {
1362 span_boxes[i].initBounds();
1364 INT_TYPE span_counts[NSPANS];
1365 for (INT_TYPE i = 0; i < NSPANS; ++i) {
1368 const INT_TYPE startbox = (taski*
uint64(nboxes))/ntasks;
1369 const INT_TYPE endbox = ((taski+1)*
uint64(nboxes))/ntasks;
1370 for (INT_TYPE indexi = startbox; indexi != endbox; ++indexi) {
1371 const auto& box = boxes[indices[indexi]];
1373 const uint span_index =
SYSclamp(
int((sum-axis_min_x2)*axis_index_scale),
int(0),
int(NSPANS-1));
1374 ++span_counts[span_index];
1376 span_box.combine(box);
1379 const INT_TYPE dest_array_start = taski*NSPANS;
1380 for (INT_TYPE i = 0; i < NSPANS; ++i) {
1381 parallel_boxes[dest_array_start+i] = span_boxes[i];
1383 for (INT_TYPE i = 0; i < NSPANS; ++i) {
1384 parallel_counts[dest_array_start+i] = span_counts[i];
1390 for (INT_TYPE taski = 0; taski < ntasks; ++taski) {
1391 const INT_TYPE dest_array_start = taski*NSPANS;
1392 for (INT_TYPE i = 0; i < NSPANS; ++i) {
1393 span_boxes[i].combine(parallel_boxes[dest_array_start+i]);
1396 for (INT_TYPE taski = 0; taski < ntasks; ++taski) {
1397 const INT_TYPE dest_array_start = taski*NSPANS;
1398 for (INT_TYPE i = 0; i < NSPANS; ++i) {
1399 span_counts[i] += parallel_counts[dest_array_start+i];
1411 left_boxes[0] = box_accumulator;
1412 for (INT_TYPE i = 1; i < NSPLITS; ++i) {
1413 box_accumulator.combine(span_boxes[i]);
1414 left_boxes[i] = box_accumulator;
1416 box_accumulator = span_boxes[NSPANS-1];
1417 right_boxes[NSPLITS-1] = box_accumulator;
1418 for (INT_TYPE i = NSPLITS-1; i > 0; --i) {
1419 box_accumulator.combine(span_boxes[i]);
1420 right_boxes[i-1] = box_accumulator;
1423 INT_TYPE left_counts[NSPLITS];
1426 INT_TYPE count_accumulator = span_counts[0];
1427 left_counts[0] = count_accumulator;
1428 for (INT_TYPE spliti = 1; spliti < NSPLITS; ++spliti) {
1429 count_accumulator += span_counts[spliti];
1430 left_counts[spliti] = count_accumulator;
1434 const INT_TYPE min_count = nboxes/MIN_FRACTION;
1435 UT_ASSERT_MSG_P(min_count > 0,
"MID_LIMIT above should have been large enough that nboxes would be > MIN_FRACTION");
1436 const INT_TYPE max_count = ((MIN_FRACTION-1)*
uint64(nboxes))/MIN_FRACTION;
1437 UT_ASSERT_MSG_P(max_count < nboxes,
"I'm not sure how this could happen mathematically, but it needs to be checked.");
1438 T smallest_heuristic = std::numeric_limits<T>::infinity();
1439 INT_TYPE split_index = -1;
1440 for (INT_TYPE spliti = 0; spliti < NSPLITS; ++spliti) {
1441 const INT_TYPE left_count = left_counts[spliti];
1442 if (left_count < min_count || left_count > max_count) {
1445 const INT_TYPE right_count = nboxes-left_count;
1447 left_count*unweightedHeuristic<H>(left_boxes[spliti]) +
1448 right_count*unweightedHeuristic<H>(right_boxes[spliti]);
1449 if (heuristic < smallest_heuristic) {
1450 smallest_heuristic = heuristic;
1451 split_index = spliti;
1455 SRC_INT_TYPE*
const indices_end = indices+nboxes;
1457 if (split_index == -1) {
1467 SRC_INT_TYPE* nth_index;
1468 if (left_counts[0] > max_count) {
1470 nth_index = indices+max_count;
1473 else if (left_counts[NSPLITS-1] < min_count) {
1475 nth_index = indices+min_count;
1480 nth_index = indices+nboxes/2;
1490 nthElement<T>(boxes,
indices,indices+nboxes,max_axis,nth_index);
1492 split_indices = nth_index;
1494 for (SRC_INT_TYPE* left_indices = indices+1; left_indices < nth_index; ++left_indices) {
1495 left_box.combine(boxes[*left_indices]);
1498 for (SRC_INT_TYPE* right_indices = nth_index+1; right_indices < indices_end; ++right_indices) {
1499 right_box.combine(boxes[*right_indices]);
1501 split_boxes[0] = left_box;
1502 split_boxes[1] = right_box;
1506 SRC_INT_TYPE* ppivot_start;
1507 SRC_INT_TYPE* ppivot_end;
1508 partitionByCentre(boxes,indices,indices+nboxes,max_axis,pivotx2,ppivot_start,ppivot_end);
1510 split_indices = indices + left_counts[split_index];
1515 if (split_indices >= ppivot_start && split_indices <= ppivot_end) {
1516 split_boxes[0] = left_boxes[split_index];
1517 split_boxes[1] = right_boxes[split_index];
1522 if (split_indices < ppivot_start) {
1523 split_indices = ppivot_start;
1526 split_indices = ppivot_end;
1530 if (split_indices == indices) {
1533 else if (split_indices == indices_end) {
1538 for (SRC_INT_TYPE* left_indices = indices+1; left_indices < split_indices; ++left_indices) {
1539 left_box.combine(boxes[*left_indices]);
1542 for (SRC_INT_TYPE* right_indices = split_indices+1; right_indices < indices_end; ++right_indices) {
1543 right_box.combine(boxes[*right_indices]);
1545 split_boxes[0] = left_box;
1546 split_boxes[1] = right_box;
1551 template<u
int PARALLEL_THRESHOLD,
typename SRC_INT_TYPE>
1552 void BVH<N>::adjustParallelChildNodes(INT_TYPE nparallel,
UT_Array<Node>& nodes,
Node& node,
UT_Array<Node>* parallel_nodes, SRC_INT_TYPE* sub_indices) noexcept
1555 INT_TYPE counted_parallel = 0;
1556 INT_TYPE childi = 0;
1557 for (INT_TYPE taski = r.begin(), end = r.end(); taski <
end; ++taski) {
1559 INT_TYPE sub_nboxes;
1560 for (; childi <
N; ++childi) {
1561 sub_nboxes = sub_indices[childi+1]-sub_indices[childi];
1562 if (sub_nboxes >= PARALLEL_THRESHOLD) {
1563 if (counted_parallel == taski) {
1571 const UT_Array<Node>& local_nodes = parallel_nodes[counted_parallel];
1572 INT_TYPE n = local_nodes.
size();
1573 INT_TYPE local_nodes_start = Node::getInternalNum(node.child[childi])+1;
1577 for (INT_TYPE
j = 0;
j <
n; ++
j) {
1578 Node local_node = local_nodes[
j];
1579 for (INT_TYPE childj = 0; childj <
N; ++childj) {
1580 INT_TYPE local_child = local_node.child[childj];
1581 if (Node::isInternal(local_child) && local_child != Node::EMPTY) {
1582 local_child += local_nodes_start;
1583 local_node.child[childj] = local_child;
1586 nodes[local_nodes_start+
j] = local_node;
1593 template<
typename T,
typename BOX_TYPE,
typename SRC_INT_TYPE>
1594 void BVH<N>::nthElement(
const BOX_TYPE* boxes, SRC_INT_TYPE* indices,
const SRC_INT_TYPE* indices_end,
const uint axis, SRC_INT_TYPE*
const nth) noexcept {
1599 utBoxCenter(boxes[indices[(indices_end-indices)/2]], axis),
1602 if (pivots[0] < pivots[1]) {
1603 const T temp = pivots[0];
1604 pivots[0] = pivots[1];
1607 if (pivots[0] < pivots[2]) {
1608 const T temp = pivots[0];
1609 pivots[0] = pivots[2];
1612 if (pivots[1] < pivots[2]) {
1613 const T temp = pivots[1];
1614 pivots[1] = pivots[2];
1617 T mid_pivotx2 = pivots[1];
1620 if (mid_pivotx2 < min_pivotx2) {
1621 mid_pivotx2 = min_pivotx2;
1623 else if (mid_pivotx2 > max_pivotx2) {
1624 mid_pivotx2 = max_pivotx2;
1627 SRC_INT_TYPE* pivot_start;
1628 SRC_INT_TYPE* pivot_end;
1629 partitionByCentre(boxes,indices,indices_end,axis,mid_pivotx2,pivot_start,pivot_end);
1630 if (nth < pivot_start) {
1631 indices_end = pivot_start;
1633 else if (nth < pivot_end) {
1639 indices = pivot_end;
1641 if (indices_end <= indices+1) {
1648 template<
typename T,
typename BOX_TYPE,
typename SRC_INT_TYPE>
1649 void BVH<N>::partitionByCentre(
const BOX_TYPE* boxes, SRC_INT_TYPE*
const indices,
const SRC_INT_TYPE*
const indices_end,
const uint axis,
const T pivotx2, SRC_INT_TYPE*& ppivot_start, SRC_INT_TYPE*& ppivot_end) noexcept {
1653 SRC_INT_TYPE* pivot_start =
indices;
1655 SRC_INT_TYPE* pivot_end =
indices;
1658 for (SRC_INT_TYPE* psrc_index = indices; psrc_index != indices_end; ++psrc_index) {
1659 const T srcsum =
utBoxCenter(boxes[*psrc_index], axis);
1660 if (srcsum < pivotx2) {
1661 if (psrc_index != pivot_start) {
1662 if (pivot_start == pivot_end) {
1664 const SRC_INT_TYPE temp = *psrc_index;
1665 *psrc_index = *pivot_start;
1666 *pivot_start = temp;
1670 const SRC_INT_TYPE temp = *psrc_index;
1671 *psrc_index = *pivot_end;
1672 *pivot_end = *pivot_start;
1673 *pivot_start = temp;
1679 else if (srcsum == pivotx2) {
1681 if (psrc_index != pivot_end) {
1682 const SRC_INT_TYPE temp = *psrc_index;
1683 *psrc_index = *pivot_end;
1689 ppivot_start = pivot_start;
1690 ppivot_end = pivot_end;
1707 INT_TYPE cur_nodei = stack[stack.
size()-2];
1708 INT_TYPE cur_i = stack[stack.
size()-1];
1716 ++stack[stack.
size()-1];
1718 INT_TYPE child_nodei = cur_node.child[cur_i];
1719 if (Node::isInternal(child_nodei)) {
1720 if (child_nodei == Node::EMPTY) {
1727 INT_TYPE internal_node = Node::getInternalNum(child_nodei);
1730 stack.
append(internal_node);
void traverseParallel(INT_TYPE parallel_threshold, FUNCTORS &functors, LOCAL_DATA *data_for_parent=nullptr) const noexcept
void UTparallelFor(const Range &range, const Body &body, const int subscribe_ratio=2, const int min_grain_size=1, const bool force_use_task_scope=true)
GLsizei GLenum const void * indices
SYS_FORCE_INLINE exint length() const
SYS_FORCE_INLINE void removeLast()
auto printf(const S &fmt, const T &...args) -> int
GLsizei const GLfloat * value
bool SYSisFinite(fpreal64 f)
void setSizeNoInit(exint newsize)
static void createTrivialIndices(SRC_INT_TYPE *indices, const INT_TYPE n) noexcept
void debugDump() const
Prints a text representation of the tree to stdout.
SYS_FORCE_INLINE const char * buffer() const
GLboolean GLboolean GLboolean GLboolean a
void setCapacity(exint new_capacity)
#define UT_ASSERT_MSG_P(ZZ,...)
unsigned long long uint64
void setSize(exint newsize)
void traverse(FUNCTORS &functors, LOCAL_DATA *data_for_parent=nullptr) const noexcept
#define UT_ASSERT_MSG(ZZ,...)
GA_API const UT_StringHolder scale
static constexpr uint scale
static int getNumProcessors()
UT_Vector3T< T > SYSclamp(const UT_Vector3T< T > &v, const UT_Vector3T< T > &min, const UT_Vector3T< T > &max)
STATIC_INLINE uint64_t H(uint64_t x, uint64_t y, uint64_t mul, int r)
SYS_FORCE_INLINE T utBoxCenter(const UT::Box< T, NAXES > &box, uint axis) noexcept
SYS_FORCE_INLINE bool utBoxExclude(const UT::Box< T, NAXES > &box) noexcept
void init(const BOX_TYPE *boxes, const INT_TYPE nboxes, SRC_INT_TYPE *indices=nullptr, bool reorder_indices=false, INT_TYPE max_items_per_leaf=1) noexcept
GLboolean GLboolean GLboolean b
GLint GLint GLsizei GLsizei GLsizei depth
SIM_API const UT_StringHolder position
SYS_FORCE_INLINE void append(char character)
GA_API const UT_StringHolder N
void traverseVector(FUNCTORS &functors, LOCAL_DATA *data_for_parent=nullptr) const noexcept
INT_TYPE utExcludeNaNInfBoxIndices(const BOX_TYPE *boxes, SRC_INT_TYPE *indices, INT_TYPE &nboxes) noexcept
void OIIO_UTIL_API split(string_view str, std::vector< string_view > &result, string_view sep=string_view(), int maxsplit=-1)
bool isEmpty() const
Returns true iff there are no occupied elements in the array.