From ac25e8919308aa0101870491ec0eb99687d9ca9a Mon Sep 17 00:00:00 2001
From: Fabio Pellacini <fabio.pellacini@gmail.com>
Date: Sun, 7 Aug 2022 06:19:20 +0200
Subject: [PATCH 1/9] renaming embree

---
 libs/yocto/yocto_bvh.cpp   | 70 ++++++++++++++++-----------------
 libs/yocto/yocto_bvh.h     | 80 +++++++++++++++++++++++++++++++-------
 libs/yocto/yocto_trace.cpp | 13 +++----
 libs/yocto/yocto_trace.h   |  4 +-
 4 files changed, 109 insertions(+), 58 deletions(-)

diff --git a/libs/yocto/yocto_bvh.cpp b/libs/yocto/yocto_bvh.cpp
index 2fc5ddb17..03cb9cbad 100644
--- a/libs/yocto/yocto_bvh.cpp
+++ b/libs/yocto/yocto_bvh.cpp
@@ -878,18 +878,17 @@ static RTCDevice embree_device() {
 }
 
 // Clear Embree bvh
-void clear_embree_bvh(void* embree_bvh) {
-  if (embree_bvh) rtcReleaseScene((RTCScene)embree_bvh);
+void clear_ebvh(void* ebvh) {
+  if (ebvh) rtcReleaseScene((RTCScene)ebvh);
 }
 
 // Build the bvh acceleration structure.
-shape_embree_bvh make_shape_embree_bvh(
-    const shape_data& shape, bool highquality) {
-  auto bvh       = shape_embree_bvh{};
-  auto edevice   = embree_device();
-  bvh.embree_bvh = unique_ptr<void, void (*)(void*)>{
-      rtcNewScene(edevice), &clear_embree_bvh};
-  auto escene = (RTCScene)bvh.embree_bvh.get();
+shape_ebvh make_shape_ebvh(const shape_data& shape, bool highquality) {
+  auto bvh     = shape_ebvh{};
+  auto edevice = embree_device();
+  bvh.bvh      = unique_ptr<void, void (*)(void*)>{
+           rtcNewScene(edevice), &clear_ebvh};
+  auto escene = (RTCScene)bvh.bvh.get();
   if (highquality) {
     rtcSetSceneBuildQuality(escene, RTC_BUILD_QUALITY_HIGH);
   } else {
@@ -967,28 +966,28 @@ shape_embree_bvh make_shape_embree_bvh(
   return bvh;
 }
 
-scene_embree_bvh make_scene_embree_bvh(
+scene_ebvh make_scene_ebvh(
     const scene_data& scene, bool highquality, bool noparallel) {
   // scene bvh
-  auto bvh = scene_embree_bvh{};
+  auto bvh = scene_ebvh{};
 
   // shape bvhs
   bvh.shapes.resize(scene.shapes.size());
   if (noparallel) {
     for (auto idx : range(scene.shapes.size())) {
-      bvh.shapes[idx] = make_shape_embree_bvh(scene.shapes[idx], highquality);
+      bvh.shapes[idx] = make_shape_ebvh(scene.shapes[idx], highquality);
     }
   } else {
     parallel_for(scene.shapes.size(), [&](size_t idx) {
-      bvh.shapes[idx] = make_shape_embree_bvh(scene.shapes[idx], highquality);
+      bvh.shapes[idx] = make_shape_ebvh(scene.shapes[idx], highquality);
     });
   }
 
   // scene bvh
-  auto edevice   = embree_device();
-  bvh.embree_bvh = unique_ptr<void, void (*)(void*)>{
-      rtcNewScene(edevice), &clear_embree_bvh};
-  auto escene = (RTCScene)bvh.embree_bvh.get();
+  auto edevice = embree_device();
+  bvh.bvh      = unique_ptr<void, void (*)(void*)>{
+           rtcNewScene(edevice), &clear_ebvh};
+  auto escene = (RTCScene)bvh.bvh.get();
   if (highquality) {
     rtcSetSceneBuildQuality(escene, RTC_BUILD_QUALITY_HIGH);
   } else {
@@ -999,7 +998,7 @@ scene_embree_bvh make_scene_embree_bvh(
     auto& instance  = scene.instances[instance_id];
     auto& sbvh      = bvh.shapes[instance.shape];
     auto  egeometry = rtcNewGeometry(edevice, RTC_GEOMETRY_TYPE_INSTANCE);
-    rtcSetGeometryInstancedScene(egeometry, (RTCScene)sbvh.embree_bvh.get());
+    rtcSetGeometryInstancedScene(egeometry, (RTCScene)sbvh.bvh.get());
     rtcSetGeometryTransform(
         egeometry, 0, RTC_FORMAT_FLOAT3X4_COLUMN_MAJOR, &instance.frame);
     rtcCommitGeometry(egeometry);
@@ -1011,18 +1010,18 @@ scene_embree_bvh make_scene_embree_bvh(
 }
 
 // Refit bvh data
-void update_shape_embree_bvh(shape_embree_bvh& bvh, const shape_data& shape) {
+void update_shape_ebvh(shape_ebvh& bvh, const shape_data& shape) {
   throw embree_error{"feature not supported"};
 }
-void update_scene_embree_bvh(scene_embree_bvh& bvh, const scene_data& scene,
+void update_scene_ebvh(scene_ebvh& bvh, const scene_data& scene,
     const vector<int>& updated_instances, const vector<int>& updated_shapes) {
   // scene bvh
-  auto escene = (RTCScene)bvh.embree_bvh.get();
+  auto escene = (RTCScene)bvh.bvh.get();
   for (auto instance_id : updated_instances) {
     auto& instance    = scene.instances[instance_id];
     auto& sbvh        = bvh.shapes[instance.shape];
     auto  embree_geom = rtcGetGeometry(escene, instance_id);
-    rtcSetGeometryInstancedScene(embree_geom, (RTCScene)sbvh.embree_bvh.get());
+    rtcSetGeometryInstancedScene(embree_geom, (RTCScene)sbvh.bvh.get());
     rtcSetGeometryTransform(
         embree_geom, 0, RTC_FORMAT_FLOAT3X4_COLUMN_MAJOR, &instance.frame);
     rtcCommitGeometry(embree_geom);
@@ -1033,7 +1032,7 @@ void update_scene_embree_bvh(scene_embree_bvh& bvh, const scene_data& scene,
 // Intersect ray with a bvh returning either the first or any intersection
 // depending on `find_any`. Returns the ray distance , the instance id,
 // the shape element index and the element barycentric coordinates.
-shape_intersection intersect_shape_embree_bvh(const shape_embree_bvh& bvh,
+shape_intersection intersect_shape_ebvh(const shape_ebvh& bvh,
     const shape_data& shape, const ray3f& ray, bool find_any) {
   RTCRayHit embree_ray;
   embree_ray.ray.org_x     = ray.o.x;
@@ -1051,7 +1050,7 @@ shape_intersection intersect_shape_embree_bvh(const shape_embree_bvh& bvh,
   embree_ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
   RTCIntersectContext embree_ctx;
   rtcInitIntersectContext(&embree_ctx);
-  rtcIntersect1((RTCScene)bvh.embree_bvh.get(), &embree_ctx, &embree_ray);
+  rtcIntersect1((RTCScene)bvh.bvh.get(), &embree_ctx, &embree_ray);
   if (embree_ray.hit.geomID == RTC_INVALID_GEOMETRY_ID) return {};
   auto element  = (int)embree_ray.hit.primID;
   auto uv       = vec2f{embree_ray.hit.u, embree_ray.hit.v};
@@ -1059,7 +1058,7 @@ shape_intersection intersect_shape_embree_bvh(const shape_embree_bvh& bvh,
   return {element, uv, distance, true};
 }
 
-scene_intersection intersect_scene_embree_bvh(const scene_embree_bvh& bvh,
+scene_intersection intersect_scene_ebvh(const scene_ebvh& bvh,
     const scene_data& scene, const ray3f& ray, bool find_any) {
   RTCRayHit embree_ray;
   embree_ray.ray.org_x     = ray.o.x;
@@ -1077,7 +1076,7 @@ scene_intersection intersect_scene_embree_bvh(const scene_embree_bvh& bvh,
   embree_ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
   RTCIntersectContext embree_ctx;
   rtcInitIntersectContext(&embree_ctx);
-  rtcIntersect1((RTCScene)bvh.embree_bvh.get(), &embree_ctx, &embree_ray);
+  rtcIntersect1((RTCScene)bvh.bvh.get(), &embree_ctx, &embree_ray);
   if (embree_ray.hit.geomID == RTC_INVALID_GEOMETRY_ID) return {};
   auto instance = (int)embree_ray.hit.instID[0];
   auto element  = (int)embree_ray.hit.primID;
@@ -1086,11 +1085,11 @@ scene_intersection intersect_scene_embree_bvh(const scene_embree_bvh& bvh,
   return {instance, element, uv, distance, true};
 }
 
-scene_intersection intersect_instance_embree_bvh(const scene_embree_bvh& bvh,
+scene_intersection intersect_instance_ebvh(const scene_ebvh& bvh,
     const scene_data& scene, int instance_, const ray3f& ray, bool find_any) {
   auto& instance     = scene.instances[instance_];
   auto  inv_ray      = transform_ray(inverse(instance.frame, true), ray);
-  auto  intersection = intersect_shape_embree_bvh(bvh.shapes[instance.shape],
+  auto  intersection = intersect_shape_ebvh(bvh.shapes[instance.shape],
        scene.shapes[instance.shape], inv_ray, find_any);
   if (!intersection.hit) return {};
   return {instance_, intersection.element, intersection.uv,
@@ -1103,34 +1102,33 @@ scene_intersection intersect_instance_embree_bvh(const scene_embree_bvh& bvh,
 bool embree_supported() { return false; }
 
 // Not implemented
-shape_embree_bvh make_shape_embree_bvh(
-    const shape_data& shape, bool highquality) {
+shape_ebvh make_shape_ebvh(const shape_data& shape, bool highquality) {
   throw embree_error{"Embree not available"};
 }
-scene_embree_bvh make_scene_embree_bvh(
+scene_ebvh make_scene_ebvh(
     const scene_data& scene, bool highquality, bool noparallel) {
   throw embree_error{"Embree not available"};
 }
 
 // Not implemented
-void update_shape_embree_bvh(shape_embree_bvh& bvh, const shape_data& shape) {
+void update_shape_ebvh(shape_ebvh& bvh, const shape_data& shape) {
   throw embree_error{"Embree not available"};
 }
-void update_scene_embree_bvh(scene_embree_bvh& bvh, const scene_data& scene,
+void update_scene_ebvh(scene_ebvh& bvh, const scene_data& scene,
     const vector<int>& updated_instances, const vector<int>& updated_shapes) {
   throw embree_error{"Embree not available"};
 }
 
 // Not implemented
-shape_intersection intersect_shape_embree_bvh(const shape_embree_bvh& bvh,
+shape_intersection intersect_shape_ebvh(const shape_ebvh& bvh,
     const shape_data& shape, const ray3f& ray, bool find_any) {
   throw embree_error{"Embree not available"};
 }
-scene_intersection intersect_scene_embree_bvh(const scene_embree_bvh& bvh,
+scene_intersection intersect_scene_ebvh(const scene_ebvh& bvh,
     const scene_data& scene, const ray3f& ray, bool find_any) {
   throw embree_error{"Embree not available"};
 }
-scene_intersection intersect_instance_embree_bvh(const scene_embree_bvh& bvh,
+scene_intersection intersect_instance_ebvh(const scene_ebvh& bvh,
     const scene_data& scene, int instance, const ray3f& ray, bool find_any) {
   throw embree_error{"Embree not available"};
 }
diff --git a/libs/yocto/yocto_bvh.h b/libs/yocto/yocto_bvh.h
index 52898f2d2..b3aa01143 100644
--- a/libs/yocto/yocto_bvh.h
+++ b/libs/yocto/yocto_bvh.h
@@ -150,39 +150,41 @@ scene_intersection overlap_scene_bvh(const scene_bvh& bvh,
 // -----------------------------------------------------------------------------
 namespace yocto {
 
+// Intel Embree tree
+using ebvh_tree = unique_ptr<void, void (*)(void*)>;
+
 // Wrapper for Intel Embree.
-struct shape_embree_bvh {
-  unique_ptr<void, void (*)(void*)> embree_bvh = {nullptr, nullptr};  // embree
+struct shape_ebvh {
+  unique_ptr<void, void (*)(void*)> bvh = {nullptr, nullptr};  // embree
 };
 
 // Wrapper for Intel Embree.
-struct scene_embree_bvh {
-  vector<shape_embree_bvh>          shapes     = {};                  // shapes
-  unique_ptr<void, void (*)(void*)> embree_bvh = {nullptr, nullptr};  // embree
+struct scene_ebvh {
+  vector<shape_ebvh>                shapes = {};                  // shapes
+  unique_ptr<void, void (*)(void*)> bvh    = {nullptr, nullptr};  // embree
 };
 
 // Check if embree is supported
 bool embree_supported();
 
 // Build the bvh acceleration structure.
-shape_embree_bvh make_shape_embree_bvh(
-    const shape_data& shape, bool highquality = false);
-scene_embree_bvh make_scene_embree_bvh(
+shape_ebvh make_shape_ebvh(const shape_data& shape, bool highquality = false);
+scene_ebvh make_scene_ebvh(
     const scene_data& scene, bool highquality = false, bool noparallel = false);
 
 // Refit bvh data
-void update_shape_embree_bvh(shape_embree_bvh& bvh, const shape_data& shape);
-void update_scene_embree_bvh(scene_embree_bvh& bvh, const scene_data& scene,
+void update_shape_ebvh(shape_ebvh& bvh, const shape_data& shape);
+void update_scene_ebvh(scene_ebvh& bvh, const scene_data& scene,
     const vector<int>& updated_instances, const vector<int>& updated_shapes);
 
 // Intersect ray with a bvh returning either the first or any intersection
 // depending on `find_any`. Returns the ray distance , the instance id,
 // the shape element index and the element barycentric coordinates.
-shape_intersection intersect_shape_embree_bvh(const shape_embree_bvh& bvh,
+shape_intersection intersect_shape_ebvh(const shape_ebvh& bvh,
     const shape_data& shape, const ray3f& ray, bool find_any = false);
-scene_intersection intersect_scene_embree_bvh(const scene_embree_bvh& bvh,
+scene_intersection intersect_scene_ebvh(const scene_ebvh& bvh,
     const scene_data& scene, const ray3f& ray, bool find_any = false);
-scene_intersection intersect_instance_embree_bvh(const scene_embree_bvh& bvh,
+scene_intersection intersect_instance_ebvh(const scene_ebvh& bvh,
     const scene_data& scene, int instance, const ray3f& ray,
     bool find_any = false);
 
@@ -272,4 +274,56 @@ using bvh_scene [[deprecated]] = scene_bvh;
 
 }  // namespace yocto
 
+// -----------------------------------------------------------------------------
+// EMBREE BACKWARD COMPATIBILITY
+// -----------------------------------------------------------------------------
+namespace yocto {
+
+// backward compatibility
+using shape_embree_bvh = shape_ebvh;
+using scene_embree_bvh = scene_ebvh;
+
+// Build the bvh acceleration structure.
+[[deprecated]] inline shape_embree_bvh make_shape_embree_bvh(
+    const shape_data& shape, bool highquality = false) {
+  return make_shape_ebvh(shape, highquality);
+}
+[[deprecated]] inline scene_embree_bvh make_scene_embree_bvh(
+    const scene_data& scene, bool highquality = false,
+    bool noparallel = false) {
+  return make_scene_ebvh(scene, highquality, noparallel);
+}
+
+// Refit bvh data
+[[deprecated]] inline void update_shape_embree_bvh(
+    shape_embree_bvh& bvh, const shape_data& shape) {
+  return update_shape_ebvh(bvh, shape);
+}
+[[deprecated]] inline void update_scene_embree_bvh(scene_ebvh& bvh,
+    const scene_data& scene, const vector<int>& updated_instances,
+    const vector<int>& updated_shapes) {
+  return update_scene_ebvh(bvh, scene, updated_instances, updated_shapes);
+}
+
+// Intersect ray with a bvh returning either the first or any intersection
+// depending on `find_any`. Returns the ray distance , the instance id,
+// the shape element index and the element barycentric coordinates.
+[[deprecated]] inline shape_intersection intersect_shape_embree_bvh(
+    const shape_ebvh& bvh, const shape_data& shape, const ray3f& ray,
+    bool find_any = false) {
+  return intersect_shape_ebvh(bvh, shape, ray, find_any);
+}
+[[deprecated]] inline scene_intersection intersect_scene_embree_bvh(
+    const scene_ebvh& bvh, const scene_data& scene, const ray3f& ray,
+    bool find_any = false) {
+  return intersect_scene_ebvh(bvh, scene, ray, find_any);
+}
+[[deprecated]] inline scene_intersection intersect_instance_embree_bvh(
+    const scene_ebvh& bvh, const scene_data& scene, int instance,
+    const ray3f& ray, bool find_any = false) {
+  return intersect_instance_ebvh(bvh, scene, instance, ray, find_any);
+}
+
+}  // namespace yocto
+
 #endif
diff --git a/libs/yocto/yocto_trace.cpp b/libs/yocto/yocto_trace.cpp
index dfc72c9f5..fb0b8501f 100644
--- a/libs/yocto/yocto_trace.cpp
+++ b/libs/yocto/yocto_trace.cpp
@@ -87,8 +87,8 @@ namespace yocto {
 // Build the Bvh acceleration structure.
 trace_bvh make_trace_bvh(const scene_data& scene, const trace_params& params) {
   if (params.embreebvh && embree_supported()) {
-    return {{},
-        make_scene_embree_bvh(scene, params.highqualitybvh, params.noparallel)};
+    return {
+        {}, make_scene_ebvh(scene, params.highqualitybvh, params.noparallel)};
   } else {
     return {
         make_scene_bvh(scene, params.highqualitybvh, params.noparallel), {}};
@@ -98,8 +98,8 @@ trace_bvh make_trace_bvh(const scene_data& scene, const trace_params& params) {
 // Ray-intersection shortcuts
 static scene_intersection intersect_scene(const trace_bvh& bvh,
     const scene_data& scene, const ray3f& ray, bool find_any = false) {
-  if (bvh.embree.embree_bvh) {
-    return intersect_scene_embree_bvh(bvh.embree, scene, ray, find_any);
+  if (bvh.ebvh.bvh) {
+    return intersect_scene_ebvh(bvh.ebvh, scene, ray, find_any);
   } else {
     return intersect_scene_bvh(bvh.bvh, scene, ray, find_any);
   }
@@ -107,9 +107,8 @@ static scene_intersection intersect_scene(const trace_bvh& bvh,
 static scene_intersection intersect_instance(const trace_bvh& bvh,
     const scene_data& scene, int instance, const ray3f& ray,
     bool find_any = false) {
-  if (bvh.embree.embree_bvh) {
-    return intersect_instance_embree_bvh(
-        bvh.embree, scene, instance, ray, find_any);
+  if (bvh.ebvh.bvh) {
+    return intersect_instance_ebvh(bvh.ebvh, scene, instance, ray, find_any);
   } else {
     return intersect_instance_bvh(bvh.bvh, scene, instance, ray, find_any);
   }
diff --git a/libs/yocto/yocto_trace.h b/libs/yocto/yocto_trace.h
index 283b1e284..10529c660 100644
--- a/libs/yocto/yocto_trace.h
+++ b/libs/yocto/yocto_trace.h
@@ -135,8 +135,8 @@ struct trace_lights {
 
 // Trace Bvh, a wrapper of a Yocto/Bvh and an Embree one
 struct trace_bvh {
-  scene_bvh        bvh    = {};
-  scene_embree_bvh embree = {};
+  scene_bvh  bvh  = {};
+  scene_ebvh ebvh = {};
 };
 
 // Check is a sampler requires lights

From 9645a283f443c50aecac0b4c6f03bf1d8344d457 Mon Sep 17 00:00:00 2001
From: Fabio Pellacini <fabio.pellacini@gmail.com>
Date: Sun, 7 Aug 2022 09:44:52 +0200
Subject: [PATCH 2/9] updated

---
 libs/yocto/yocto_bvh.h   | 12 ------------
 libs/yocto/yocto_shape.h | 27 ++++++++++++++-------------
 2 files changed, 14 insertions(+), 25 deletions(-)

diff --git a/libs/yocto/yocto_bvh.h b/libs/yocto/yocto_bvh.h
index b3aa01143..c1a4b41c7 100644
--- a/libs/yocto/yocto_bvh.h
+++ b/libs/yocto/yocto_bvh.h
@@ -66,18 +66,6 @@ using std::vector;
 // -----------------------------------------------------------------------------
 namespace yocto {
 
-// BVH tree node containing its bounds, indices to the BVH arrays of either
-// primitives or internal nodes, the node element type,
-// and the split axis. Leaf and internal nodes are identical, except that
-// indices refer to primitives for leaf nodes or other nodes for internal nodes.
-struct bvh_node {
-  bbox3f  bbox     = invalidb3f;
-  int32_t start    = 0;
-  int16_t num      = 0;
-  int8_t  axis     = 0;
-  bool    internal = false;
-};
-
 // BVH tree stored as a node array with the tree structure is encoded using
 // array indices. BVH nodes indices refer to either the node array,
 // for internal nodes, or the primitive arrays, for leaf nodes.
diff --git a/libs/yocto/yocto_shape.h b/libs/yocto/yocto_shape.h
index 55ef357f4..cd16db616 100644
--- a/libs/yocto/yocto_shape.h
+++ b/libs/yocto/yocto_shape.h
@@ -467,24 +467,25 @@ vector<vector<int>> vertex_to_faces_adjacencies(
 // -----------------------------------------------------------------------------
 namespace yocto {
 
-// BVH tree stored as a node array with the tree structure is encoded using
-// array indices. BVH nodes indices refer to either the node array,
-// for internal nodes, or the primitive arrays, for leaf nodes.
-// Application data is not stored explicitly.
 // BVH tree node containing its bounds, indices to the BVH arrays of either
 // primitives or internal nodes, the node element type,
 // and the split axis. Leaf and internal nodes are identical, except that
 // indices refer to primitives for leaf nodes or other nodes for internal nodes.
+struct bvh_node {
+  bbox3f  bbox     = invalidb3f;
+  int32_t start    = 0;
+  int16_t num      = 0;
+  int8_t  axis     = 0;
+  bool    internal = false;
+};
+
+// BVH tree stored as a node array with the tree structure is encoded using
+// array indices. BVH nodes indices refer to either the node array,
+// for internal nodes, or the primitive arrays, for leaf nodes.
+// Application data is not stored explicitly.
 struct bvh_tree {
-  struct node {
-    bbox3f  bbox     = invalidb3f;
-    int32_t start    = 0;
-    int16_t num      = 0;
-    int8_t  axis     = 0;
-    bool    internal = false;
-  };
-  vector<node> nodes      = {};
-  vector<int>  primitives = {};
+  vector<bvh_node> nodes      = {};
+  vector<int>      primitives = {};
 };
 
 // Results of intersect_xxx and overlap_xxx functions that include hit flag,

From e69dde3f744c7fb7fe806b0cc3688ea37a559000 Mon Sep 17 00:00:00 2001
From: Fabio Pellacini <fabio.pellacini@gmail.com>
Date: Sun, 7 Aug 2022 10:17:05 +0200
Subject: [PATCH 3/9] updated

---
 libs/yocto/yocto_bvh.cpp   | 104 ++++++++++++++++++++-----------------
 libs/yocto/yocto_bvh.h     |  34 +++++-------
 libs/yocto/yocto_trace.cpp |   4 +-
 3 files changed, 69 insertions(+), 73 deletions(-)

diff --git a/libs/yocto/yocto_bvh.cpp b/libs/yocto/yocto_bvh.cpp
index 03cb9cbad..54ea9ea04 100644
--- a/libs/yocto/yocto_bvh.cpp
+++ b/libs/yocto/yocto_bvh.cpp
@@ -235,15 +235,17 @@ static pair<int, int> split_middle(vector<int>& primitives,
 const int bvh_max_prims = 4;
 
 // Build BVH nodes
-static void build_bvh(vector<bvh_node>& nodes, vector<int>& primitives,
-    const vector<bbox3f>& bboxes, bool highquality) {
+static bvh_tree make_bvh(const vector<bbox3f>& bboxes, bool highquality) {
+  // bvh
+  auto bvh = bvh_tree{};
+
   // prepare to build nodes
-  nodes.clear();
-  nodes.reserve(bboxes.size() * 2);
+  bvh.nodes.clear();
+  bvh.nodes.reserve(bboxes.size() * 2);
 
   // prepare primitives
-  primitives.resize(bboxes.size());
-  for (auto idx : range(bboxes.size())) primitives[idx] = (int)idx;
+  bvh.primitives.resize(bboxes.size());
+  for (auto idx : range(bboxes.size())) bvh.primitives[idx] = (int)idx;
 
   // prepare centers
   auto centers = vector<vec3f>(bboxes.size());
@@ -251,7 +253,7 @@ static void build_bvh(vector<bvh_node>& nodes, vector<int>& primitives,
 
   // push first node onto the stack
   auto stack = vector<vec3i>{{0, 0, (int)bboxes.size()}};
-  nodes.emplace_back();
+  bvh.nodes.emplace_back();
 
   // create nodes until the stack is empty
   while (!stack.empty()) {
@@ -260,27 +262,28 @@ static void build_bvh(vector<bvh_node>& nodes, vector<int>& primitives,
     stack.pop_back();
 
     // grab node
-    auto& node = nodes[nodeid];
+    auto& node = bvh.nodes[nodeid];
 
     // compute bounds
     node.bbox = invalidb3f;
     for (auto i = start; i < end; i++)
-      node.bbox = merge(node.bbox, bboxes[primitives[i]]);
+      node.bbox = merge(node.bbox, bboxes[bvh.primitives[i]]);
 
     // split into two children
     if (end - start > bvh_max_prims) {
       // get split
       auto [mid, axis] =
-          highquality ? split_sah(primitives, bboxes, centers, start, end)
-                      : split_middle(primitives, bboxes, centers, start, end);
+          highquality
+              ? split_sah(bvh.primitives, bboxes, centers, start, end)
+              : split_middle(bvh.primitives, bboxes, centers, start, end);
 
       // make an internal node
       node.internal = true;
       node.axis     = (uint8_t)axis;
       node.num      = 2;
-      node.start    = (int)nodes.size();
-      nodes.emplace_back();
-      nodes.emplace_back();
+      node.start    = (int)bvh.nodes.size();
+      bvh.nodes.emplace_back();
+      bvh.nodes.emplace_back();
       stack.push_back({node.start + 0, start, mid});
       stack.push_back({node.start + 1, mid, end});
     } else {
@@ -292,22 +295,24 @@ static void build_bvh(vector<bvh_node>& nodes, vector<int>& primitives,
   }
 
   // cleanup
-  nodes.shrink_to_fit();
+  bvh.nodes.shrink_to_fit();
+
+  // done
+  return bvh;
 }
 
 // Update bvh
-static void refit_bvh(vector<bvh_node>& nodes, const vector<int>& primitives,
-    const vector<bbox3f>& bboxes) {
-  for (auto nodeid = (int)nodes.size() - 1; nodeid >= 0; nodeid--) {
-    auto& node = nodes[nodeid];
+static void refit_bvh(bvh_tree& bvh, const vector<bbox3f>& bboxes) {
+  for (auto nodeid = (int)bvh.nodes.size() - 1; nodeid >= 0; nodeid--) {
+    auto& node = bvh.nodes[nodeid];
     node.bbox  = invalidb3f;
     if (node.internal) {
       for (auto idx : range(2)) {
-        node.bbox = merge(node.bbox, nodes[node.start + idx].bbox);
+        node.bbox = merge(node.bbox, bvh.nodes[node.start + idx].bbox);
       }
     } else {
       for (auto idx : range(node.num)) {
-        node.bbox = merge(node.bbox, bboxes[primitives[node.start + idx]]);
+        node.bbox = merge(node.bbox, bboxes[bvh.primitives[node.start + idx]]);
       }
     }
   }
@@ -350,10 +355,7 @@ shape_bvh make_shape_bvh(const shape_data& shape, bool highquality) {
   }
 
   // build nodes
-  build_bvh(bvh.nodes, bvh.primitives, bboxes, highquality);
-
-  // done
-  return bvh;
+  return make_bvh(bboxes, highquality);
 }
 
 scene_bvh make_scene_bvh(
@@ -384,7 +386,7 @@ scene_bvh make_scene_bvh(
   }
 
   // build nodes
-  build_bvh(bvh.nodes, bvh.primitives, bboxes, highquality);
+  bvh.instances = make_bvh(bboxes, highquality);
 
   // done
   return bvh;
@@ -423,7 +425,7 @@ void update_shape_bvh(shape_bvh& bvh, const shape_data& shape) {
   }
 
   // update nodes
-  refit_bvh(bvh.nodes, bvh.primitives, bboxes);
+  refit_bvh(bvh, bboxes);
 }
 
 void update_scene_bvh(scene_bvh& bvh, const scene_data& scene,
@@ -442,7 +444,7 @@ void update_scene_bvh(scene_bvh& bvh, const scene_data& scene,
   }
 
   // update nodes
-  refit_bvh(bvh.nodes, bvh.primitives, bboxes);
+  refit_bvh(bvh.instances, bboxes);
 }
 
 }  // namespace yocto
@@ -543,8 +545,11 @@ shape_intersection intersect_shape_bvh(const shape_bvh& bvh,
   return intersection;
 }
 
-scene_intersection intersect_scene_bvh(const scene_bvh& bvh,
+scene_intersection intersect_scene_bvh(const scene_bvh& sbvh,
     const scene_data& scene, const ray3f& ray_, bool find_any) {
+  // get instances bvh
+  auto& bvh = sbvh.instances;
+
   // check empty
   if (bvh.nodes.empty()) return {};
 
@@ -589,7 +594,7 @@ scene_intersection intersect_scene_bvh(const scene_bvh& bvh,
       for (auto idx = node.start; idx < node.start + node.num; idx++) {
         auto& instance_ = scene.instances[bvh.primitives[idx]];
         auto  inv_ray   = transform_ray(inverse(instance_.frame, true), ray);
-        auto  sintersection = intersect_shape_bvh(bvh.shapes[instance_.shape],
+        auto  sintersection = intersect_shape_bvh(sbvh.shapes[instance_.shape],
              scene.shapes[instance_.shape], inv_ray, find_any);
         if (!sintersection.hit) continue;
         intersection = {bvh.primitives[idx], sintersection.element,
@@ -710,9 +715,12 @@ shape_intersection overlap_shape_bvh(const shape_bvh& bvh,
 }
 
 // Intersect ray with a bvh.
-scene_intersection overlap_scene_bvh(const scene_bvh& bvh,
+scene_intersection overlap_scene_bvh(const scene_bvh& sbvh,
     const scene_data& scene, const vec3f& pos, float max_distance,
     bool find_any) {
+  // get instances bvh
+  auto& bvh = sbvh.instances;
+
   // check if empty
   if (bvh.nodes.empty()) return {};
 
@@ -742,11 +750,9 @@ scene_intersection overlap_scene_bvh(const scene_bvh& bvh,
       for (auto idx : range(node.num)) {
         auto  primitive = bvh.primitives[node.start + idx];
         auto& instance_ = scene.instances[primitive];
-        auto& shape     = scene.shapes[instance_.shape];
-        auto& sbvh      = bvh.shapes[instance_.shape];
         auto  inv_pos   = transform_point(inverse(instance_.frame, true), pos);
-        auto  sintersection = overlap_shape_bvh(
-             sbvh, shape, inv_pos, max_distance, find_any);
+        auto  sintersection = overlap_shape_bvh(sbvh.shapes[instance_.shape],
+             scene.shapes[instance_.shape], inv_pos, max_distance, find_any);
         if (!sintersection.hit) continue;
         intersection = {primitive, sintersection.element, sintersection.uv,
             sintersection.distance, true};
@@ -886,9 +892,9 @@ void clear_ebvh(void* ebvh) {
 shape_ebvh make_shape_ebvh(const shape_data& shape, bool highquality) {
   auto bvh     = shape_ebvh{};
   auto edevice = embree_device();
-  bvh.bvh      = unique_ptr<void, void (*)(void*)>{
-           rtcNewScene(edevice), &clear_ebvh};
-  auto escene = (RTCScene)bvh.bvh.get();
+  bvh.ebvh     = unique_ptr<void, void (*)(void*)>{
+          rtcNewScene(edevice), &clear_ebvh};
+  auto escene = (RTCScene)bvh.ebvh.get();
   if (highquality) {
     rtcSetSceneBuildQuality(escene, RTC_BUILD_QUALITY_HIGH);
   } else {
@@ -984,10 +990,10 @@ scene_ebvh make_scene_ebvh(
   }
 
   // scene bvh
-  auto edevice = embree_device();
-  bvh.bvh      = unique_ptr<void, void (*)(void*)>{
-           rtcNewScene(edevice), &clear_ebvh};
-  auto escene = (RTCScene)bvh.bvh.get();
+  auto edevice       = embree_device();
+  bvh.instances.ebvh = unique_ptr<void, void (*)(void*)>{
+      rtcNewScene(edevice), &clear_ebvh};
+  auto escene = (RTCScene)bvh.instances.ebvh.get();
   if (highquality) {
     rtcSetSceneBuildQuality(escene, RTC_BUILD_QUALITY_HIGH);
   } else {
@@ -996,9 +1002,9 @@ scene_ebvh make_scene_ebvh(
   for (auto instance_id = 0; instance_id < (int)scene.instances.size();
        instance_id++) {
     auto& instance  = scene.instances[instance_id];
-    auto& sbvh      = bvh.shapes[instance.shape];
     auto  egeometry = rtcNewGeometry(edevice, RTC_GEOMETRY_TYPE_INSTANCE);
-    rtcSetGeometryInstancedScene(egeometry, (RTCScene)sbvh.bvh.get());
+    rtcSetGeometryInstancedScene(
+        egeometry, (RTCScene)bvh.shapes[instance.shape].ebvh.get());
     rtcSetGeometryTransform(
         egeometry, 0, RTC_FORMAT_FLOAT3X4_COLUMN_MAJOR, &instance.frame);
     rtcCommitGeometry(egeometry);
@@ -1016,12 +1022,12 @@ void update_shape_ebvh(shape_ebvh& bvh, const shape_data& shape) {
 void update_scene_ebvh(scene_ebvh& bvh, const scene_data& scene,
     const vector<int>& updated_instances, const vector<int>& updated_shapes) {
   // scene bvh
-  auto escene = (RTCScene)bvh.bvh.get();
+  auto escene = (RTCScene)bvh.instances.ebvh.get();
   for (auto instance_id : updated_instances) {
     auto& instance    = scene.instances[instance_id];
-    auto& sbvh        = bvh.shapes[instance.shape];
     auto  embree_geom = rtcGetGeometry(escene, instance_id);
-    rtcSetGeometryInstancedScene(embree_geom, (RTCScene)sbvh.bvh.get());
+    rtcSetGeometryInstancedScene(
+        embree_geom, (RTCScene)bvh.shapes[instance.shape].ebvh.get());
     rtcSetGeometryTransform(
         embree_geom, 0, RTC_FORMAT_FLOAT3X4_COLUMN_MAJOR, &instance.frame);
     rtcCommitGeometry(embree_geom);
@@ -1050,7 +1056,7 @@ shape_intersection intersect_shape_ebvh(const shape_ebvh& bvh,
   embree_ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
   RTCIntersectContext embree_ctx;
   rtcInitIntersectContext(&embree_ctx);
-  rtcIntersect1((RTCScene)bvh.bvh.get(), &embree_ctx, &embree_ray);
+  rtcIntersect1((RTCScene)bvh.ebvh.get(), &embree_ctx, &embree_ray);
   if (embree_ray.hit.geomID == RTC_INVALID_GEOMETRY_ID) return {};
   auto element  = (int)embree_ray.hit.primID;
   auto uv       = vec2f{embree_ray.hit.u, embree_ray.hit.v};
@@ -1076,7 +1082,7 @@ scene_intersection intersect_scene_ebvh(const scene_ebvh& bvh,
   embree_ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
   RTCIntersectContext embree_ctx;
   rtcInitIntersectContext(&embree_ctx);
-  rtcIntersect1((RTCScene)bvh.bvh.get(), &embree_ctx, &embree_ray);
+  rtcIntersect1((RTCScene)bvh.instances.ebvh.get(), &embree_ctx, &embree_ray);
   if (embree_ray.hit.geomID == RTC_INVALID_GEOMETRY_ID) return {};
   auto instance = (int)embree_ray.hit.instID[0];
   auto element  = (int)embree_ray.hit.primID;
diff --git a/libs/yocto/yocto_bvh.h b/libs/yocto/yocto_bvh.h
index c1a4b41c7..821042eb7 100644
--- a/libs/yocto/yocto_bvh.h
+++ b/libs/yocto/yocto_bvh.h
@@ -66,24 +66,14 @@ using std::vector;
 // -----------------------------------------------------------------------------
 namespace yocto {
 
-// BVH tree stored as a node array with the tree structure is encoded using
-// array indices. BVH nodes indices refer to either the node array,
-// for internal nodes, or the primitive arrays, for leaf nodes.
-// Application data is not stored explicitly.
-struct shape_bvh {
-  vector<bvh_node> nodes      = {};
-  vector<int>      primitives = {};
-};
+// Shape BVHs are just the bvh for the shape.
+using shape_bvh = bvh_tree;
 
-// BVH tree stored as a node array with the tree structure is encoded using
-// array indices. BVH nodes indices refer to either the node array,
-// for internal nodes, or the primitive arrays, for leaf nodes.
-// We also store the BVH of the contained shapes.
+// Scene BVHs store the bvh for instances and shapes.
 // Application data is not stored explicitly.
 struct scene_bvh {
-  vector<bvh_node>  nodes      = {};
-  vector<int>       primitives = {};
-  vector<shape_bvh> shapes     = {};  // shapes
+  bvh_tree         instances = {};
+  vector<bvh_tree> shapes    = {};
 };
 
 // Build the bvh acceleration structure.
@@ -138,18 +128,18 @@ scene_intersection overlap_scene_bvh(const scene_bvh& bvh,
 // -----------------------------------------------------------------------------
 namespace yocto {
 
-// Intel Embree tree
-using ebvh_tree = unique_ptr<void, void (*)(void*)>;
+// Wrapper for Intel's Embree
+struct ebvh_tree {
+  unique_ptr<void, void (*)(void*)> ebvh = {nullptr, nullptr};
+};
 
 // Wrapper for Intel Embree.
-struct shape_ebvh {
-  unique_ptr<void, void (*)(void*)> bvh = {nullptr, nullptr};  // embree
-};
+using shape_ebvh = ebvh_tree;
 
 // Wrapper for Intel Embree.
 struct scene_ebvh {
-  vector<shape_ebvh>                shapes = {};                  // shapes
-  unique_ptr<void, void (*)(void*)> bvh    = {nullptr, nullptr};  // embree
+  ebvh_tree         instances = {};  // instances
+  vector<ebvh_tree> shapes    = {};  // shapes
 };
 
 // Check if embree is supported
diff --git a/libs/yocto/yocto_trace.cpp b/libs/yocto/yocto_trace.cpp
index fb0b8501f..2c3a664f8 100644
--- a/libs/yocto/yocto_trace.cpp
+++ b/libs/yocto/yocto_trace.cpp
@@ -98,7 +98,7 @@ trace_bvh make_trace_bvh(const scene_data& scene, const trace_params& params) {
 // Ray-intersection shortcuts
 static scene_intersection intersect_scene(const trace_bvh& bvh,
     const scene_data& scene, const ray3f& ray, bool find_any = false) {
-  if (bvh.ebvh.bvh) {
+  if (bvh.ebvh.instances.ebvh) {
     return intersect_scene_ebvh(bvh.ebvh, scene, ray, find_any);
   } else {
     return intersect_scene_bvh(bvh.bvh, scene, ray, find_any);
@@ -107,7 +107,7 @@ static scene_intersection intersect_scene(const trace_bvh& bvh,
 static scene_intersection intersect_instance(const trace_bvh& bvh,
     const scene_data& scene, int instance, const ray3f& ray,
     bool find_any = false) {
-  if (bvh.ebvh.bvh) {
+  if (bvh.ebvh.instances.ebvh) {
     return intersect_instance_ebvh(bvh.ebvh, scene, instance, ray, find_any);
   } else {
     return intersect_instance_bvh(bvh.bvh, scene, instance, ray, find_any);

From ff1c8f6f671de89df284045c7cda302459520094 Mon Sep 17 00:00:00 2001
From: Fabio Pellacini <fabio.pellacini@gmail.com>
Date: Sun, 7 Aug 2022 10:19:40 +0200
Subject: [PATCH 4/9] updated

---
 libs/yocto/yocto_shape.cpp | 91 ++++++++++++++++++--------------------
 1 file changed, 43 insertions(+), 48 deletions(-)

diff --git a/libs/yocto/yocto_shape.cpp b/libs/yocto/yocto_shape.cpp
index 8d52d97e4..a144bd3e7 100644
--- a/libs/yocto/yocto_shape.cpp
+++ b/libs/yocto/yocto_shape.cpp
@@ -1159,16 +1159,16 @@ shape_data make_cube(float scale, int subdivisions) {
       {+1, +1, +1}, {+1, +1, -1}, {-1, +1, -1}, {+1, -1, +1}, {-1, -1, +1},
       {-1, -1, -1}, {+1, -1, -1}};
   static const auto cube_normals   = vector<vec3f>{{0, 0, +1}, {0, 0, +1},
-      {0, 0, +1}, {0, 0, +1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
-      {+1, 0, 0}, {+1, 0, 0}, {+1, 0, 0}, {+1, 0, 0}, {-1, 0, 0}, {-1, 0, 0},
-      {-1, 0, 0}, {-1, 0, 0}, {0, +1, 0}, {0, +1, 0}, {0, +1, 0}, {0, +1, 0},
-      {0, -1, 0}, {0, -1, 0}, {0, -1, 0}, {0, -1, 0}};
+        {0, 0, +1}, {0, 0, +1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
+        {+1, 0, 0}, {+1, 0, 0}, {+1, 0, 0}, {+1, 0, 0}, {-1, 0, 0}, {-1, 0, 0},
+        {-1, 0, 0}, {-1, 0, 0}, {0, +1, 0}, {0, +1, 0}, {0, +1, 0}, {0, +1, 0},
+        {0, -1, 0}, {0, -1, 0}, {0, -1, 0}, {0, -1, 0}};
   static const auto cube_texcoords = vector<vec2f>{{0, 1}, {1, 1}, {1, 0},
       {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0},
       {0, 1}, {1, 1}, {1, 0}, {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}, {0, 1},
       {1, 1}, {1, 0}, {0, 0}};
   static const auto cube_quads     = vector<vec4i>{{0, 1, 2, 3}, {4, 5, 6, 7},
-      {8, 9, 10, 11}, {12, 13, 14, 15}, {16, 17, 18, 19}, {20, 21, 22, 23}};
+          {8, 9, 10, 11}, {12, 13, 14, 15}, {16, 17, 18, 19}, {20, 21, 22, 23}};
 
   auto shape = shape_data{};
   if (subdivisions == 0) {
@@ -1194,16 +1194,16 @@ fvshape_data make_fvcube(float scale, int subdivisions) {
       {+1, +1, +1}, {-1, +1, +1}, {+1, -1, -1}, {-1, -1, -1}, {-1, +1, -1},
       {+1, +1, -1}};
   static const auto fvcube_normals   = vector<vec3f>{{0, 0, +1}, {0, 0, +1},
-      {0, 0, +1}, {0, 0, +1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
-      {+1, 0, 0}, {+1, 0, 0}, {+1, 0, 0}, {+1, 0, 0}, {-1, 0, 0}, {-1, 0, 0},
-      {-1, 0, 0}, {-1, 0, 0}, {0, +1, 0}, {0, +1, 0}, {0, +1, 0}, {0, +1, 0},
-      {0, -1, 0}, {0, -1, 0}, {0, -1, 0}, {0, -1, 0}};
+        {0, 0, +1}, {0, 0, +1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
+        {+1, 0, 0}, {+1, 0, 0}, {+1, 0, 0}, {+1, 0, 0}, {-1, 0, 0}, {-1, 0, 0},
+        {-1, 0, 0}, {-1, 0, 0}, {0, +1, 0}, {0, +1, 0}, {0, +1, 0}, {0, +1, 0},
+        {0, -1, 0}, {0, -1, 0}, {0, -1, 0}, {0, -1, 0}};
   static const auto fvcube_texcoords = vector<vec2f>{{0, 1}, {1, 1}, {1, 0},
       {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0},
       {0, 1}, {1, 1}, {1, 0}, {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}, {0, 1},
       {1, 1}, {1, 0}, {0, 0}};
   static const auto fvcube_quadspos  = vector<vec4i>{{0, 1, 2, 3}, {4, 5, 6, 7},
-      {1, 4, 7, 2}, {5, 0, 3, 6}, {3, 2, 7, 6}, {1, 0, 5, 4}};
+       {1, 4, 7, 2}, {5, 0, 3, 6}, {3, 2, 7, 6}, {1, 0, 5, 4}};
   static const auto fvcube_quadsnorm = vector<vec4i>{{0, 1, 2, 3}, {4, 5, 6, 7},
       {8, 9, 10, 11}, {12, 13, 14, 15}, {16, 17, 18, 19}, {20, 21, 22, 23}};
   static const auto fvcube_quadstexcoord = vector<vec4i>{{0, 1, 2, 3},
@@ -2046,14 +2046,13 @@ static pair<int, int> split_middle(vector<int>& primitives,
 const int bvh_max_prims = 4;
 
 // Build BVH nodes
-static void build_bvh(bvh_tree& bvh, vector<bbox3f>& bboxes) {
-  // get values
-  auto& nodes      = bvh.nodes;
-  auto& primitives = bvh.primitives;
+static bvh_tree make_bvh(vector<bbox3f>& bboxes) {
+  // bvh
+  auto bvh = bvh_tree{};
 
   // prepare to build nodes
-  nodes.clear();
-  nodes.reserve(bboxes.size() * 2);
+  bvh.nodes.clear();
+  bvh.nodes.reserve(bboxes.size() * 2);
 
   // prepare primitives
   bvh.primitives.resize(bboxes.size());
@@ -2065,7 +2064,7 @@ static void build_bvh(bvh_tree& bvh, vector<bbox3f>& bboxes) {
 
   // queue up first node
   auto queue = deque<vec3i>{{0, 0, (int)bboxes.size()}};
-  nodes.emplace_back();
+  bvh.nodes.emplace_back();
 
   // create nodes until the queue is empty
   while (!queue.empty()) {
@@ -2075,25 +2074,26 @@ static void build_bvh(bvh_tree& bvh, vector<bbox3f>& bboxes) {
     auto nodeid = next.x, start = next.y, end = next.z;
 
     // grab node
-    auto& node = nodes[nodeid];
+    auto& node = bvh.nodes[nodeid];
 
     // compute bounds
     node.bbox = invalidb3f;
     for (auto i = start; i < end; i++)
-      node.bbox = merge(node.bbox, bboxes[primitives[i]]);
+      node.bbox = merge(node.bbox, bboxes[bvh.primitives[i]]);
 
     // split into two children
     if (end - start > bvh_max_prims) {
       // get split
-      auto [mid, axis] = split_middle(primitives, bboxes, centers, start, end);
+      auto [mid, axis] = split_middle(
+          bvh.primitives, bboxes, centers, start, end);
 
       // make an internal node
       node.internal = true;
       node.axis     = (int8_t)axis;
       node.num      = 2;
-      node.start    = (int)nodes.size();
-      nodes.emplace_back();
-      nodes.emplace_back();
+      node.start    = (int)bvh.nodes.size();
+      bvh.nodes.emplace_back();
+      bvh.nodes.emplace_back();
       queue.push_back({node.start + 0, start, mid});
       queue.push_back({node.start + 1, mid, end});
     } else {
@@ -2105,7 +2105,10 @@ static void build_bvh(bvh_tree& bvh, vector<bbox3f>& bboxes) {
   }
 
   // cleanup
-  nodes.shrink_to_fit();
+  bvh.nodes.shrink_to_fit();
+
+  // done
+  return bvh;
 }
 
 // Update bvh
@@ -2136,9 +2139,7 @@ bvh_tree make_points_bvh(const vector<int>& points,
   }
 
   // build nodes
-  auto bvh = bvh_tree{};
-  build_bvh(bvh, bboxes);
-  return bvh;
+  return make_bvh(bboxes);
 }
 bvh_tree make_lines_bvh(const vector<vec2i>& lines,
     const vector<vec3f>& positions, const vector<float>& radius) {
@@ -2151,9 +2152,7 @@ bvh_tree make_lines_bvh(const vector<vec2i>& lines,
   }
 
   // build nodes
-  auto bvh = bvh_tree{};
-  build_bvh(bvh, bboxes);
-  return bvh;
+  return make_bvh(bboxes);
 }
 bvh_tree make_triangles_bvh(const vector<vec3i>& triangles,
     const vector<vec3f>& positions, const vector<float>& radius) {
@@ -2166,9 +2165,7 @@ bvh_tree make_triangles_bvh(const vector<vec3i>& triangles,
   }
 
   // build nodes
-  auto bvh = bvh_tree{};
-  build_bvh(bvh, bboxes);
-  return bvh;
+  return make_bvh(bboxes);
 }
 bvh_tree make_quads_bvh(const vector<vec4i>& quads,
     const vector<vec3f>& positions, const vector<float>& radius) {
@@ -2181,9 +2178,7 @@ bvh_tree make_quads_bvh(const vector<vec4i>& quads,
   }
 
   // build nodes
-  auto bvh = bvh_tree{};
-  build_bvh(bvh, bboxes);
-  return bvh;
+  return make_bvh(bboxes);
 }
 
 void update_points_bvh(bvh_tree& bvh, const vector<int>& points,
@@ -3769,8 +3764,8 @@ void make_bezier_circle(
   // constant from http://spencermortensen.com/articles/bezier-circle/
   const auto  c              = 0.551915024494f;
   static auto circle_pos     = vector<vec3f>{{1, 0, 0}, {1, c, 0}, {c, 1, 0},
-      {0, 1, 0}, {-c, 1, 0}, {-1, c, 0}, {-1, 0, 0}, {-1, -c, 0}, {-c, -1, 0},
-      {0, -1, 0}, {c, -1, 0}, {1, -c, 0}};
+          {0, 1, 0}, {-c, 1, 0}, {-1, c, 0}, {-1, 0, 0}, {-1, -c, 0}, {-c, -1, 0},
+          {0, -1, 0}, {c, -1, 0}, {1, -c, 0}};
   static auto circle_beziers = vector<vec4i>{
       {0, 1, 2, 3}, {3, 4, 5, 6}, {6, 7, 8, 9}, {9, 10, 11, 0}};
   positions = circle_pos;
@@ -3892,16 +3887,16 @@ void make_cube(vector<vec4i>& quads, vector<vec3f>& positions,
       {+1, +1, +1}, {+1, +1, -1}, {-1, +1, -1}, {+1, -1, +1}, {-1, -1, +1},
       {-1, -1, -1}, {+1, -1, -1}};
   static const auto cube_normals   = vector<vec3f>{{0, 0, +1}, {0, 0, +1},
-      {0, 0, +1}, {0, 0, +1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
-      {+1, 0, 0}, {+1, 0, 0}, {+1, 0, 0}, {+1, 0, 0}, {-1, 0, 0}, {-1, 0, 0},
-      {-1, 0, 0}, {-1, 0, 0}, {0, +1, 0}, {0, +1, 0}, {0, +1, 0}, {0, +1, 0},
-      {0, -1, 0}, {0, -1, 0}, {0, -1, 0}, {0, -1, 0}};
+        {0, 0, +1}, {0, 0, +1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
+        {+1, 0, 0}, {+1, 0, 0}, {+1, 0, 0}, {+1, 0, 0}, {-1, 0, 0}, {-1, 0, 0},
+        {-1, 0, 0}, {-1, 0, 0}, {0, +1, 0}, {0, +1, 0}, {0, +1, 0}, {0, +1, 0},
+        {0, -1, 0}, {0, -1, 0}, {0, -1, 0}, {0, -1, 0}};
   static const auto cube_texcoords = vector<vec2f>{{0, 1}, {1, 1}, {1, 0},
       {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0},
       {0, 1}, {1, 1}, {1, 0}, {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}, {0, 1},
       {1, 1}, {1, 0}, {0, 0}};
   static const auto cube_quads     = vector<vec4i>{{0, 1, 2, 3}, {4, 5, 6, 7},
-      {8, 9, 10, 11}, {12, 13, 14, 15}, {16, 17, 18, 19}, {20, 21, 22, 23}};
+          {8, 9, 10, 11}, {12, 13, 14, 15}, {16, 17, 18, 19}, {20, 21, 22, 23}};
   if (subdivisions == 0) {
     quads     = cube_quads;
     positions = cube_positions;
@@ -3928,16 +3923,16 @@ void make_fvcube(vector<vec4i>& quadspos, vector<vec4i>& quadsnorm,
       {+1, +1, +1}, {-1, +1, +1}, {+1, -1, -1}, {-1, -1, -1}, {-1, +1, -1},
       {+1, +1, -1}};
   static const auto fvcube_normals   = vector<vec3f>{{0, 0, +1}, {0, 0, +1},
-      {0, 0, +1}, {0, 0, +1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
-      {+1, 0, 0}, {+1, 0, 0}, {+1, 0, 0}, {+1, 0, 0}, {-1, 0, 0}, {-1, 0, 0},
-      {-1, 0, 0}, {-1, 0, 0}, {0, +1, 0}, {0, +1, 0}, {0, +1, 0}, {0, +1, 0},
-      {0, -1, 0}, {0, -1, 0}, {0, -1, 0}, {0, -1, 0}};
+        {0, 0, +1}, {0, 0, +1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
+        {+1, 0, 0}, {+1, 0, 0}, {+1, 0, 0}, {+1, 0, 0}, {-1, 0, 0}, {-1, 0, 0},
+        {-1, 0, 0}, {-1, 0, 0}, {0, +1, 0}, {0, +1, 0}, {0, +1, 0}, {0, +1, 0},
+        {0, -1, 0}, {0, -1, 0}, {0, -1, 0}, {0, -1, 0}};
   static const auto fvcube_texcoords = vector<vec2f>{{0, 1}, {1, 1}, {1, 0},
       {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0},
       {0, 1}, {1, 1}, {1, 0}, {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}, {0, 1},
       {1, 1}, {1, 0}, {0, 0}};
   static const auto fvcube_quadspos  = vector<vec4i>{{0, 1, 2, 3}, {4, 5, 6, 7},
-      {1, 4, 7, 2}, {5, 0, 3, 6}, {3, 2, 7, 6}, {1, 0, 5, 4}};
+       {1, 4, 7, 2}, {5, 0, 3, 6}, {3, 2, 7, 6}, {1, 0, 5, 4}};
   static const auto fvcube_quadsnorm = vector<vec4i>{{0, 1, 2, 3}, {4, 5, 6, 7},
       {8, 9, 10, 11}, {12, 13, 14, 15}, {16, 17, 18, 19}, {20, 21, 22, 23}};
   static const auto fvcube_quadstexcoord = vector<vec4i>{{0, 1, 2, 3},

From 9992a4e74e1afdad575b904c8cd23c1287af0590 Mon Sep 17 00:00:00 2001
From: Fabio Pellacini <fabio.pellacini@gmail.com>
Date: Sun, 7 Aug 2022 10:42:44 +0200
Subject: [PATCH 5/9] updated

---
 libs/yocto/yocto_bvh.cpp | 115 +++++++++++++++++++++------------------
 libs/yocto/yocto_bvh.h   |   8 ++-
 2 files changed, 67 insertions(+), 56 deletions(-)

diff --git a/libs/yocto/yocto_bvh.cpp b/libs/yocto/yocto_bvh.cpp
index 54ea9ea04..ff4af3f71 100644
--- a/libs/yocto/yocto_bvh.cpp
+++ b/libs/yocto/yocto_bvh.cpp
@@ -320,7 +320,7 @@ static void refit_bvh(bvh_tree& bvh, const vector<bbox3f>& bboxes) {
 
 shape_bvh make_shape_bvh(const shape_data& shape, bool highquality) {
   // bvh
-  auto bvh = shape_bvh{};
+  auto sbvh = shape_bvh{};
 
   // build primitives
   auto bboxes = vector<bbox3f>{};
@@ -355,23 +355,26 @@ shape_bvh make_shape_bvh(const shape_data& shape, bool highquality) {
   }
 
   // build nodes
-  return make_bvh(bboxes, highquality);
+  sbvh.bvh = make_bvh(bboxes, highquality);
+
+  // done
+  return sbvh;
 }
 
 scene_bvh make_scene_bvh(
     const scene_data& scene, bool highquality, bool noparallel) {
   // bvh
-  auto bvh = scene_bvh{};
+  auto sbvh = scene_bvh{};
 
   // build shape bvh
-  bvh.shapes.resize(scene.shapes.size());
+  sbvh.shapes.resize(scene.shapes.size());
   if (noparallel) {
     for (auto idx : range(scene.shapes.size())) {
-      bvh.shapes[idx] = make_shape_bvh(scene.shapes[idx], highquality);
+      sbvh.shapes[idx] = make_shape_bvh(scene.shapes[idx], highquality);
     }
   } else {
     parallel_for(scene.shapes.size(), [&](size_t idx) {
-      bvh.shapes[idx] = make_shape_bvh(scene.shapes[idx], highquality);
+      sbvh.shapes[idx] = make_shape_bvh(scene.shapes[idx], highquality);
     });
   }
 
@@ -379,20 +382,20 @@ scene_bvh make_scene_bvh(
   auto bboxes = vector<bbox3f>(scene.instances.size());
   for (auto idx : range(bboxes.size())) {
     auto& instance = scene.instances[idx];
-    auto& sbvh     = bvh.shapes[instance.shape];
-    bboxes[idx]    = sbvh.nodes.empty()
+    bboxes[idx]    = sbvh.shapes[instance.shape].bvh.nodes.empty()
                          ? invalidb3f
-                         : transform_bbox(instance.frame, sbvh.nodes[0].bbox);
+                         : transform_bbox(instance.frame,
+                               sbvh.shapes[instance.shape].bvh.nodes[0].bbox);
   }
 
   // build nodes
-  bvh.instances = make_bvh(bboxes, highquality);
+  sbvh.bvh = make_bvh(bboxes, highquality);
 
   // done
-  return bvh;
+  return sbvh;
 }
 
-void update_shape_bvh(shape_bvh& bvh, const shape_data& shape) {
+void update_shape_bvh(shape_bvh& sbvh, const shape_data& shape) {
   // build primitives
   auto bboxes = vector<bbox3f>{};
   if (!shape.points.empty()) {
@@ -425,26 +428,26 @@ void update_shape_bvh(shape_bvh& bvh, const shape_data& shape) {
   }
 
   // update nodes
-  refit_bvh(bvh, bboxes);
+  refit_bvh(sbvh.bvh, bboxes);
 }
 
-void update_scene_bvh(scene_bvh& bvh, const scene_data& scene,
+void update_scene_bvh(scene_bvh& sbvh, const scene_data& scene,
     const vector<int>& updated_instances, const vector<int>& updated_shapes) {
   // update shapes
   for (auto shape : updated_shapes) {
-    update_shape_bvh(bvh.shapes[shape], scene.shapes[shape]);
+    update_shape_bvh(sbvh.shapes[shape], scene.shapes[shape]);
   }
 
   // handle instances
   auto bboxes = vector<bbox3f>(scene.instances.size());
   for (auto idx : range(bboxes.size())) {
     auto& instance = scene.instances[idx];
-    auto& sbvh     = bvh.shapes[instance.shape];
-    bboxes[idx]    = transform_bbox(instance.frame, sbvh.nodes[0].bbox);
+    bboxes[idx]    = transform_bbox(
+           instance.frame, sbvh.shapes[instance.shape].bvh.nodes[0].bbox);
   }
 
   // update nodes
-  refit_bvh(bvh.instances, bboxes);
+  refit_bvh(sbvh.bvh, bboxes);
 }
 
 }  // namespace yocto
@@ -454,8 +457,11 @@ void update_scene_bvh(scene_bvh& bvh, const scene_data& scene,
 // -----------------------------------------------------------------------------
 namespace yocto {
 
-shape_intersection intersect_shape_bvh(const shape_bvh& bvh,
+shape_intersection intersect_shape_bvh(const shape_bvh& sbvh,
     const shape_data& shape, const ray3f& ray_, bool find_any) {
+  // get bvh tree
+  auto& bvh = sbvh.bvh;
+
   // check empty
   if (bvh.nodes.empty()) return {};
 
@@ -548,7 +554,7 @@ shape_intersection intersect_shape_bvh(const shape_bvh& bvh,
 scene_intersection intersect_scene_bvh(const scene_bvh& sbvh,
     const scene_data& scene, const ray3f& ray_, bool find_any) {
   // get instances bvh
-  auto& bvh = sbvh.instances;
+  auto& bvh = sbvh.bvh;
 
   // check empty
   if (bvh.nodes.empty()) return {};
@@ -610,11 +616,11 @@ scene_intersection intersect_scene_bvh(const scene_bvh& sbvh,
   return intersection;
 }
 
-scene_intersection intersect_instance_bvh(const scene_bvh& bvh,
+scene_intersection intersect_instance_bvh(const scene_bvh& sbvh,
     const scene_data& scene, int instance_, const ray3f& ray, bool find_any) {
   auto& instance     = scene.instances[instance_];
   auto  inv_ray      = transform_ray(inverse(instance.frame, true), ray);
-  auto  intersection = intersect_shape_bvh(bvh.shapes[instance.shape],
+  auto  intersection = intersect_shape_bvh(sbvh.shapes[instance.shape],
        scene.shapes[instance.shape], inv_ray, find_any);
   if (!intersection.hit) return {};
   return {instance_, intersection.element, intersection.uv,
@@ -629,9 +635,12 @@ scene_intersection intersect_instance_bvh(const scene_bvh& bvh,
 namespace yocto {
 
 // Intersect ray with a bvh.
-shape_intersection overlap_shape_bvh(const shape_bvh& bvh,
+shape_intersection overlap_shape_bvh(const shape_bvh& sbvh,
     const shape_data& shape, const vec3f& pos, float max_distance,
     bool find_any) {
+  // get bvh tree
+  auto& bvh = sbvh.bvh;
+
   // check if empty
   if (bvh.nodes.empty()) return {};
 
@@ -719,7 +728,7 @@ scene_intersection overlap_scene_bvh(const scene_bvh& sbvh,
     const scene_data& scene, const vec3f& pos, float max_distance,
     bool find_any) {
   // get instances bvh
-  auto& bvh = sbvh.instances;
+  auto& bvh = sbvh.bvh;
 
   // check if empty
   if (bvh.nodes.empty()) return {};
@@ -890,11 +899,11 @@ void clear_ebvh(void* ebvh) {
 
 // Build the bvh acceleration structure.
 shape_ebvh make_shape_ebvh(const shape_data& shape, bool highquality) {
-  auto bvh     = shape_ebvh{};
+  auto sbvh    = shape_ebvh{};
   auto edevice = embree_device();
-  bvh.ebvh     = unique_ptr<void, void (*)(void*)>{
-          rtcNewScene(edevice), &clear_ebvh};
-  auto escene = (RTCScene)bvh.ebvh.get();
+  sbvh.ebvh    = unique_ptr<void, void (*)(void*)>{
+         rtcNewScene(edevice), &clear_ebvh};
+  auto escene = (RTCScene)sbvh.ebvh.get();
   if (highquality) {
     rtcSetSceneBuildQuality(escene, RTC_BUILD_QUALITY_HIGH);
   } else {
@@ -969,31 +978,31 @@ shape_ebvh make_shape_ebvh(const shape_data& shape, bool highquality) {
     throw std::runtime_error("empty shapes not supported");
   }
   rtcCommitScene(escene);
-  return bvh;
+  return sbvh;
 }
 
 scene_ebvh make_scene_ebvh(
     const scene_data& scene, bool highquality, bool noparallel) {
   // scene bvh
-  auto bvh = scene_ebvh{};
+  auto sbvh = scene_ebvh{};
 
   // shape bvhs
-  bvh.shapes.resize(scene.shapes.size());
+  sbvh.shapes.resize(scene.shapes.size());
   if (noparallel) {
     for (auto idx : range(scene.shapes.size())) {
-      bvh.shapes[idx] = make_shape_ebvh(scene.shapes[idx], highquality);
+      sbvh.shapes[idx] = make_shape_ebvh(scene.shapes[idx], highquality);
     }
   } else {
     parallel_for(scene.shapes.size(), [&](size_t idx) {
-      bvh.shapes[idx] = make_shape_ebvh(scene.shapes[idx], highquality);
+      sbvh.shapes[idx] = make_shape_ebvh(scene.shapes[idx], highquality);
     });
   }
 
   // scene bvh
-  auto edevice       = embree_device();
-  bvh.instances.ebvh = unique_ptr<void, void (*)(void*)>{
+  auto edevice        = embree_device();
+  sbvh.instances.ebvh = unique_ptr<void, void (*)(void*)>{
       rtcNewScene(edevice), &clear_ebvh};
-  auto escene = (RTCScene)bvh.instances.ebvh.get();
+  auto escene = (RTCScene)sbvh.instances.ebvh.get();
   if (highquality) {
     rtcSetSceneBuildQuality(escene, RTC_BUILD_QUALITY_HIGH);
   } else {
@@ -1004,7 +1013,7 @@ scene_ebvh make_scene_ebvh(
     auto& instance  = scene.instances[instance_id];
     auto  egeometry = rtcNewGeometry(edevice, RTC_GEOMETRY_TYPE_INSTANCE);
     rtcSetGeometryInstancedScene(
-        egeometry, (RTCScene)bvh.shapes[instance.shape].ebvh.get());
+        egeometry, (RTCScene)sbvh.shapes[instance.shape].ebvh.get());
     rtcSetGeometryTransform(
         egeometry, 0, RTC_FORMAT_FLOAT3X4_COLUMN_MAJOR, &instance.frame);
     rtcCommitGeometry(egeometry);
@@ -1012,22 +1021,22 @@ scene_ebvh make_scene_ebvh(
     rtcReleaseGeometry(egeometry);
   }
   rtcCommitScene(escene);
-  return bvh;
+  return sbvh;
 }
 
 // Refit bvh data
-void update_shape_ebvh(shape_ebvh& bvh, const shape_data& shape) {
+void update_shape_ebvh(shape_ebvh& sbvh, const shape_data& shape) {
   throw embree_error{"feature not supported"};
 }
-void update_scene_ebvh(scene_ebvh& bvh, const scene_data& scene,
+void update_scene_ebvh(scene_ebvh& sbvh, const scene_data& scene,
     const vector<int>& updated_instances, const vector<int>& updated_shapes) {
   // scene bvh
-  auto escene = (RTCScene)bvh.instances.ebvh.get();
+  auto escene = (RTCScene)sbvh.instances.ebvh.get();
   for (auto instance_id : updated_instances) {
     auto& instance    = scene.instances[instance_id];
     auto  embree_geom = rtcGetGeometry(escene, instance_id);
     rtcSetGeometryInstancedScene(
-        embree_geom, (RTCScene)bvh.shapes[instance.shape].ebvh.get());
+        embree_geom, (RTCScene)sbvh.shapes[instance.shape].ebvh.get());
     rtcSetGeometryTransform(
         embree_geom, 0, RTC_FORMAT_FLOAT3X4_COLUMN_MAJOR, &instance.frame);
     rtcCommitGeometry(embree_geom);
@@ -1038,7 +1047,7 @@ void update_scene_ebvh(scene_ebvh& bvh, const scene_data& scene,
 // Intersect ray with a bvh returning either the first or any intersection
 // depending on `find_any`. Returns the ray distance , the instance id,
 // the shape element index and the element barycentric coordinates.
-shape_intersection intersect_shape_ebvh(const shape_ebvh& bvh,
+shape_intersection intersect_shape_ebvh(const shape_ebvh& sbvh,
     const shape_data& shape, const ray3f& ray, bool find_any) {
   RTCRayHit embree_ray;
   embree_ray.ray.org_x     = ray.o.x;
@@ -1056,7 +1065,7 @@ shape_intersection intersect_shape_ebvh(const shape_ebvh& bvh,
   embree_ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
   RTCIntersectContext embree_ctx;
   rtcInitIntersectContext(&embree_ctx);
-  rtcIntersect1((RTCScene)bvh.ebvh.get(), &embree_ctx, &embree_ray);
+  rtcIntersect1((RTCScene)sbvh.ebvh.get(), &embree_ctx, &embree_ray);
   if (embree_ray.hit.geomID == RTC_INVALID_GEOMETRY_ID) return {};
   auto element  = (int)embree_ray.hit.primID;
   auto uv       = vec2f{embree_ray.hit.u, embree_ray.hit.v};
@@ -1064,7 +1073,7 @@ shape_intersection intersect_shape_ebvh(const shape_ebvh& bvh,
   return {element, uv, distance, true};
 }
 
-scene_intersection intersect_scene_ebvh(const scene_ebvh& bvh,
+scene_intersection intersect_scene_ebvh(const scene_ebvh& sbvh,
     const scene_data& scene, const ray3f& ray, bool find_any) {
   RTCRayHit embree_ray;
   embree_ray.ray.org_x     = ray.o.x;
@@ -1082,7 +1091,7 @@ scene_intersection intersect_scene_ebvh(const scene_ebvh& bvh,
   embree_ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
   RTCIntersectContext embree_ctx;
   rtcInitIntersectContext(&embree_ctx);
-  rtcIntersect1((RTCScene)bvh.instances.ebvh.get(), &embree_ctx, &embree_ray);
+  rtcIntersect1((RTCScene)sbvh.instances.ebvh.get(), &embree_ctx, &embree_ray);
   if (embree_ray.hit.geomID == RTC_INVALID_GEOMETRY_ID) return {};
   auto instance = (int)embree_ray.hit.instID[0];
   auto element  = (int)embree_ray.hit.primID;
@@ -1091,11 +1100,11 @@ scene_intersection intersect_scene_ebvh(const scene_ebvh& bvh,
   return {instance, element, uv, distance, true};
 }
 
-scene_intersection intersect_instance_ebvh(const scene_ebvh& bvh,
+scene_intersection intersect_instance_ebvh(const scene_ebvh& sbvh,
     const scene_data& scene, int instance_, const ray3f& ray, bool find_any) {
   auto& instance     = scene.instances[instance_];
   auto  inv_ray      = transform_ray(inverse(instance.frame, true), ray);
-  auto  intersection = intersect_shape_ebvh(bvh.shapes[instance.shape],
+  auto  intersection = intersect_shape_ebvh(sbvh.shapes[instance.shape],
        scene.shapes[instance.shape], inv_ray, find_any);
   if (!intersection.hit) return {};
   return {instance_, intersection.element, intersection.uv,
@@ -1117,24 +1126,24 @@ scene_ebvh make_scene_ebvh(
 }
 
 // Not implemented
-void update_shape_ebvh(shape_ebvh& bvh, const shape_data& shape) {
+void update_shape_ebvh(shape_ebvh& sbvh, const shape_data& shape) {
   throw embree_error{"Embree not available"};
 }
-void update_scene_ebvh(scene_ebvh& bvh, const scene_data& scene,
+void update_scene_ebvh(scene_ebvh& sbvh, const scene_data& scene,
     const vector<int>& updated_instances, const vector<int>& updated_shapes) {
   throw embree_error{"Embree not available"};
 }
 
 // Not implemented
-shape_intersection intersect_shape_ebvh(const shape_ebvh& bvh,
+shape_intersection intersect_shape_ebvh(const shape_ebvh& sbvh,
     const shape_data& shape, const ray3f& ray, bool find_any) {
   throw embree_error{"Embree not available"};
 }
-scene_intersection intersect_scene_ebvh(const scene_ebvh& bvh,
+scene_intersection intersect_scene_ebvh(const scene_ebvh& sbvh,
     const scene_data& scene, const ray3f& ray, bool find_any) {
   throw embree_error{"Embree not available"};
 }
-scene_intersection intersect_instance_ebvh(const scene_ebvh& bvh,
+scene_intersection intersect_instance_ebvh(const scene_ebvh& sbvh,
     const scene_data& scene, int instance, const ray3f& ray, bool find_any) {
   throw embree_error{"Embree not available"};
 }
diff --git a/libs/yocto/yocto_bvh.h b/libs/yocto/yocto_bvh.h
index 821042eb7..d97f19cbb 100644
--- a/libs/yocto/yocto_bvh.h
+++ b/libs/yocto/yocto_bvh.h
@@ -67,13 +67,15 @@ using std::vector;
 namespace yocto {
 
 // Shape BVHs are just the bvh for the shape.
-using shape_bvh = bvh_tree;
+struct shape_bvh {
+  bvh_tree bvh = {};
+};
 
 // Scene BVHs store the bvh for instances and shapes.
 // Application data is not stored explicitly.
 struct scene_bvh {
-  bvh_tree         instances = {};
-  vector<bvh_tree> shapes    = {};
+  bvh_tree          bvh    = {};
+  vector<shape_bvh> shapes = {};
 };
 
 // Build the bvh acceleration structure.

From d38fb4f3516d604fcd072f484fc1e10ac86c4a90 Mon Sep 17 00:00:00 2001
From: Fabio Pellacini <fabio.pellacini@gmail.com>
Date: Sun, 7 Aug 2022 10:44:46 +0200
Subject: [PATCH 6/9] updated

---
 libs/yocto/yocto_bvh.cpp   | 12 ++++++------
 libs/yocto/yocto_bvh.h     | 12 ++++++------
 libs/yocto/yocto_trace.cpp |  4 ++--
 3 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/libs/yocto/yocto_bvh.cpp b/libs/yocto/yocto_bvh.cpp
index ff4af3f71..38e6c51de 100644
--- a/libs/yocto/yocto_bvh.cpp
+++ b/libs/yocto/yocto_bvh.cpp
@@ -999,10 +999,10 @@ scene_ebvh make_scene_ebvh(
   }
 
   // scene bvh
-  auto edevice        = embree_device();
-  sbvh.instances.ebvh = unique_ptr<void, void (*)(void*)>{
-      rtcNewScene(edevice), &clear_ebvh};
-  auto escene = (RTCScene)sbvh.instances.ebvh.get();
+  auto edevice = embree_device();
+  sbvh.ebvh    = unique_ptr<void, void (*)(void*)>{
+         rtcNewScene(edevice), &clear_ebvh};
+  auto escene = (RTCScene)sbvh.ebvh.get();
   if (highquality) {
     rtcSetSceneBuildQuality(escene, RTC_BUILD_QUALITY_HIGH);
   } else {
@@ -1031,7 +1031,7 @@ void update_shape_ebvh(shape_ebvh& sbvh, const shape_data& shape) {
 void update_scene_ebvh(scene_ebvh& sbvh, const scene_data& scene,
     const vector<int>& updated_instances, const vector<int>& updated_shapes) {
   // scene bvh
-  auto escene = (RTCScene)sbvh.instances.ebvh.get();
+  auto escene = (RTCScene)sbvh.ebvh.get();
   for (auto instance_id : updated_instances) {
     auto& instance    = scene.instances[instance_id];
     auto  embree_geom = rtcGetGeometry(escene, instance_id);
@@ -1091,7 +1091,7 @@ scene_intersection intersect_scene_ebvh(const scene_ebvh& sbvh,
   embree_ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
   RTCIntersectContext embree_ctx;
   rtcInitIntersectContext(&embree_ctx);
-  rtcIntersect1((RTCScene)sbvh.instances.ebvh.get(), &embree_ctx, &embree_ray);
+  rtcIntersect1((RTCScene)sbvh.ebvh.get(), &embree_ctx, &embree_ray);
   if (embree_ray.hit.geomID == RTC_INVALID_GEOMETRY_ID) return {};
   auto instance = (int)embree_ray.hit.instID[0];
   auto element  = (int)embree_ray.hit.primID;
diff --git a/libs/yocto/yocto_bvh.h b/libs/yocto/yocto_bvh.h
index d97f19cbb..1fe6cffc4 100644
--- a/libs/yocto/yocto_bvh.h
+++ b/libs/yocto/yocto_bvh.h
@@ -131,17 +131,17 @@ scene_intersection overlap_scene_bvh(const scene_bvh& bvh,
 namespace yocto {
 
 // Wrapper for Intel's Embree
-struct ebvh_tree {
-  unique_ptr<void, void (*)(void*)> ebvh = {nullptr, nullptr};
-};
+using ebvh_tree = unique_ptr<void, void (*)(void*)>;
 
 // Wrapper for Intel Embree.
-using shape_ebvh = ebvh_tree;
+struct shape_ebvh {
+  ebvh_tree ebvh = {nullptr, nullptr};
+};
 
 // Wrapper for Intel Embree.
 struct scene_ebvh {
-  ebvh_tree         instances = {};  // instances
-  vector<ebvh_tree> shapes    = {};  // shapes
+  ebvh_tree          ebvh   = {nullptr, nullptr};  // instances
+  vector<shape_ebvh> shapes = {};                  // shapes
 };
 
 // Check if embree is supported
diff --git a/libs/yocto/yocto_trace.cpp b/libs/yocto/yocto_trace.cpp
index 2c3a664f8..82d049b06 100644
--- a/libs/yocto/yocto_trace.cpp
+++ b/libs/yocto/yocto_trace.cpp
@@ -98,7 +98,7 @@ trace_bvh make_trace_bvh(const scene_data& scene, const trace_params& params) {
 // Ray-intersection shortcuts
 static scene_intersection intersect_scene(const trace_bvh& bvh,
     const scene_data& scene, const ray3f& ray, bool find_any = false) {
-  if (bvh.ebvh.instances.ebvh) {
+  if (bvh.ebvh.ebvh) {
     return intersect_scene_ebvh(bvh.ebvh, scene, ray, find_any);
   } else {
     return intersect_scene_bvh(bvh.bvh, scene, ray, find_any);
@@ -107,7 +107,7 @@ static scene_intersection intersect_scene(const trace_bvh& bvh,
 static scene_intersection intersect_instance(const trace_bvh& bvh,
     const scene_data& scene, int instance, const ray3f& ray,
     bool find_any = false) {
-  if (bvh.ebvh.instances.ebvh) {
+  if (bvh.ebvh.ebvh) {
     return intersect_instance_ebvh(bvh.ebvh, scene, instance, ray, find_any);
   } else {
     return intersect_instance_bvh(bvh.bvh, scene, instance, ray, find_any);

From 72b93f2e192c47fbe7661d9733efbd2ec05261f6 Mon Sep 17 00:00:00 2001
From: Fabio Pellacini <fabio.pellacini@gmail.com>
Date: Sun, 7 Aug 2022 15:06:23 +0200
Subject: [PATCH 7/9] updated

---
 libs/yocto/yocto_cutrace.cpp | 44 ++++++++++++++++++------------------
 libs/yocto/yocto_cutrace.h   | 31 +++++++++++++------------
 2 files changed, 38 insertions(+), 37 deletions(-)

diff --git a/libs/yocto/yocto_cutrace.cpp b/libs/yocto/yocto_cutrace.cpp
index 1097f1f63..c9ba31518 100644
--- a/libs/yocto/yocto_cutrace.cpp
+++ b/libs/yocto/yocto_cutrace.cpp
@@ -223,22 +223,22 @@ cuscene_data::~cuscene_data() {
   clear_buffer(environments);
 };
 
-cubvh_data::cubvh_data(cubvh_data&& other) {
+cuscene_bvh::cuscene_bvh(cuscene_bvh&& other) {
   instances.swap(other.instances);
-  shapes_bvhs.swap(other.shapes_bvhs);
-  instances_bvh.buffer.swap(other.instances_bvh.buffer);
-  std::swap(instances_bvh.handle, other.instances_bvh.handle);
+  shapes.swap(other.shapes);
+  bvh.buffer.swap(other.bvh.buffer);
+  std::swap(bvh.handle, other.bvh.handle);
 }
-cubvh_data& cubvh_data::operator=(cubvh_data&& other) {
+cuscene_bvh& cuscene_bvh::operator=(cuscene_bvh&& other) {
   instances.swap(other.instances);
-  shapes_bvhs.swap(other.shapes_bvhs);
-  instances_bvh.buffer.swap(other.instances_bvh.buffer);
-  std::swap(instances_bvh.handle, other.instances_bvh.handle);
+  shapes.swap(other.shapes);
+  bvh.buffer.swap(other.bvh.buffer);
+  std::swap(bvh.handle, other.bvh.handle);
   return *this;
 }
-cubvh_data::~cubvh_data() {
-  for (auto& shape_bvh : shapes_bvhs) {
-    clear_buffer(shape_bvh.buffer);
+cuscene_bvh::~cuscene_bvh() {
+  for (auto& bvh : shapes) {
+    clear_buffer(bvh.buffer);
     // TODO: bvh
   }
   clear_buffer(instances);
@@ -505,7 +505,7 @@ cutrace_context make_cutrace_context(const trace_params& params) {
 
 // start a new render
 void trace_start(cutrace_context& context, cutrace_state& state,
-    const cuscene_data& cuscene, const cubvh_data& bvh,
+    const cuscene_data& cuscene, const cuscene_bvh& bvh,
     const cutrace_lights& lights, const scene_data& scene,
     const trace_params& params) {
   auto globals = cutrace_globals{};
@@ -514,7 +514,7 @@ void trace_start(cutrace_context& context, cutrace_state& state,
   update_buffer_value(context.cuda_stream, context.globals_buffer,
       offsetof(cutrace_globals, scene), cuscene);
   update_buffer_value(context.cuda_stream, context.globals_buffer,
-      offsetof(cutrace_globals, bvh), bvh.instances_bvh.handle);
+      offsetof(cutrace_globals, bvh), bvh.bvh.handle);
   update_buffer_value(context.cuda_stream, context.globals_buffer,
       offsetof(cutrace_globals, lights), lights);
   update_buffer_value(context.cuda_stream, context.globals_buffer,
@@ -525,7 +525,7 @@ void trace_start(cutrace_context& context, cutrace_state& state,
 
 // render a batch of samples
 void trace_samples(cutrace_context& context, cutrace_state& state,
-    const cuscene_data& cuscene, const cubvh_data& bvh,
+    const cuscene_data& cuscene, const cuscene_bvh& bvh,
     const cutrace_lights& lights, const scene_data& scene,
     const trace_params& params) {
   if (state.samples >= params.samples) return;
@@ -700,9 +700,9 @@ void update_cutrace_cameras(cutrace_context& context, cuscene_data& cuscene,
   sync_gpu(context.cuda_stream);
 }
 
-cubvh_data make_cutrace_bvh(cutrace_context& context, const cuscene_data& scene,
-    const trace_params& params) {
-  auto bvh = cubvh_data{};
+cutrace_bvh make_cutrace_bvh(cutrace_context& context,
+    const cuscene_data& scene, const trace_params& params) {
+  auto bvh = cutrace_bvh{};
 
   // download shapes and instances
   // this is not efficient, but keeps the API very clean
@@ -711,7 +711,7 @@ cubvh_data make_cutrace_bvh(cutrace_context& context, const cuscene_data& scene,
   auto instances_data = download_buffer_vector(scene.instances);
 
   // shapes
-  bvh.shapes_bvhs.resize(scene.shapes.size());
+  bvh.shapes.resize(scene.shapes.size());
   for (auto shape_id = (size_t)0; shape_id < scene.shapes.size(); shape_id++) {
     auto& shape = shapes_data[shape_id];
 
@@ -757,7 +757,7 @@ cubvh_data make_cutrace_bvh(cutrace_context& context, const cuscene_data& scene,
         context.cuda_stream, accelerator_sizes.tempSizeInBytes, (byte*)nullptr);
     auto  bvh_buffer = make_buffer(context.cuda_stream,
          accelerator_sizes.outputSizeInBytes, (byte*)nullptr);
-    auto& sbvh       = bvh.shapes_bvhs[shape_id];
+    auto& sbvh       = bvh.shapes[shape_id];
     check_result(optixAccelBuild(context.optix_context,
         /* cuda_stream */ 0, &accelerator_options, &built_input, (int)1,
         temporary_buffer.device_ptr(), temporary_buffer.size_in_bytes(),
@@ -796,7 +796,7 @@ cubvh_data make_cutrace_bvh(cutrace_context& context, const cuscene_data& scene,
       memcpy(opinstance.transform, &transform, sizeof(float) * 12);
       opinstance.sbtOffset         = 0;
       opinstance.instanceId        = instance_id;
-      opinstance.traversableHandle = bvh.shapes_bvhs[instance.shape].handle;
+      opinstance.traversableHandle = bvh.shapes[instance.shape].handle;
       opinstance.flags             = OPTIX_INSTANCE_FLAG_NONE;
       opinstance.visibilityMask    = 0xff;
     }
@@ -830,7 +830,7 @@ cubvh_data make_cutrace_bvh(cutrace_context& context, const cuscene_data& scene,
     auto bvh_buffer = make_buffer(context.cuda_stream,
         accelerator_sizes.outputSizeInBytes, (byte*)nullptr);
 
-    auto& ibvh = bvh.instances_bvh;
+    auto& ibvh = bvh.bvh;
     check_result(optixAccelBuild(context.optix_context,
         /* cuda_stream */ 0, &accelerator_options, &build_input, (int)1,
         temporary_buffer.device_ptr(), temporary_buffer.size_in_bytes(),
@@ -979,7 +979,7 @@ image_data cutrace_image(const scene_data& scene, const trace_params& params) {
 
 // render preview
 void trace_preview(image_data& image, cutrace_context& context,
-    cutrace_state& pstate, const cuscene_data& cuscene, const cubvh_data& bvh,
+    cutrace_state& pstate, const cuscene_data& cuscene, const cutrace_bvh& bvh,
     const cutrace_lights& lights, const scene_data& scene,
     const trace_params& params) {
   auto pparams = params;
diff --git a/libs/yocto/yocto_cutrace.h b/libs/yocto/yocto_cutrace.h
index d373d44ef..27302365a 100644
--- a/libs/yocto/yocto_cutrace.h
+++ b/libs/yocto/yocto_cutrace.h
@@ -79,10 +79,11 @@ namespace yocto {
 
 // forward declarations
 struct cuscene_data;
-struct cubvh_data;
+struct cuscene_bvh;
 struct cutrace_state;
 struct cutrace_lights;
 struct cutrace_context;
+using cutrace_bvh = cuscene_bvh;
 
 // Initialize GPU context.
 cutrace_context make_cutrace_context(const trace_params& params);
@@ -94,7 +95,7 @@ void update_cutrace_cameras(cutrace_context& context, cuscene_data& cuscene,
     const scene_data& scene, const trace_params& params);
 
 // Build the bvh acceleration structure.
-cubvh_data make_cutrace_bvh(cutrace_context& context,
+cutrace_bvh make_cutrace_bvh(cutrace_context& context,
     const cuscene_data& cuscene, const trace_params& params);
 
 // Initialize state.
@@ -109,18 +110,18 @@ cutrace_lights make_cutrace_lights(cutrace_context& context,
 
 // Start rendering an image.
 void trace_start(cutrace_context& context, cutrace_state& state,
-    const cuscene_data& cuscene, const cubvh_data& bvh,
+    const cuscene_data& cuscene, const cutrace_bvh& bvh,
     const cutrace_lights& lights, const scene_data& scene,
     const trace_params& params);
 
 // Progressively computes an image.
 void trace_samples(cutrace_context& context, cutrace_state& state,
-    const cuscene_data& cuscene, const cubvh_data& bvh,
+    const cuscene_data& cuscene, const cutrace_bvh& bvh,
     const cutrace_lights& lights, const scene_data& scene,
     const trace_params& params);
 
 void trace_preview(image_data& image, cutrace_context& context,
-    cutrace_state& pstate, const cuscene_data& cuscene, const cubvh_data& bvh,
+    cutrace_state& pstate, const cuscene_data& cuscene, const cutrace_bvh& bvh,
     const cutrace_lights& lights, const scene_data& scene,
     const trace_params& params);
 
@@ -191,8 +192,8 @@ struct cuspan {
   CUdeviceptr device_ptr() const { return _data; }
   size_t      size_in_bytes() const { return _size * sizeof(T); }
   void        swap(cuspan& other) {
-    std::swap(_data, other._data);
-    std::swap(_size, other._size);
+           std::swap(_data, other._data);
+           std::swap(_size, other._size);
   }
 
   CUdeviceptr _data = 0;
@@ -283,15 +284,15 @@ struct cubvh_tree {
   OptixTraversableHandle handle = 0;
 };
 
-struct cubvh_data {
-  cuspan<OptixInstance> instances     = {};
-  cubvh_tree            instances_bvh = {};
-  vector<cubvh_tree>    shapes_bvhs   = {};
+struct cuscene_bvh {
+  cubvh_tree            bvh       = {};
+  vector<cubvh_tree>    shapes    = {};
+  cuspan<OptixInstance> instances = {};
 
-  cubvh_data() {}
-  cubvh_data(cubvh_data&&);
-  cubvh_data& operator=(cubvh_data&&);
-  ~cubvh_data();
+  cuscene_bvh() {}
+  cuscene_bvh(cuscene_bvh&&);
+  cuscene_bvh& operator=(cuscene_bvh&&);
+  ~cuscene_bvh();
 };
 
 // state

From 1f9c4ddccb48c1cea3717e417304ab4aa4135160 Mon Sep 17 00:00:00 2001
From: Fabio Pellacini <fabio.pellacini@gmail.com>
Date: Sun, 7 Aug 2022 15:13:23 +0200
Subject: [PATCH 8/9] updated

---
 libs/yocto/yocto_cutrace.cpp | 23 ++++++++++++++---------
 libs/yocto/yocto_cutrace.h   | 11 ++++++++++-
 2 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/libs/yocto/yocto_cutrace.cpp b/libs/yocto/yocto_cutrace.cpp
index c9ba31518..eaaa828eb 100644
--- a/libs/yocto/yocto_cutrace.cpp
+++ b/libs/yocto/yocto_cutrace.cpp
@@ -223,6 +223,17 @@ cuscene_data::~cuscene_data() {
   clear_buffer(environments);
 };
 
+cushape_bvh::cushape_bvh(cushape_bvh&& other) {
+  bvh.buffer.swap(other.bvh.buffer);
+  std::swap(bvh.handle, other.bvh.handle);
+}
+cushape_bvh& cushape_bvh::operator=(cushape_bvh&& other) {
+  bvh.buffer.swap(other.bvh.buffer);
+  std::swap(bvh.handle, other.bvh.handle);
+  return *this;
+}
+cushape_bvh::~cushape_bvh() { clear_buffer(bvh.buffer); }
+
 cuscene_bvh::cuscene_bvh(cuscene_bvh&& other) {
   instances.swap(other.instances);
   shapes.swap(other.shapes);
@@ -236,13 +247,7 @@ cuscene_bvh& cuscene_bvh::operator=(cuscene_bvh&& other) {
   std::swap(bvh.handle, other.bvh.handle);
   return *this;
 }
-cuscene_bvh::~cuscene_bvh() {
-  for (auto& bvh : shapes) {
-    clear_buffer(bvh.buffer);
-    // TODO: bvh
-  }
-  clear_buffer(instances);
-}
+cuscene_bvh::~cuscene_bvh() { clear_buffer(instances); }
 
 cutrace_context::cutrace_context(cutrace_context&& other) {
   std::swap(denoiser, other.denoiser);
@@ -757,7 +762,7 @@ cutrace_bvh make_cutrace_bvh(cutrace_context& context,
         context.cuda_stream, accelerator_sizes.tempSizeInBytes, (byte*)nullptr);
     auto  bvh_buffer = make_buffer(context.cuda_stream,
          accelerator_sizes.outputSizeInBytes, (byte*)nullptr);
-    auto& sbvh       = bvh.shapes[shape_id];
+    auto& sbvh       = bvh.shapes[shape_id].bvh;
     check_result(optixAccelBuild(context.optix_context,
         /* cuda_stream */ 0, &accelerator_options, &built_input, (int)1,
         temporary_buffer.device_ptr(), temporary_buffer.size_in_bytes(),
@@ -796,7 +801,7 @@ cutrace_bvh make_cutrace_bvh(cutrace_context& context,
       memcpy(opinstance.transform, &transform, sizeof(float) * 12);
       opinstance.sbtOffset         = 0;
       opinstance.instanceId        = instance_id;
-      opinstance.traversableHandle = bvh.shapes[instance.shape].handle;
+      opinstance.traversableHandle = bvh.shapes[instance.shape].bvh.handle;
       opinstance.flags             = OPTIX_INSTANCE_FLAG_NONE;
       opinstance.visibilityMask    = 0xff;
     }
diff --git a/libs/yocto/yocto_cutrace.h b/libs/yocto/yocto_cutrace.h
index 27302365a..ba62c7b2e 100644
--- a/libs/yocto/yocto_cutrace.h
+++ b/libs/yocto/yocto_cutrace.h
@@ -284,9 +284,18 @@ struct cubvh_tree {
   OptixTraversableHandle handle = 0;
 };
 
+struct cushape_bvh {
+  cubvh_tree bvh = {};
+
+  cushape_bvh() {}
+  cushape_bvh(cushape_bvh&&);
+  cushape_bvh& operator=(cushape_bvh&&);
+  ~cushape_bvh();
+};
+
 struct cuscene_bvh {
   cubvh_tree            bvh       = {};
-  vector<cubvh_tree>    shapes    = {};
+  vector<cushape_bvh>   shapes    = {};
   cuspan<OptixInstance> instances = {};
 
   cuscene_bvh() {}

From 38e7d2106760d7aed590a309d7871bfcfea99ece Mon Sep 17 00:00:00 2001
From: Fabio Pellacini <fabio.pellacini@gmail.com>
Date: Sun, 7 Aug 2022 15:21:40 +0200
Subject: [PATCH 9/9] updated

---
 libs/yocto/yocto_cutrace.cpp | 13 ++++++++++++-
 libs/yocto/yocto_cutrace.h   |  5 +++++
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/libs/yocto/yocto_cutrace.cpp b/libs/yocto/yocto_cutrace.cpp
index eaaa828eb..b31459695 100644
--- a/libs/yocto/yocto_cutrace.cpp
+++ b/libs/yocto/yocto_cutrace.cpp
@@ -223,6 +223,17 @@ cuscene_data::~cuscene_data() {
   clear_buffer(environments);
 };
 
+cubvh_tree::cubvh_tree(cubvh_tree&& other) {
+  buffer.swap(other.buffer);
+  std::swap(handle, other.handle);
+}
+cubvh_tree& cubvh_tree::operator=(cubvh_tree&& other) {
+  buffer.swap(other.buffer);
+  std::swap(handle, other.handle);
+  return *this;
+}
+cubvh_tree::~cubvh_tree() { clear_buffer(buffer); }
+
 cushape_bvh::cushape_bvh(cushape_bvh&& other) {
   bvh.buffer.swap(other.bvh.buffer);
   std::swap(bvh.handle, other.bvh.handle);
@@ -232,7 +243,7 @@ cushape_bvh& cushape_bvh::operator=(cushape_bvh&& other) {
   std::swap(bvh.handle, other.bvh.handle);
   return *this;
 }
-cushape_bvh::~cushape_bvh() { clear_buffer(bvh.buffer); }
+cushape_bvh::~cushape_bvh() {}
 
 cuscene_bvh::cuscene_bvh(cuscene_bvh&& other) {
   instances.swap(other.instances);
diff --git a/libs/yocto/yocto_cutrace.h b/libs/yocto/yocto_cutrace.h
index ba62c7b2e..779384ba5 100644
--- a/libs/yocto/yocto_cutrace.h
+++ b/libs/yocto/yocto_cutrace.h
@@ -282,6 +282,11 @@ struct cuscene_data {
 struct cubvh_tree {
   cuspan<byte>           buffer = {};
   OptixTraversableHandle handle = 0;
+
+  cubvh_tree() {}
+  cubvh_tree(cubvh_tree&&);
+  cubvh_tree& operator=(cubvh_tree&&);
+  ~cubvh_tree();
 };
 
 struct cushape_bvh {