commit ceeb6fbd3b03e0f196f53ef98a18ab5624c80392
parent fb9d5d84b79d4946dd228416f53c13eb53eb70f3
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Fri, 18 Jan 2019 09:52:16 +0100
Use Embree3 rather than Embree2 as RT backend
No test is performed yet: only compilation is OK on GNU/Linux.
Diffstat:
11 files changed, 517 insertions(+), 274 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -27,7 +27,7 @@
# knowledge of the CeCILL license and that you accept its terms.
cmake_minimum_required(VERSION 2.8)
-project(star-2d C CXX)
+project(star-2d C)
enable_testing()
set(S2D_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src)
@@ -36,18 +36,22 @@ option(NO_TEST "Disable the test" OFF)
################################################################################
# Check dependencies
################################################################################
-find_package(Embree 2.9 REQUIRED)
+find_package(Embree 3 REQUIRED)
find_package(RCMake 0.2.2 REQUIRED)
find_package(RSys 0.6.0 REQUIRED)
+
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${RCMAKE_SOURCE_DIR})
include(rcmake)
include(rcmake_runtime)
-message(STATUS ${EMBREE_INCLUDE_DIRS})
include_directories(${EMBREE_INCLUDE_DIRS} ${RSys_INCLUDE_DIR})
rcmake_append_runtime_dirs(_runtime_dirs RSys Embree)
+if(CMAKE_COMPILER_IS_GNUCC)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")
+endif()
+
################################################################################
# Configure and define targets
################################################################################
@@ -80,10 +84,9 @@ rcmake_prepend_path(S2D_FILES_SRC ${S2D_SOURCE_DIR})
rcmake_prepend_path(S2D_FILES_INC ${S2D_SOURCE_DIR})
rcmake_prepend_path(S2D_FILES_INC_API ${S2D_SOURCE_DIR})
rcmake_prepend_path(S2D_FILES_DOC ${PROJECT_SOURCE_DIR}/../)
-set_source_files_properties(${S2D_FILES_SRC} PROPERTIES LANGUAGE CXX)
add_library(s2d SHARED ${S2D_FILES_SRC} ${S2D_FILES_INC} ${S2D_FILES_INC_API})
-target_link_libraries(s2d RSys ${EMBREE_LIBRARY})
+target_link_libraries(s2d RSys ${EMBREE_LIBRARIES})
if(CMAKE_COMPILER_IS_GNUCC)
target_link_libraries(s2d m)
@@ -99,17 +102,9 @@ endif()
set_target_properties(s2d PROPERTIES
DEFINE_SYMBOL S2D_SHARED_BUILD
- LINKER_LANGUAGE CXX
VERSION ${VERSION}
SOVERSION ${VERSION_MAJOR})
-if(CMAKE_COMPILER_IS_GNUCXX)
- # Shut up the use of variadic macros by Embree and the use of long long
- # constants by RSys
- set_target_properties(s2d PROPERTIES
- COMPILE_FLAGS "-Wno-variadic-macros -Wno-long-long")
-endif()
-
rcmake_setup_devel(s2d Star2D ${VERSION} star/s2d_version.h)
################################################################################
@@ -146,7 +141,7 @@ if(NOT NO_TEST)
new_test(test_s2d_scene_view2)
new_test(test_s2d_trace_ray)
new_test(test_s2d_trace_ray_3d)
-
+
rcmake_copy_runtime_libraries(test_s2d_device)
endif(NOT NO_TEST)
diff --git a/src/s2d.h b/src/s2d.h
@@ -231,6 +231,11 @@ s2d_scene_get_device
(struct s2d_scene* scn,
struct s2d_device** dev);
+S2D_API res_T
+s2d_scene_get_shapes_count
+ (struct s2d_scene* scn,
+ size_t* nshapes);
+
/*******************************************************************************
* Scene view API - State of the scene geometry
******************************************************************************/
diff --git a/src/s2d_backend.h b/src/s2d_backend.h
@@ -35,21 +35,14 @@
#include <rsys/rsys.h>
-#ifdef COMPILER_GCC
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wpedantic"
- #pragma GCC diagnostic ignored "-Wsign-compare"
-#elif defined(COMPILER_CL)
+#ifdef COMPILER_CL
#pragma warning(push)
- #pragma warning(disable:4324) /* Structure was padded due to alignment */
+/* #pragma warning(disable:4324)*/ /* Structure was padded due to alignment */
#endif
-#include <embree2/rtcore.h>
-#include <embree2/rtcore_ray.h>
+#include <embree3/rtcore.h>
-#ifdef COMPILER_GCC
- #pragma GCC diagnostic pop
-#elif defined(COMPILER_CL)
+#ifdef COMPILER_CL
#pragma warning(pop)
#endif
diff --git a/src/s2d_buffer.h b/src/s2d_buffer.h
@@ -49,7 +49,7 @@
#define BUFFER_DARRAY_FUNC__(Func) CONCAT(CONCAT(BUFFER_DARRAY, _), Func)
struct BUFFER_NAME {
- BUFFER_DARRAY data;
+ struct BUFFER_DARRAY data;
struct mem_allocator* allocator;
ref_T ref;
};
diff --git a/src/s2d_c.h b/src/s2d_c.h
@@ -30,9 +30,42 @@
#define S2D_C_H
#include "s2d.h"
+#include "s2d_backend.h"
#include <rsys/rsys.h>
+static FINLINE res_T
+rtc_error_to_res_T(const enum RTCError err)
+{
+ switch(err) {
+ case RTC_ERROR_NONE: return RES_OK;
+ case RTC_ERROR_UNKNOWN: return RES_UNKNOWN_ERR;
+ case RTC_ERROR_INVALID_ARGUMENT: return RES_BAD_ARG;
+ case RTC_ERROR_INVALID_OPERATION: return RES_BAD_ARG;
+ case RTC_ERROR_OUT_OF_MEMORY: return RES_MEM_ERR;
+ case RTC_ERROR_UNSUPPORTED_CPU: return RES_BAD_ARG;
+ case RTC_ERROR_CANCELLED: return RES_UNKNOWN_ERR;
+ default: FATAL("Unreachable code\n"); break;
+ }
+}
+
+static INLINE const char*
+rtc_error_string(const enum RTCError err)
+{
+ const char* str = NULL;
+ switch(err) {
+ case RTC_ERROR_NONE: str = "No error"; break;
+ case RTC_ERROR_UNKNOWN: str = "Unknown error"; break;
+ case RTC_ERROR_INVALID_ARGUMENT: str = "Invalid argument"; break;
+ case RTC_ERROR_INVALID_OPERATION: str = "Invalid operation"; break;
+ case RTC_ERROR_OUT_OF_MEMORY: str = "Out of memory"; break;
+ case RTC_ERROR_UNSUPPORTED_CPU: str = "Unsupported CPU"; break;
+ case RTC_ERROR_CANCELLED: str = "Cancelled operation"; break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+ return str;
+}
+
static INLINE unsigned
s2d_type_get_dimension(const enum s2d_type type)
{
@@ -44,5 +77,99 @@ s2d_type_get_dimension(const enum s2d_type type)
}
}
-#endif /* S2D_C_H */
+#define RAYN_GRAB(RayN, N, i, Type, Attr) \
+ (((Type*)((char*)(RayN)+(offsetof(struct RTCRay, Attr)*N)))[i])
+#define HITN_GRAB(HitN, N, i, Type, Attr) \
+ (((Type*)((char*)(HitN)+(offsetof(struct RTCHit, Attr)*N)))[i])
+#define RAYHITN_GET_RAYN(RayHitN, N) \
+ ((struct RTCRayN*)((char*)RayHitN+offsetof(struct RTCRayHit, ray)*N))
+#define RAYHITN_GET_HITN(RayHitN, N) \
+ ((struct RTCHitN*)((char*)RayHitN+offsetof(struct RTCRayHit, hit)*N))
+
+static FINLINE void
+rtc_rayN_get_ray
+ (const struct RTCRayN* rayN, /* SoA layout */
+ const size_t N, /* SoA width */
+ const size_t i, /* Id of the ray */
+ struct RTCRay* ray)
+{
+ ASSERT(rayN && ray && i < N);
+ ray->org_x = RAYN_GRAB(rayN, N, i, float, org_x);
+ ray->org_y = RAYN_GRAB(rayN, N, i, float, org_y);
+ ray->org_z = RAYN_GRAB(rayN, N, i, float, org_z);
+ ray->tnear = RAYN_GRAB(rayN, N, i, float, tnear);
+ ray->dir_x = RAYN_GRAB(rayN, N, i, float, dir_x);
+ ray->dir_y = RAYN_GRAB(rayN, N, i, float, dir_y);
+ ray->dir_z = RAYN_GRAB(rayN, N, i, float, dir_z);
+ ray->time = RAYN_GRAB(rayN, N, i, float, time);
+ ray->tfar = RAYN_GRAB(rayN, N, i, float, tfar);
+ ray->mask = RAYN_GRAB(rayN, N, i, unsigned, mask);
+ ray->id = RAYN_GRAB(rayN, N, i, unsigned, id);
+ ray->flags = RAYN_GRAB(rayN, N, i, unsigned, flags);
+}
+static FINLINE void
+rtc_hitN_get_hit
+ (const struct RTCHitN* hitN,
+ const size_t N,
+ const size_t i,
+ struct RTCHit* hit)
+{
+ size_t id;
+ ASSERT(hitN && hit && i < N);
+ hit->Ng_x = HITN_GRAB(hitN, N, i, float, Ng_x);
+ hit->Ng_y = HITN_GRAB(hitN, N, i, float, Ng_y);
+ hit->Ng_z = HITN_GRAB(hitN, N, i, float, Ng_z);
+ hit->u = HITN_GRAB(hitN, N, i, float, u);
+ hit->v = HITN_GRAB(hitN, N, i, float, v);
+ hit->primID = HITN_GRAB(hitN, N, i, unsigned, primID);
+ hit->geomID = HITN_GRAB(hitN, N, i, unsigned, geomID);
+ FOR_EACH(id, 0, RTC_MAX_INSTANCE_LEVEL_COUNT) {
+ hit->instID[id] = HITN_GRAB(hitN, N, i, unsigned, instID[id]);
+ }
+}
+
+static FINLINE void
+rtc_rayN_set_ray
+ (struct RTCRayN* rayN,
+ const size_t N,
+ const size_t i,
+ const struct RTCRay* ray)
+{
+ ASSERT(rayN && ray && i < N);
+ RAYN_GRAB(rayN, N, i, float, org_x) = ray->org_x;
+ RAYN_GRAB(rayN, N, i, float, org_y) = ray->org_y;
+ RAYN_GRAB(rayN, N, i, float, org_z) = ray->org_z;
+ RAYN_GRAB(rayN, N, i, float, tnear) = ray->tnear;
+ RAYN_GRAB(rayN, N, i, float, dir_x) = ray->dir_x;
+ RAYN_GRAB(rayN, N, i, float, dir_y) = ray->dir_y;
+ RAYN_GRAB(rayN, N, i, float, dir_z) = ray->dir_z;
+ RAYN_GRAB(rayN, N, i, float, time) = ray->time;
+ RAYN_GRAB(rayN, N, i, float, tfar) = ray->tfar;
+ RAYN_GRAB(rayN, N, i, unsigned, mask) = ray->mask;
+ RAYN_GRAB(rayN, N, i, unsigned, id) = ray->id;
+ RAYN_GRAB(rayN, N, i, unsigned, flags) = ray->flags;
+}
+
+static FINLINE void
+rtc_hitN_set_hit
+ (const struct RTCHitN* hitN,
+ const size_t N,
+ const size_t i,
+ struct RTCHit* hit)
+{
+ size_t id;
+ ASSERT(hitN && hit && i < N);
+ HITN_GRAB(hitN, N, i, float, Ng_x) = hit->Ng_x;
+ HITN_GRAB(hitN, N, i, float, Ng_y) = hit->Ng_y;
+ HITN_GRAB(hitN, N, i, float, Ng_z) = hit->Ng_z;
+ HITN_GRAB(hitN, N, i, float, u) = hit->u;
+ HITN_GRAB(hitN, N, i, float, v) = hit->v;
+ HITN_GRAB(hitN, N, i, unsigned, primID) = hit->primID;
+ HITN_GRAB(hitN, N, i, unsigned, geomID) = hit->geomID;
+ FOR_EACH(id, 0, RTC_MAX_INSTANCE_LEVEL_COUNT) {
+ HITN_GRAB(hitN, N, i, unsigned, instID[id]) = hit->instID[id];
+ }
+}
+
+#endif /* S2D_C_H */
diff --git a/src/s2d_device.c b/src/s2d_device.c
@@ -27,6 +27,7 @@
* knowledge of the CeCILL license and that you accept its terms. */
#include "s2d.h"
+#include "s2d_c.h"
#include "s2d_device_c.h"
#include <rsys/logger.h>
@@ -36,6 +37,15 @@
* Helper functions
******************************************************************************/
static INLINE void
+rtc_error_func(void* context, enum RTCError err, const char* str)
+{
+ char msg[128];
+ (void)str, (void)err, (void)context;
+ snprintf(msg, sizeof(msg), "Embree:error: %s\n", rtc_error_string(err));
+ FATAL(msg);
+}
+
+static INLINE void
log_msg
(struct s2d_device* dev,
const enum log_type stream,
@@ -56,8 +66,9 @@ device_release(ref_T* ref)
struct s2d_device* dev;
ASSERT(ref);
dev = CONTAINER_OF(ref, struct s2d_device, ref);
+ ASSERT(flist_name_is_empty(&dev->names) == 1);
flist_name_release(&dev->names);
- rtcDeleteDevice(dev->rtc);
+ rtcReleaseDevice(dev->rtc);
MEM_RM(dev->allocator, dev);
}
@@ -91,7 +102,19 @@ s2d_device_create
dev->verbose = verbose;
flist_name_init(allocator, &dev->names);
ref_init(&dev->ref);
+
dev->rtc = rtcNewDevice(verbose ? "verbose=1" : NULL);
+ if(dev->rtc == NULL) {
+ const enum RTCError err = rtcGetDeviceError(NULL);
+ log_error(dev, "Could not create the embree device -- %s.\n",
+ rtc_error_string(err));
+ res = rtc_error_to_res_T(err);
+ goto error;
+ }
+
+#ifndef NDEBUG
+ rtcSetDeviceErrorFunction(dev->rtc, rtc_error_func, dev);
+#endif
exit:
if(out_dev) *out_dev = dev;
diff --git a/src/s2d_geometry.c b/src/s2d_geometry.c
@@ -68,7 +68,8 @@ geometry_create(struct s2d_device* dev, struct geometry** out_geom)
S2D(device_ref_get(dev));
geom->dev = dev;
geom->name = S2D_INVALID_ID;
- geom->irtc = RTC_INVALID_GEOMETRY_ID;
+ geom->rtc = NULL;
+ geom->rtc_id = RTC_INVALID_GEOMETRY_ID;
geom->embree_outdated_mask = 0;
geom->flip_contour = 0;
geom->is_enabled = 1;
diff --git a/src/s2d_geometry.h b/src/s2d_geometry.h
@@ -43,7 +43,8 @@ enum embree_attrib {
/* Backend geometry */
struct geometry {
unsigned name; /* Client side identifier */
- unsigned irtc; /* Backend identifier */
+ RTCGeometry rtc; /* Embree geometry */
+ unsigned rtc_id; /* Embree geometry identifier */
unsigned scene_prim_id_offset; /* Offset from local to scene prim_id */
int embree_outdated_mask; /* Combination of embree_attrib */
diff --git a/src/s2d_primitive.c b/src/s2d_primitive.c
@@ -146,7 +146,7 @@ s2d_primitive_sample
}
res_T
-s2d_primitive_compute_length(const s2d_primitive* prim, float* length)
+s2d_primitive_compute_length(const struct s2d_primitive* prim, float* length)
{
const uint32_t* ids;
const float* pos;
diff --git a/src/s2d_scene_view.c b/src/s2d_scene_view.c
@@ -27,6 +27,7 @@
* knowledge of the CeCILL license and that you accept its terms. */
#include "s2d.h"
+#include "s2d_c.h"
#include "s2d_device_c.h"
#include "s2d_line_segments.h"
#include "s2d_geometry.h"
@@ -34,48 +35,67 @@
#include "s2d_scene_view_c.h"
#include "s2d_shape_c.h"
+#include <rsys/algorithm.h>
#include <rsys/float2.h>
#include <rsys/float3.h>
+#include <rsys/mem_allocator.h>
-#include <algorithm>
+#include <limits.h>
-struct ray_extended : public RTCRay {
+struct intersect_context {
+ struct RTCIntersectContext rtc;
struct s2d_scene_view* scnview;
- float ws_org[3]; /* World space ray origin */
- float ws_dir[3]; /* World space ray direction */
void* data; /* User defined data */
+ float ws_org[2]; /* World space ray origin */
+ float ws_dir[3]; /* World space ray direction */
+ float cos_dir_dir2d; /* Cosine between the 3D ws_dir and its 2D projection */
+ int rt_3d; /* Define if the ray is traced in 3D */
};
/*******************************************************************************
* Helper functions
******************************************************************************/
-static FINLINE bool
-operator < (const struct fltui& it, const float val)
+static INLINE int
+cmp_float(const void* a, const void* b)
+{
+ const float key = *(const float*)a;
+ const float val = *(const float*)b;
+ if(key < val) return -1;
+ if(key > val) return +1;
+ return 0;
+}
+
+static INLINE int
+cmp_float_to_fltui(const void* a, const void* b)
{
- /* This operator is used by the std::lower_bound algorithm that returns an
- * iterator to the first element that is not less than val while one expect
- * an iterator on the first element that is not less *or equal* than val.
- * That's why we use <= rather than < */
- return it.flt <= val;
+ const float key = *(const float*)a;
+ const struct fltui* fltui = (const struct fltui*)b;
+ if(key < fltui->flt) return -1;
+ if(key > fltui->flt) return +1;
+ return 0;
}
-static FINLINE bool
-operator < (const struct nprims_cdf& it, const size_t iprim)
+static INLINE int
+cmp_size_t_to_nprims_cdf(const void* a, const void* b)
{
- /* This operator is used by the std::lower_bound algorithm that returns an
- * iterator to the first element that is not less than iprim while one expect
- * an iterator on the first element that is not less *or equal* than iprim.
- * That's why we use <= rather than < */
- return it.nprims <= iprim;
+ const size_t key = *(const size_t*)a;
+ const struct nprims_cdf* nprims_cdf = (const struct nprims_cdf*)b;
+ if(key < nprims_cdf->nprims-1) return -1;
+ if(key > nprims_cdf->nprims-1) return +1;
+ return 0;
}
static INLINE void
scene_view_destroy_geometry(struct s2d_scene_view* scnview, struct geometry* geom)
{
ASSERT(geom);
- if(geom->irtc != RTC_INVALID_GEOMETRY_ID) {
- rtcDeleteGeometry(scnview->rtc_scn, geom->irtc);
- geom->irtc = RTC_INVALID_GEOMETRY_ID;
+ if(geom->rtc) {
+ if(geom->rtc_id != RTC_INVALID_GEOMETRY_ID) {
+ rtcDetachGeometry(scnview->rtc_scn, geom->rtc_id);
+ geom->rtc_id = RTC_INVALID_GEOMETRY_ID;
+ }
+ rtcReleaseGeometry(geom->rtc);
+ geom->rtc = NULL;
scnview->rtc_scn_update = 1; /* Notify the scene upd */
}
geometry_ref_put(geom);
@@ -115,52 +135,45 @@ on_shape_detach
}
static INLINE void
-hit_setup(struct s2d_scene_view* scnview, const RTCRay* ray, struct s2d_hit* hit)
+hit_setup
+ (struct s2d_scene_view* scnview,
+ const struct RTCRayHit* ray_hit,
+ struct s2d_hit* hit)
{
struct geometry* geom;
+ ASSERT(scnview && hit && ray_hit);
- if((unsigned)ray->geomID == RTC_INVALID_GEOMETRY_ID) { /* No hit */
+ if(ray_hit->hit.geomID == RTC_INVALID_GEOMETRY_ID) { /* No hit */
*hit = S2D_HIT_NULL;
return;
}
- ASSERT(eq_epsf(ray->Ng[2], 0.f, 1.e-6f));
- ASSERT((unsigned)ray->instID == RTC_INVALID_GEOMETRY_ID);
- ASSERT((unsigned)ray->geomID < darray_geom_size_get(&scnview->embree2geoms));
+ ASSERT(eq_epsf(ray_hit->hit.Ng_z, 0.f, 1.e-6f));
+ ASSERT((unsigned)(ray_hit->hit.instID[0]) == RTC_INVALID_GEOMETRY_ID);
- geom = darray_geom_data_get(&scnview->embree2geoms)[ray->geomID];
- ASSERT(geom);
+ hit->normal[0] = ray_hit->hit.Ng_x;
+ hit->normal[1] = ray_hit->hit.Ng_y;
+ hit->distance = ray_hit->ray.tfar;
+
+ /* In Embree3 the normal orientation is flipped wrt to Star-2D convention */
+ #if RTC_VERSION_MAJOR >= 3
+ f2_minus(hit->normal, hit->normal);
+ #endif
+ geom = scene_view_geometry_from_embree_id(scnview, ray_hit->hit.geomID);
hit->prim.mesh__ = geom;
- hit->prim.prim_id = ray->primID;
+ hit->prim.prim_id = ray_hit->hit.primID;
hit->prim.geom_id = geom->name;
hit->prim.scene_prim_id = hit->prim.prim_id + geom->scene_prim_id_offset;
- hit->normal[0] = ray->Ng[0];
- hit->normal[1] = ray->Ng[1];
- hit->distance = ray->tfar;
- /* The Embree "v" parametric coordinate of the extruded quad corresponds to
+
+ /* The Embree "v" parametric coordinate of the extruded quad corresponds to
* the edge parametric coordinate */
- hit->u = ray->v;
+ hit->u = ray_hit->hit.v;
if(geom->flip_contour) {
f2_minus(hit->normal, hit->normal);
}
}
-static void
-filter_wrapper(void* user_ptr, RTCRay& ray)
-{
- struct s2d_hit hit;
- struct hit_filter* filter = (struct hit_filter*)user_ptr;
- struct ray_extended* ray_ex = static_cast<struct ray_extended*>(&ray);
-
- hit_setup(ray_ex->scnview, &ray, &hit);
- if(filter->func
- (&hit, ray_ex->ws_org, ray_ex->ws_dir, ray_ex->data, filter->data)) {
- /* Discard the intersection */
- ray.geomID = RTC_INVALID_GEOMETRY_ID;
- }
-}
-
static res_T
embree_geometry_register
(struct s2d_scene_view* scnview,
@@ -169,78 +182,94 @@ embree_geometry_register
ASSERT(scnview);
/* Create the Embree geometry if it is not valid */
- if(geom->irtc == RTC_INVALID_GEOMETRY_ID) {
- geom->irtc = rtcNewQuadMesh
- (scnview->rtc_scn,
- RTC_GEOMETRY_DYNAMIC,
- line_segments_get_nsegments(geom->lines),
- line_segments_get_nverts(geom->lines)*2/*Lines are extruded as quads*/);
- if(geom->irtc == RTC_INVALID_GEOMETRY_ID)
+ if(geom->rtc == NULL) {
+ geom->rtc = rtcNewGeometry(scnview->scn->dev->rtc, RTC_GEOMETRY_TYPE_QUAD);
+ if(geom->rtc == NULL)
return RES_UNKNOWN_ERR;
- scnview->rtc_scn_update = 1;
- }
- /* Register the embree geometry in the embree2geoms associative array */
- if(geom->irtc >= darray_geom_size_get(&scnview->embree2geoms)) {
- const res_T res = darray_geom_resize(&scnview->embree2geoms, geom->irtc+1);
- if(res != RES_OK) {
- rtcDeleteGeometry(scnview->rtc_scn, geom->irtc);
- geom->irtc = RTC_INVALID_GEOMETRY_ID;
- return res;
- }
- }
+ /* Set the Star-2D representation of the geometry to the Embree geometry */
+ rtcSetGeometryUserData(geom->rtc, geom);
+
+ /* Attach the Embree geometry to the Embree scene of the scene view */
+ geom->rtc_id = rtcAttachGeometry(scnview->rtc_scn, geom->rtc);
- darray_geom_data_get(&scnview->embree2geoms)[geom->irtc] = geom;
+ scnview->rtc_scn_update = 1;
+ }
return RES_OK;
}
-static void
+static res_T
embree_geometry_setup_positions
(struct s2d_scene_view* scnview, struct geometry* geom)
{
+ RTCBuffer buf = NULL;
size_t nverts;
size_t i;
float* verts;
float* rtc_verts;
- ASSERT(scnview && geom && geom->irtc != RTC_INVALID_GEOMETRY_ID);
+ res_T res = RES_OK;
+ ASSERT(scnview && geom && geom->rtc);
- /* Extrude segment vertices as quad whose Z is [-1, 1] */
nverts = line_segments_get_nverts(geom->lines);
verts = line_segments_get_attr(geom->lines, S2D_POSITION);
- rtc_verts = (float*)rtcMapBuffer(scnview->rtc_scn, geom->irtc, RTC_VERTEX_BUFFER);
+
+ buf = rtcNewBuffer(scnview->scn->dev->rtc, nverts*2*sizeof(float[3]));
+ if(!buf) {
+ res = rtc_error_to_res_T(rtcGetDeviceError(scnview->scn->dev->rtc));
+ goto error;
+ }
+
+ /* Extrude segment vertices as quad whose Z is [-1, 1] */
+ rtc_verts = rtcGetBufferData(buf);
FOR_EACH(i, 0, nverts) {
size_t ivert = i*2/*#coords per vertex*/;
- size_t rtc_ivert = i*4/*#coords + padding*/ * 2/*#rtc vertices per line vertex*/;
+ size_t rtc_ivert = i*3/*#coords*/ * 2/*#rtc vertices per line vertex*/;
rtc_verts[rtc_ivert + 0] = verts[ivert + 0];
rtc_verts[rtc_ivert + 1] = verts[ivert + 1];
rtc_verts[rtc_ivert + 2] = 1.f;
- rtc_verts[rtc_ivert + 3] = 0.f; /* Padding */
- rtc_verts[rtc_ivert + 4] = verts[ivert + 0];
- rtc_verts[rtc_ivert + 5] = verts[ivert + 1];
- rtc_verts[rtc_ivert + 6] = -1.f;
- rtc_verts[rtc_ivert + 7] = 0.f; /* Padding */
+ rtc_verts[rtc_ivert + 3] = verts[ivert + 0];
+ rtc_verts[rtc_ivert + 4] = verts[ivert + 1];
+ rtc_verts[rtc_ivert + 5] = -1.f;
}
- rtcUnmapBuffer(scnview->rtc_scn, geom->irtc, RTC_VERTEX_BUFFER);
- rtcUpdateBuffer(scnview->rtc_scn, geom->irtc, RTC_VERTEX_BUFFER);
+
+ rtcSetGeometryBuffer(geom->rtc, RTC_BUFFER_TYPE_VERTEX, 0/*slot*/,
+ RTC_FORMAT_FLOAT3, buf, 0/*offset*/, sizeof(float[3])/*stride*/, nverts);
+ rtcUpdateGeometryBuffer(geom->rtc, RTC_BUFFER_TYPE_VERTEX, 0/*slot*/);
+
+exit:
+ if(buf) rtcReleaseBuffer(buf);
+ return res;
+error:
+ goto exit;
}
-static INLINE void
+static INLINE res_T
embree_geometry_setup_indices
(struct s2d_scene_view* scnview, struct geometry* geom)
{
+ RTCBuffer buf = NULL;
size_t nsegs;
size_t i;
uint32_t* ids;
uint32_t* rtc_ids;
- ASSERT(scnview && geom && geom->irtc != RTC_INVALID_GEOMETRY_ID);
+ res_T res = RES_OK;
+ ASSERT(scnview && geom && geom->rtc);
/* Define the index of the extruded line segments */
nsegs = line_segments_get_nsegments(geom->lines);
ids = line_segments_get_ids(geom->lines);
- rtc_ids = (uint32_t*)rtcMapBuffer(scnview->rtc_scn, geom->irtc, RTC_INDEX_BUFFER);
+
+ buf = rtcNewBuffer(scnview->scn->dev->rtc, nsegs*sizeof(uint32_t[4]));
+ if(!buf) {
+ res = rtc_error_to_res_T(rtcGetDeviceError(scnview->scn->dev->rtc));
+ goto error;
+ }
+
+ /* Define the index of the extruded line segments */
+ rtc_ids = rtcGetBufferData(buf);
FOR_EACH(i, 0, nsegs) {
size_t id = i*2/*#ids per segment*/;
size_t rtc_id = i*4/*#ids per quad*/;
@@ -250,19 +279,28 @@ embree_geometry_setup_indices
rtc_ids[rtc_id + 2] = ids[id + 1] * 2/*#rtc vertices per line vertex*/ + 0;
rtc_ids[rtc_id + 3] = ids[id + 1] * 2/*#rtc vertices per line vertex*/ + 1;
}
- rtcUnmapBuffer(scnview->rtc_scn, geom->irtc, RTC_INDEX_BUFFER);
- rtcUpdateBuffer(scnview->rtc_scn, geom->irtc, RTC_INDEX_BUFFER);
+
+ rtcSetGeometryBuffer(geom->rtc,RTC_BUFFER_TYPE_INDEX, 0/*slot*/,
+ RTC_FORMAT_UINT4, buf, 0/*offset*/, sizeof(uint32_t[4])/*stride*/, nsegs);
+ rtcUpdateGeometryBuffer(geom->rtc, RTC_BUFFER_TYPE_INDEX, 0/*slot*/);
+
+exit:
+ if(buf) rtcReleaseBuffer(buf);
+ return res;
+error:
+ goto exit;
}
static INLINE void
embree_geometry_setup_enable_state
(struct s2d_scene_view* scnview, struct geometry* geom)
{
- ASSERT(scnview && geom);
+ ASSERT(scnview && geom && geom->rtc);
+ (void)scnview;
if(geom->is_enabled) {
- rtcEnable(scnview->rtc_scn, geom->irtc);
+ rtcEnableGeometry(geom->rtc);
} else {
- rtcDisable(scnview->rtc_scn, geom->irtc);
+ rtcDisableGeometry(geom->rtc);
}
}
@@ -270,13 +308,12 @@ static INLINE void
embree_geometry_setup_filter_function
(struct s2d_scene_view* scnview, struct geometry* geom)
{
- ASSERT(scnview && geom && geom->irtc != RTC_INVALID_GEOMETRY_ID);
-
+ ASSERT(scnview && geom && geom->rtc);
+ (void)scnview;
if(!geom->lines->filter.func) {
- rtcSetIntersectionFilterFunction(scnview->rtc_scn, geom->irtc, NULL);
+ rtcSetGeometryIntersectFilterFunction(geom->rtc, NULL);
} else {
- rtcSetIntersectionFilterFunction(scnview->rtc_scn, geom->irtc, filter_wrapper);
- rtcSetUserData(scnview->rtc_scn, geom->irtc, &geom->lines->filter);
+ rtcSetGeometryIntersectFilterFunction(geom->rtc, rtc_hit_filter_wrapper);
}
}
@@ -284,25 +321,20 @@ static INLINE res_T
scene_view_setup_embree(struct s2d_scene_view* scnview)
{
struct htable_geom_iterator it, end;
- const RTCSceneFlags rtc_scene_mask =
- RTC_SCENE_DYNAMIC
- | RTC_SCENE_INCOHERENT
- | RTC_SCENE_ROBUST;
- const RTCAlgorithmFlags rtc_algorithm_mask =
- RTC_INTERSECT1
- | RTC_INTERSECT4;
int rtc_outdated = 0;
res_T res = RES_OK;
ASSERT(scnview);
/* The rtc_scn could be already allocated since the scene views are cached */
if(!scnview->rtc_scn) {
- scnview->rtc_scn = rtcDeviceNewScene
- (scnview->scn->dev->rtc, rtc_scene_mask, rtc_algorithm_mask);
+ scnview->rtc_scn = rtcNewScene(scnview->scn->dev->rtc);
if(!scnview->rtc_scn) {
- res = RES_MEM_ERR;
+ res = rtc_error_to_res_T(rtcGetDeviceError(scnview->scn->dev->rtc));
goto error;
}
+ rtcSetSceneFlags
+ (scnview->rtc_scn, RTC_SCENE_FLAG_ROBUST | RTC_SCENE_FLAG_DYNAMIC);
+ rtc_outdated = 1;
}
htable_geom_begin(&scnview->cached_geoms, &it);
@@ -322,15 +354,23 @@ scene_view_setup_embree(struct s2d_scene_view* scnview)
if(res != RES_OK) goto error;
/* Flush the embree geometry states */
- if((geom->embree_outdated_mask & EMBREE_VERTICES) != 0)
- embree_geometry_setup_positions(scnview, geom);
- if((geom->embree_outdated_mask & EMBREE_INDICES) != 0)
- embree_geometry_setup_indices(scnview, geom);
+ if((geom->embree_outdated_mask & EMBREE_VERTICES) != 0) {
+ res = embree_geometry_setup_positions(scnview, geom);
+ if(res != RES_OK) goto error;
+ }
+ if((geom->embree_outdated_mask & EMBREE_INDICES) != 0) {
+ res = embree_geometry_setup_indices(scnview, geom);
+ if(res != RES_OK) goto error;
+ }
if((geom->embree_outdated_mask & EMBREE_ENABLE) != 0)
embree_geometry_setup_enable_state(scnview, geom);
if((geom->embree_outdated_mask & EMBREE_FILTER_FUNCTION) != 0)
embree_geometry_setup_filter_function(scnview, geom);
+ /* Commit the updated geometry */
+ if(geom->embree_outdated_mask)
+ rtcCommitGeometry(geom->rtc);
+
geom->embree_outdated_mask = 0;
}
@@ -338,7 +378,7 @@ scene_view_setup_embree(struct s2d_scene_view* scnview)
/* Commit the embree changes */
if(rtc_outdated) {
- rtcCommit(scnview->rtc_scn);
+ rtcCommitScene(scnview->rtc_scn);
scnview->rtc_commit = 1; /* Notify that the scene view was committed */
scnview->rtc_scn_update = 0;
}
@@ -347,10 +387,9 @@ exit:
return res;
error:
if(scnview->rtc_scn) {
+ rtcReleaseScene(scnview->rtc_scn);
scnview->rtc_scn = NULL;
- rtcDeleteScene(scnview->rtc_scn);
}
- darray_geom_clear(&scnview->embree2geoms);
goto exit;
}
@@ -363,15 +402,22 @@ scene_view_register_line_segments
struct geometry* geom = NULL;
size_t iattr;
unsigned shape_id;
+ int is_valid;
res_T res = RES_OK;
ASSERT(scnview && shape);
+ is_valid = shape->lines->indices && shape->lines->attribs[S2D_POSITION];
+
/* Retrieved the cached geometry */
S2D(shape_get_id(shape, &shape_id));
pgeom = htable_geom_find(&scnview->cached_geoms, &shape_id);
if(pgeom) {
geom = *pgeom;
- } else {
+ if(!is_valid) {
+ scene_view_destroy_geometry(scnview, geom);
+ htable_geom_erase(&scnview->cached_geoms, &shape_id);
+ }
+ } else if(is_valid) {
res = geometry_create(scnview->scn->dev, &geom);
if(res != RES_OK) goto error;
res = line_segments_create(scnview->scn->dev, &geom->lines);
@@ -381,15 +427,7 @@ scene_view_register_line_segments
geom->name = shape->id.index;
}
- /* Discard the geometries that are not geometrically valid */
- if(!shape->lines->indices || !shape->lines->attribs[S2D_POSITION]) {
- if(geom->irtc != RTC_INVALID_GEOMETRY_ID) {
- rtcDeleteGeometry(scnview->rtc_scn, geom->irtc);
- geom->irtc = RTC_INVALID_GEOMETRY_ID;
- }
- line_segments_clear(geom->lines);
- goto exit;
- }
+ if(!is_valid) goto exit;
/* Get a reference onto the shape lines segments indices */
if(geom->lines->indices != shape->lines->indices) {
@@ -405,10 +443,11 @@ scene_view_register_line_segments
/* Get a reference onto the shape line segments attribs */
FOR_EACH(iattr, 0, S2D_ATTRIBS_COUNT__) {
- geom->embree_outdated_mask |= EMBREE_VERTICES;
if(geom->lines->attribs[iattr] == shape->lines->attribs[iattr])
continue;
+ geom->embree_outdated_mask |= EMBREE_VERTICES;
+
if(geom->lines->attribs[iattr]) { /* Release the previous geometry attribs */
vertex_buffer_ref_put(geom->lines->attribs[iattr]);
geom->lines->attribs[iattr] = NULL;
@@ -416,6 +455,7 @@ scene_view_register_line_segments
if(!shape->lines->attribs[iattr]) continue;
+ /* Get the new buffer */
vertex_buffer_ref_get(shape->lines->attribs[iattr]);
geom->lines->attribs[iattr] = shape->lines->attribs[iattr];
geom->lines->attribs_type[iattr] = shape->lines->attribs_type[iattr];
@@ -434,23 +474,6 @@ scene_view_register_line_segments
geom->embree_outdated_mask |= EMBREE_FILTER_FUNCTION;
}
- if(geom->irtc != RTC_INVALID_GEOMETRY_ID) {
- struct index_buffer* shape_ids = shape->lines->indices;
- struct index_buffer* geom_ids = geom->lines->indices;
- struct vertex_buffer* shape_verts = shape->lines->attribs[S2D_POSITION];
- struct vertex_buffer* geom_verts = geom->lines->attribs[S2D_POSITION];
- const size_t shape_nids = darray_u32_size_get(&shape_ids->data);
- const size_t geom_nids = darray_u32_size_get(&geom_ids->data);
- const size_t shape_nverts = darray_float_size_get(&shape_verts->data);
- const size_t geom_nverts = darray_float_size_get(&geom_verts->data);
-
- /* The shape lines was resize => the Embree geometry is no more valid */
- if(shape_nids != geom_nids || shape_nverts != geom_nverts) {
- rtcDeleteGeometry(scnview->rtc_scn, geom->irtc);
- geom->irtc = RTC_INVALID_GEOMETRY_ID;
- }
- }
-
geom->flip_contour = shape->flip_contour;
exit:
@@ -636,7 +659,6 @@ scene_view_create(struct s2d_scene* scn, struct s2d_scene_view** out_scnview)
}
list_init(&scnview->node);
htable_geom_init(scn->dev->allocator, &scnview->cached_geoms);
- darray_geom_init(scn->dev->allocator, &scnview->embree2geoms);
darray_fltui_init(scn->dev->allocator, &scnview->cdf);
darray_nprims_cdf_init(scn->dev->allocator, &scnview->nprims_cdf);
darray_uint_init(scn->dev->allocator, &scnview->detached_shapes);
@@ -683,7 +705,6 @@ scene_view_release(ref_T* ref)
/* Clear the scnview data structures excepted the cache of geometries that
* will be used to speed up the future scnview creation */
- darray_geom_clear(&scnview->embree2geoms);
darray_fltui_clear(&scnview->cdf);
darray_nprims_cdf_clear(&scnview->nprims_cdf);
f2_splat(scnview->lower, FLT_MAX);
@@ -697,6 +718,108 @@ scene_view_release(ref_T* ref)
S2D(scene_ref_put(scnview->scn));
}
+static res_T
+scene_view_trace_ray
+ (struct s2d_scene_view* scnview,
+ const float org[2],
+ const float dir[],
+ const float range[2],
+ const int rt_3d,
+ void* ray_data,
+ struct s2d_hit* hit)
+{
+ struct RTCRayHit ray_hit;
+ struct intersect_context intersect_ctx;
+ float dot = 1;
+ float dir2d[3] = {0.f, 0.f, 0.f};
+ float range2d[2] = {FLT_MAX, -FLT_MAX};
+ size_t i;
+
+ if(!scnview || !org || !dir || !range || !hit)
+ return RES_BAD_ARG;
+ if(!rt_3d) {
+ if(!f2_is_normalized(dir)) {
+ log_error(scnview->scn->dev,
+ "%s: unnormalized ray direction {%g, %g}.\n", FUNC_NAME, SPLIT2(dir));
+ return RES_BAD_ARG;
+ }
+ } else {
+ if(!f3_is_normalized(dir)) {
+ log_error(scnview->scn->dev,
+ "%s: unnormalized ray direction {%g, %g, %g}.\n", FUNC_NAME, SPLIT3(dir));
+ return RES_BAD_ARG;
+ }
+ if(eq_epsf(dir[0], 0.f, 1.e-6f) && eq_epsf(dir[1], 0.f, 1.e-6f)) {
+ *hit = S2D_HIT_NULL;
+ return RES_OK;
+ }
+ }
+ if(range[0] < 0) {
+ log_error(scnview->scn->dev,
+ "%s: invalid ray range [%g, %g] - it must be in [0, INF).\n",
+ FUNC_NAME, range[0], range[1]);
+ return RES_BAD_ARG;
+ }
+ if((scnview->mask & S2D_TRACE) == 0) {
+ log_error(scnview->scn->dev,
+ "%s: the S2D_TRACE flag is not active onto the submitted scene view.\n",
+ FUNC_NAME);
+ return RES_BAD_OP;
+ }
+ if(range[0] > range[1]) { /* Degenerated range <=> disabled ray */
+ *hit = S2D_HIT_NULL;
+ return RES_OK;
+ }
+
+ if(!rt_3d) {
+ f2_set(dir2d, dir);
+ f2_set(range2d, range);
+ } else {
+ f2_normalize(dir2d, dir);
+ dot = f3_dot(dir2d, dir); /* Cosine between dir and dir_2d */
+ range2d[0] = dot*range[0];
+ range2d[1] = dot*range[1];
+ }
+
+ /* Initialise the ray */
+ ray_hit.ray.org_x = org[0];
+ ray_hit.ray.org_y = org[1];
+ ray_hit.ray.org_z = 0.f;
+ ray_hit.ray.dir_x = dir2d[0];
+ ray_hit.ray.dir_y = dir2d[1];
+ ray_hit.ray.dir_z = 0.f;
+ ray_hit.ray.tnear = range2d[0];
+ ray_hit.ray.tfar = range2d[1];
+ ray_hit.ray.time = FLT_MAX; /* Invalid fields */
+ ray_hit.ray.mask = UINT_MAX; /* Invalid fields */
+ ray_hit.ray.id = UINT_MAX; /* Invalid fields */
+ ray_hit.ray.flags = UINT_MAX; /* Invalid fields */
+
+ /* Initialise the hit */
+ ray_hit.hit.geomID = RTC_INVALID_GEOMETRY_ID;
+ FOR_EACH(i, 0, RTC_MAX_INSTANCE_LEVEL_COUNT) {
+ ray_hit.hit.instID[i] = RTC_INVALID_GEOMETRY_ID;
+ }
+
+ /* Initialise the intersect context */
+ rtcInitIntersectContext(&intersect_ctx.rtc);
+ intersect_ctx.ws_org[0] = org[0];
+ intersect_ctx.ws_org[1] = org[1];
+ intersect_ctx.ws_dir[0] = dir[0];
+ intersect_ctx.ws_dir[1] = dir[1];
+ intersect_ctx.ws_dir[2] = rt_3d ? dir[3] : 0.f;
+ intersect_ctx.scnview = scnview;
+ intersect_ctx.data = ray_data;
+ intersect_ctx.rt_3d = rt_3d;
+ intersect_ctx.cos_dir_dir2d = dot;
+
+ /* Here we go */
+ rtcIntersect1(scnview->rtc_scn, &intersect_ctx.rtc, &ray_hit);
+
+ hit_setup(scnview, &ray_hit, hit);
+ return RES_OK;
+}
+
/*******************************************************************************
* Exported functions
******************************************************************************/
@@ -772,42 +895,7 @@ s2d_scene_view_trace_ray
void* ray_data,
struct s2d_hit* hit)
{
- struct ray_extended ray_ex;
-
- if(!scnview || !org || !dir || !range || !hit)
- return RES_BAD_ARG;
- if(!f2_is_normalized(dir)) {
- log_error(scnview->scn->dev,
- "%s: unnormalized ray direction {%g, %g}.\n", FUNC_NAME, SPLIT2(dir));
- return RES_BAD_ARG;
- }
- if((scnview->mask & S2D_TRACE) == 0) {
- log_error(scnview->scn->dev,
- "%s: the S2D_TRACE flag is not active onto the submitted scene view.\n",
- FUNC_NAME);
- return RES_BAD_OP;
- }
- if(range[0] > range[1]) { /* Degenerated range <=> disabled ray */
- *hit = S2D_HIT_NULL;
- return RES_OK;
- }
-
- f3_set(ray_ex.org, f3(ray_ex.ws_org, org[0], org[1], 0.f));
- f3_set(ray_ex.dir, f3(ray_ex.ws_dir, dir[0], dir[1], 0.f));
- ray_ex.tnear = range[0];
- ray_ex.tfar = range[1];
- ray_ex.geomID = RTC_INVALID_GEOMETRY_ID;
- ray_ex.primID = RTC_INVALID_GEOMETRY_ID;
- ray_ex.instID = RTC_INVALID_GEOMETRY_ID;
- ray_ex.mask = 0xFFFFFFFF;
- ray_ex.time = 0.f;
- ray_ex.scnview = scnview;
- ray_ex.data = ray_data;
-
- rtcIntersect(scnview->rtc_scn, ray_ex);
- hit_setup(scnview, &ray_ex, hit);
-
- return RES_OK;
+ return scene_view_trace_ray(scnview, org, dir, range, 0/*2D*/, ray_data, hit);
}
res_T
@@ -819,30 +907,7 @@ s2d_scene_view_trace_ray_3d
void* ray_data,
struct s2d_hit* hit)
{
- float range_2d[2];
- float dir_2d[3] = {0.f, 0.f, 0.f};
- float dot;
- res_T res = RES_OK;
-
- if(!dir || !range || !hit) {
- return RES_BAD_ARG;
- }
- if((dir[0] == 0.f && dir[1] == 0.f) || range[0] > range[1]) {
- *hit = S2D_HIT_NULL;
- return RES_OK;
- }
-
- f2_normalize(dir_2d, dir);
- dot = f3_dot(dir_2d, dir); /* Cosine between dir and dir_2d */
- range_2d[0] = dot*range[0];
- range_2d[1] = dot*range[1];
-
- res = s2d_scene_view_trace_ray(scnview, org, dir_2d, range_2d, ray_data, hit);
- if(res != RES_OK) return res;
-
- if(!S2D_HIT_NONE(hit))
- hit->distance = hit->distance / dot;
- return RES_OK;
+ return scene_view_trace_ray(scnview, org, dir, range, 1/*3D*/, ray_data, hit);
}
res_T
@@ -854,8 +919,10 @@ s2d_scene_view_sample
{
struct geometry** pgeom;
struct geometry* geom;
- const struct fltui* fltui_begin, *fltui_end, *fltui_found;
- const float* flt_begin, *flt_end, *flt_found;
+ size_t sz;
+ size_t i;
+ const struct fltui* fltui, *fltui_found;
+ const float* flt, *flt_found;
unsigned ishape;
float f;
res_T res = RES_OK;
@@ -889,29 +956,44 @@ s2d_scene_view_sample
/* Map u to the CDF bounds */
f = u * darray_fltui_cdata_get(&scnview->cdf)[0].flt;
} else {
- fltui_begin = darray_fltui_cdata_get(&scnview->cdf);
- fltui_end = fltui_begin + darray_fltui_size_get(&scnview->cdf);
- f = u * fltui_end[-1].flt; /* Map u to the CDF bounds */
- fltui_found = std::lower_bound(fltui_begin, fltui_end, f);
- ASSERT(fltui_found != fltui_end);
+ fltui = darray_fltui_cdata_get(&scnview->cdf);
+ sz = darray_fltui_size_get(&scnview->cdf);
+ f = u * fltui[sz-1].flt; /* Map u to [0, ScenePerimeter[ */
+ fltui_found = search_lower_bound
+ (&f, fltui, sz, sizeof(*fltui), cmp_float_to_fltui);
+ ASSERT(fltui_found);
+
+ /* search_lower_bound returns the first entry that is not less than `f'.
+ * The following code discards entries that are also `equal' to `f' */
+ i = (size_t)(fltui_found - fltui);
+ while(fltui[i].flt == f && i < sz) ++i;
+ ASSERT(i < sz);
+
+ fltui_found = fltui + i;
ishape = fltui_found->ui;
- if(fltui_found != fltui_begin) /* Transform u to the geometry CDF bounds */
- f -= fltui_found[-1].flt;
+ /* Map f to [0, ShapePerimeter[ */
+ if(i) f -= fltui[i-1].flt;
}
pgeom = htable_geom_find(&scnview->cached_geoms, &ishape);
ASSERT(pgeom);
geom = *pgeom;
/* Find the sampled segment */
- flt_begin = darray_float_cdata_get(&geom->lines->cdf);
- flt_end = flt_begin + darray_float_size_get(&geom->lines->cdf);
- flt_found = std::lower_bound(flt_begin, flt_end, f);
- ASSERT(flt_found != flt_end);
+ flt = darray_float_cdata_get(&geom->lines->cdf);
+ sz = darray_float_size_get(&geom->lines->cdf);
+ flt_found = search_lower_bound(&f, flt, sz, sizeof(*flt), cmp_float);
+ ASSERT(flt_found);
+
+ /* search_lower_bound returns the first entry that is not less than `f'.
+ * The following code discards entries that are also equal to `f' */
+ i = (size_t)(flt_found - flt);
+ while(flt[i] == f && i < sz) ++i;
+ ASSERT(i < sz);
primitive->mesh__ = geom;
primitive->geom_id = geom->name;
- primitive->prim_id = (unsigned)(flt_found - flt_begin);
+ primitive->prim_id = (unsigned)i;
primitive->scene_prim_id = primitive->prim_id + geom->scene_prim_id_offset;
S2D(primitive_sample(primitive, v, s));
@@ -929,12 +1011,11 @@ s2d_scene_view_get_primitive
{
struct geometry** pgeom;
struct geometry* geom;
- const struct nprims_cdf* begin;
- const struct nprims_cdf* end;
- const struct nprims_cdf* found;
+ const struct nprims_cdf* begin, *found;
size_t nprims;
- unsigned ishape;
+ size_t sz;
size_t i;
+ unsigned ishape;
res_T res = RES_OK;
if(!scnview || !prim) {
@@ -962,9 +1043,10 @@ s2d_scene_view_get_primitive
ishape = darray_nprims_cdf_cdata_get(&scnview->nprims_cdf)[0].ishape;
} else {
begin = darray_nprims_cdf_cdata_get(&scnview->nprims_cdf);
- end = begin + darray_nprims_cdf_size_get(&scnview->nprims_cdf);
- found = std::lower_bound(begin, end, i);
- ASSERT(found != end);
+ sz = darray_nprims_cdf_size_get(&scnview->nprims_cdf);
+ found = search_lower_bound
+ (&i, begin, sz, sizeof(*begin), cmp_size_t_to_nprims_cdf);
+ ASSERT(found);
ishape = found->ishape;
if(found != begin) {
ASSERT(i >= found[-1].nprims);
@@ -1132,7 +1214,7 @@ s2d_scene_view_get_aabb
void
scene_view_destroy(struct s2d_scene_view* scnview)
{
- htable_geom_iterator it, end;
+ struct htable_geom_iterator it, end;
ASSERT(scnview && !is_list_empty(&scnview->node)/*Not in use*/);
ASSERT(scnview->mask == 0);
@@ -1147,11 +1229,10 @@ scene_view_destroy(struct s2d_scene_view* scnview)
}
/* Delete the back-end scene */
- if(scnview->rtc_scn) rtcDeleteScene(scnview->rtc_scn);
+ if(scnview->rtc_scn) rtcReleaseScene(scnview->rtc_scn);
/* Release internal data structure */
htable_geom_release(&scnview->cached_geoms);
- darray_geom_release(&scnview->embree2geoms);
darray_fltui_release(&scnview->cdf);
darray_nprims_cdf_release(&scnview->nprims_cdf);
darray_uint_release(&scnview->detached_shapes);
@@ -1164,3 +1245,31 @@ scene_view_destroy(struct s2d_scene_view* scnview)
MEM_RM(scnview->scn->dev->allocator, scnview);
}
+void
+rtc_hit_filter_wrapper(const struct RTCFilterFunctionNArguments* args)
+{
+ struct s2d_hit hit;
+ struct RTCRayHit ray_hit;
+ struct intersect_context* ctx;
+ struct geometry* geom;
+ struct hit_filter* filter;
+ ASSERT(args && args->N == 1 && args->context && args->valid[0] != 0);
+
+ rtc_rayN_get_ray(args->ray, args->N, 0, &ray_hit.ray);
+ rtc_hitN_get_hit(args->hit, args->N, 0, &ray_hit.hit);
+
+ ctx = CONTAINER_OF(args->context, struct intersect_context, rtc);
+
+ geom = args->geometryUserPtr;
+ filter = &geom->lines->filter;
+ ASSERT(filter->func);
+
+ hit_setup(ctx->scnview, &ray_hit, &hit);
+ if(ctx->rt_3d) {
+ hit.distance /= ctx->cos_dir_dir2d;
+ }
+ if(filter->func(&hit, ctx->ws_org, ctx->ws_dir, ctx->data, filter->data)) {
+ args->valid[0] = 0;
+ }
+}
+
diff --git a/src/s2d_scene_view_c.h b/src/s2d_scene_view_c.h
@@ -40,22 +40,6 @@
/* Forward declarations */
struct s2d_scene_view;
-/*
- * The geometry pointers must be initialized to NULL in order to define
- * which pointers are valid or not
- */
-static FINLINE void
-geom_ptr_init__(struct mem_allocator* alloc, struct geometry** geom)
-{
- (void)alloc; *geom = NULL;
-}
-
-/* Generate the darray_geom dynamic array */
-#define DARRAY_NAME geom
-#define DARRAY_DATA struct geometry*
-#define DARRAY_FUNCTOR_INIT geom_ptr_init__
-#include <rsys/dynamic_array.h>
-
/* Generate the htable_geom hash table */
#define HTABLE_NAME geom
#define HTABLE_DATA struct geometry*
@@ -78,7 +62,6 @@ struct s2d_scene_view {
struct list_node node; /* Attachment point to the scene scene_views pool */
struct htable_geom cached_geoms; /* Cached shape geometries */
- struct darray_geom embree2geoms; /* Embree index to geometry */
struct darray_fltui cdf; /* Unormalized CDF */
struct darray_nprims_cdf nprims_cdf;
@@ -100,6 +83,10 @@ struct s2d_scene_view {
};
extern LOCAL_SYM void
+rtc_hit_filter_wrapper
+ (const struct RTCFilterFunctionNArguments* args);
+
+extern LOCAL_SYM void
scene_view_destroy
(struct s2d_scene_view* scnview);
@@ -109,9 +96,11 @@ scene_view_geometry_from_embree_id
const unsigned irtc)
{
struct geometry* geom;
+ RTCGeometry rtc_geom;
ASSERT(scnview && irtc != RTC_INVALID_GEOMETRY_ID);
- ASSERT(irtc < darray_geom_size_get(&scnview->embree2geoms));
- geom = darray_geom_data_get(&scnview->embree2geoms)[irtc];
+ rtc_geom = rtcGetGeometry(scnview->rtc_scn, irtc);
+ ASSERT(rtc_geom);
+ geom = rtcGetGeometryUserData(rtc_geom);
ASSERT(geom);
return geom;
}