star-2d

Contour structuring for efficient 2D geometric queries
git clone git://git.meso-star.fr/star-2d.git
Log | Files | Refs | README | LICENSE

commit ad5fd1a88b15772e4e238a5e6eb48e403b520fe9
parent 76ee77a09f4eff1df3fd0657b7fcb3cadc5d4f76
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Fri, 18 Jan 2019 12:36:16 +0100

Merge branch 'release_0.3'

Diffstat:
MREADME.md | 14+++++++++-----
Mcmake/CMakeLists.txt | 29++++++++++++-----------------
Msrc/s2d.h | 7++++++-
Msrc/s2d_backend.h | 22++--------------------
Msrc/s2d_buffer.h | 4++--
Msrc/s2d_c.h | 131+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/s2d_device.c | 27+++++++++++++++++++++++++--
Msrc/s2d_device_c.h | 2+-
Msrc/s2d_geometry.c | 5+++--
Msrc/s2d_geometry.h | 5+++--
Msrc/s2d_line_segments.c | 2+-
Msrc/s2d_line_segments.h | 2+-
Msrc/s2d_primitive.c | 4++--
Msrc/s2d_scene.c | 2+-
Msrc/s2d_scene_c.h | 2+-
Msrc/s2d_scene_view.c | 561+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Msrc/s2d_scene_view_c.h | 29+++++++++--------------------
Msrc/s2d_shape.c | 3++-
Msrc/s2d_shape_c.h | 2+-
Msrc/test_s2d_device.c | 2+-
Msrc/test_s2d_primitive.c | 2+-
Msrc/test_s2d_sample.c | 2+-
Msrc/test_s2d_scene.c | 2+-
Msrc/test_s2d_scene_view.c | 2+-
Msrc/test_s2d_scene_view2.c | 2+-
Msrc/test_s2d_shape.c | 2+-
Msrc/test_s2d_trace_ray.c | 2+-
Msrc/test_s2d_trace_ray_3d.c | 2+-
Msrc/test_s2d_utils.h | 2+-
29 files changed, 556 insertions(+), 317 deletions(-)

diff --git a/README.md b/README.md @@ -96,6 +96,10 @@ with `<STAR2D_INSTALL_DIR>` the install directory of Star-2D and ## Release notes +### Version 0.3 + +- Migrate the ray-tracing backend from Embree2 to Embree3. + ### Version 0.2 - Add the `s2d_segment_get_vertex_attrib` function that returns the vertex @@ -104,7 +108,7 @@ with `<STAR2D_INSTALL_DIR>` the install directory of Star-2D and ### Version 0.1.1 - Fix the `s2d_primitive_get_function`. The function failed when the submitted - parametric coordinate was equal to 1 + parametric coordinate was equal to 1. ### Version 0.1 @@ -117,8 +121,8 @@ with `<STAR2D_INSTALL_DIR>` the install directory of Star-2D and ## License -Star-2D is Copyright (C) |Meso|Star> 2016-2018 (<contact@meso-star.com>). It is a -free software released under the [OSI](http://opensource.org)-approved CeCILL -license. You are welcome to redistribute it under certain conditions; refer to -the COPYING files for details. +Copyright (C) 2016-2019 |Meso|Star> (<contact@meso-star.com>). Star-2D is free +software released under the CeCILL v2.1 license. You are welcome to +redistribute it under certain conditions; refer to the COPYING files for +details. diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +# Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) # # This software is governed by the CeCILL license under French law and # abiding by the rules of distribution of free software. You can use, @@ -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,23 +36,27 @@ 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) +find_package(RSys 0.6 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 ################################################################################ set(VERSION_MAJOR 0) -set(VERSION_MINOR 2) +set(VERSION_MINOR 3) set(VERSION_PATCH 0) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) @@ -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 @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, @@ -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 @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is a computer program whose purpose is to describe a * virtual 3D environment that can be ray-traced and sampled both robustly @@ -33,25 +33,7 @@ #ifndef S2D_BACKEND_H #define S2D_BACKEND_H -#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) - #pragma warning(push) - #pragma warning(disable:4324) /* Structure was padded due to alignment */ -#endif - -#include <embree2/rtcore.h> -#include <embree2/rtcore_ray.h> - -#ifdef COMPILER_GCC - #pragma GCC diagnostic pop -#elif defined(COMPILER_CL) - #pragma warning(pop) -#endif +#include <embree3/rtcore.h> #endif /* S2D_BACKEND_H */ diff --git a/src/s2d_buffer.h b/src/s2d_buffer.h @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, @@ -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 @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, @@ -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 @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, @@ -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_device_c.h b/src/s2d_device_c.h @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/s2d_geometry.c b/src/s2d_geometry.c @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, @@ -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 @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, @@ -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_line_segments.c b/src/s2d_line_segments.c @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/s2d_line_segments.h b/src/s2d_line_segments.h @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/s2d_primitive.c b/src/s2d_primitive.c @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, @@ -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.c b/src/s2d_scene.c @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/s2d_scene_c.h b/src/s2d_scene_c.h @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/s2d_scene_view.c b/src/s2d_scene_view.c @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, @@ -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*2); + 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,110 @@ 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); + + if(rt_3d && !S2D_HIT_NONE(hit)) hit->distance /= dot; + return RES_OK; +} + /******************************************************************************* * Exported functions ******************************************************************************/ @@ -772,42 +897,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 +909,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 +921,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 +958,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 +1013,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 +1045,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 +1216,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 +1231,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 +1247,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 @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, @@ -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; } diff --git a/src/s2d_shape.c b/src/s2d_shape.c @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, @@ -49,6 +49,7 @@ shape_release(ref_T* ref) /* The shape should not be attached */ ASSERT(is_list_empty(&shape->scene_attachment)); line_segments_ref_put(shape->lines); + flist_name_del(&dev->names, shape->id); MEM_RM(dev->allocator, shape); S2D(device_ref_put(dev)); } diff --git a/src/s2d_shape_c.h b/src/s2d_shape_c.h @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/test_s2d_device.c b/src/test_s2d_device.c @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/test_s2d_primitive.c b/src/test_s2d_primitive.c @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/test_s2d_sample.c b/src/test_s2d_sample.c @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/test_s2d_scene.c b/src/test_s2d_scene.c @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/test_s2d_scene_view.c b/src/test_s2d_scene_view.c @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/test_s2d_scene_view2.c b/src/test_s2d_scene_view2.c @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/test_s2d_shape.c b/src/test_s2d_shape.c @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/test_s2d_trace_ray.c b/src/test_s2d_trace_ray.c @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/test_s2d_trace_ray_3d.c b/src/test_s2d_trace_ray_3d.c @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/test_s2d_utils.h b/src/test_s2d_utils.h @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +/* Copyright (C) 2016-2019 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use,