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 47e30a4173e993dfb22839f993feda0351795e80
parent 29dd366b10ff06d751c9d24758f83fa7c024bbb5
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Thu, 11 Jan 2018 15:04:45 +0100

Major update of the API

Add the the scene_view concept

Diffstat:
Mcmake/CMakeLists.txt | 21++++++++++++---------
Msrc/s2d.h | 120++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/s2d_device.c | 37++++++++++++++++++++++++++++++-------
Msrc/s2d_device_c.h | 14++++++++++++++
Msrc/s2d_geometry.c | 1+
Msrc/s2d_geometry.h | 10++++++++++
Msrc/s2d_scene.c | 1048+++++--------------------------------------------------------------------------
Msrc/s2d_scene_c.h | 58++++++++++++----------------------------------------------
Asrc/s2d_scene_view.c | 1155+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/s2d_scene_view_c.h | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_s2d_device.c | 40++++++++++++++++++++--------------------
Msrc/test_s2d_primitive.c | 132++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/test_s2d_sample.c | 150++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/test_s2d_scene.c | 286++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/test_s2d_session_advanced.c | 134++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/test_s2d_shape.c | 330++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/test_s2d_trace_ray.c | 210++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/test_s2d_trace_ray_3d.c | 110++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/test_s2d_utils.h | 4++--
19 files changed, 2167 insertions(+), 1812 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -38,11 +38,12 @@ option(NO_TEST "Disable the test" OFF) ################################################################################ find_package(Embree 2.9 REQUIRED) find_package(RCMake 0.2.2 REQUIRED) -find_package(RSys 0.4.0 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) @@ -51,7 +52,7 @@ rcmake_append_runtime_dirs(_runtime_dirs RSys Embree) # Configure and define targets ################################################################################ set(VERSION_MAJOR 0) -set(VERSION_MINOR 0) +set(VERSION_MINOR 1) set(VERSION_PATCH 0) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) @@ -61,6 +62,7 @@ set(S2D_FILES_SRC s2d_line_segments.c s2d_primitive.c s2d_scene.c + s2d_scene_view.c s2d_shape.c) set(S2D_FILES_INC_API s2d.h) set(S2D_FILES_INC @@ -69,6 +71,7 @@ set(S2D_FILES_INC s2d_geometry.h s2d_line_segments.h s2d_scene_c.h + s2d_scene_view_c.h s2d_shape_c.h) set(S2D_FILES_DOC COPYING.fr COPYING.en README.md) @@ -127,13 +130,13 @@ if(NOT NO_TEST) endfunction() new_test(test_s2d_device) - new_test(test_s2d_primitive) - new_test(test_s2d_sample) - new_test(test_s2d_scene) - new_test(test_s2d_session_advanced) - new_test(test_s2d_shape) - new_test(test_s2d_trace_ray) - new_test(test_s2d_trace_ray_3d) +# new_test(test_s2d_primitive) +# new_test(test_s2d_sample) +# new_test(test_s2d_scene) +# new_test(test_s2d_session_advanced) +# new_test(test_s2d_shape) +# new_test(test_s2d_trace_ray) +# new_test(test_s2d_trace_ray_3d) endif(NOT NO_TEST) ################################################################################ diff --git a/src/s2d.h b/src/s2d.h @@ -137,6 +137,12 @@ static const struct s2d_hit S2D_HIT_NULL = S2D_HIT_NULL__; * intersects a shape or not */ #define S2D_HIT_NONE(Hit) ((Hit)->distance >= FLT_MAX) +enum s2d_scene_view_flag { + S2D_TRACE = BIT(0), + S2D_SAMPLE = BIT(1), + S2D_GET_PRIMITIVE = BIT(2) +}; + /* Filter function data type. One can define such function to discard * intersections along a ray with respect to user defined criteria, e.g.: * masked/transparent primitive, etc. Return 0 or the intersection is not @@ -149,15 +155,10 @@ typedef int void* ray_data, /* User data submitted on trace ray(s) invocation */ void* filter_data); /* Data defined on the setup of the filter function */ -enum s2d_session_flag { - S2D_TRACE = BIT(0), - S2D_SAMPLE = BIT(1), - S2D_GET_PRIMITIVE = BIT(2) -}; - /* Forward declaration of s2d opaque data types */ struct s2d_device; struct s2d_scene; +struct s2d_scene_view; struct s2d_shape; /* Forward declaration of external data types */ @@ -200,9 +201,8 @@ S2D_API res_T s2d_scene_ref_put (struct s2d_scene* scn); -/* Attach the shape to the scene. If the shape is already attached to the same - * or another scene, nothing is performed and a RES_BAD_ARG error is returned. - * On success, the scene gets a reference onto the attached shape */ +/* Attach the shape to the scene. On success, the scene gets a reference onto + * the attached shape */ S2D_API res_T s2d_scene_attach_shape (struct s2d_scene* scn, @@ -221,34 +221,42 @@ S2D_API res_T s2d_scene_clear (struct s2d_scene* scn); -/* Synchronize the scene geometry with the geometry of its attached shapes. If - * a s2d_scene_begin_session is already active on `scn' or one of its attached - * instance a RES_BAD_OP error is returned. On success neither another begin - * session nor a clear or shape_detach can be invoked on `scn' and its attached - * instances until s2d_scene_end_session is called. */ +/* Retrieve the device from which the scene was created */ S2D_API res_T -s2d_scene_begin_session +s2d_scene_get_device (struct s2d_scene* scn, - const int session_mask); /* Combination of s2d_session_flag */ + struct s2d_device** dev); -/* End the session on the `scn' */ +/******************************************************************************* + * Scene view API - State of the scene geometry + ******************************************************************************/ S2D_API res_T -s2d_scene_end_session - (struct s2d_scene* scn); +s2d_scene_view_create + (struct s2d_scene* scn, + const int mask, /* Combination of s2d_scene_view_flag */ + struct s2d_scene_view** scnview); S2D_API res_T -s2d_scene_get_session_mask - (struct s2d_scene* scn, +s2d_scene_view_ref_get + (struct s2d_scene_view* scnview); + +S2D_API res_T +s2d_scene_view_ref_put + (struct s2d_scene_view* scnview); + +S2D_API res_T +s2d_scene_view_get_mask + (struct s2d_scene_view* scnview, int* mask); /* Trace a ray into the `scn' and return the closest intersection. The ray is * defined by `origin' + t*`direction' = 0 with t in [`range[0]', `range[1]'). * Note that if range is degenerated (i.e. `range[0]' >= `range[1]') then the - * ray is not traced and `hit' is set to S2D_HIT_NULL. Can be called only if an - * S2D_TRACE session is active on `scn' */ + * ray is not traced and `hit' is set to S2D_HIT_NULL. Can be called only if + * the scnview was created with the S2D_TRACE flag. */ S2D_API res_T -s2d_scene_trace_ray - (struct s2d_scene* scn, +s2d_scene_view_trace_ray + (struct s2d_scene_view* scnview, const float origin[2], /* Ray origin */ const float direction[2], /* Ray direction. Must be normalized */ const float range[2], /* In [0, INF)^2 */ @@ -262,10 +270,10 @@ s2d_scene_trace_ray * as the potential hit distance are expressed with respect to the 3D * direction. Note that if range is degenerated (i.e. `range[0]' >= * `range[1]') then the ray is not traced and `hit' is set to S2D_HIT_NULL. Can - * be called only if an S2D_TRACE session is active on `scn'. */ + * be called only if te scnview was created with the S2D_TRACE flag. */ S2D_API res_T -s2d_scene_trace_ray_3d - (struct s2d_scene* scn, +s2d_scene_view_trace_ray_3d + (struct s2d_scene_view* scnview, const float origin[3], const float dir[3], const float range[2], @@ -273,60 +281,52 @@ s2d_scene_trace_ray_3d struct s2d_hit* hit); /* Uniformly sample the scene and returned the sampled primitive and its sample - * position. Can be called only if a S2D_SAMPLE session is active on `scn'*/ + * position. CCan be called only if the scnview was created with the + * S2D_SAMPLE flag */ S2D_API res_T -s2d_scene_sample - (struct s2d_scene* scn, +s2d_scene_view_sample + (struct s2d_scene_view* scnview, const float u, const float v, /* Random numbers in [0, 1) */ struct s2d_primitive* primitive, /* Sampled primitive */ float* s); /* Sampled parametric coordinates on the primitive */ -/* Retrieve a primitive from the scene. Can be called only if a - * S2D_GET_PRIMITIVE session is active on `scn' */ +/* Retrieve a primitive from the scene. Can be called only if the scnview was + * created with the S2D_GET_PRIMITIVE flag */ S2D_API res_T -s2d_scene_get_primitive - (struct s2d_scene* scn, +s2d_scene_view_get_primitive + (struct s2d_scene* scnview, const unsigned iprim, /* in [0, #prims) */ struct s2d_primitive* prim); -/* Retrieve the number of scene primitives. Can be called only if a sessio is - * active on `scn' */ +/* Retrieve the number of scene primitives. Can be called only if the scnview + * was created with the S2D_GET_PRIMITIVE flag */ S2D_API res_T -s2d_scene_primitives_count - (struct s2d_scene* scn, +s2d_scene_view_primitives_count + (struct s2d_scene_view* scnview, size_t* primitives_count); -/* Compute the overall length of the shape contours. Return RES_BAD_ARG if no - * session is active on scn. */ +/* Compute the overall length of the shape contours */ S2D_API res_T -s2d_scene_compute_contour_length - (struct s2d_scene* scn, +s2d_scene_view_compute_contour_length + (struct s2d_scene_view* scnview, float* length); /* This function assumes that the scene defines a closed polygon and that the - * normals point into the polygon. Return RES_BAD_ARG if no session is active - * on scn */ + * normals point into the polygon. */ S2D_API res_T -s2d_scene_compute_area - (struct s2d_scene* scn, +s2d_scene_view_compute_area + (struct s2d_scene_view* scnview, float* area); -/* Retrieve the Axis Aligned Bounding Box of the scene. Return RES_BAD_ARG if - * no session is active on scn */ +/* Retrieve the Axis Aligned Bounding Box of the scene. */ S2D_API res_T -s2d_scene_get_aabb - (struct s2d_scene* scn, - float lower[3], /* AABB lower bound */ - float upper[3]); /* AABB upper bound */ - -/* Retrieve the device from which the scene was created */ -S2D_API res_T -s2d_scene_get_device - (struct s2d_scene* scn, - struct s2d_device** dev); +s2d_scene_view_get_aabb + (struct s2d_scene_view* scnview, + float lower[2], /* AABB lower bound */ + float upper[2]); /* AABB upper bound */ /******************************************************************************* - * Shape API - define a 2D contour that can be attached to *one* scene. + * Shape API - define a 2D contour that can be attached to a scene. ******************************************************************************/ S2D_API res_T s2d_shape_create_line_segments diff --git a/src/s2d_device.c b/src/s2d_device.c @@ -35,6 +35,21 @@ /******************************************************************************* * Helper functions ******************************************************************************/ +static INLINE void +log_msg + (struct s2d_device* dev, + const enum log_type stream, + const char* msg, + va_list vargs) +{ + ASSERT(dev && msg); + if(dev->verbose) { + res_T res; (void)res; + res = logger_vprint(dev->logger, stream, msg, vargs); + ASSERT(res == RES_OK); + } +} + static void device_release(ref_T* ref) { @@ -113,12 +128,20 @@ log_error(struct s2d_device* dev, const char* msg, ...) { va_list vargs_list; ASSERT(dev && msg); - if(dev->verbose) { - res_T res; (void)res; - va_start(vargs_list, msg); - res = logger_vprint(dev->logger, LOG_ERROR, msg, vargs_list); - ASSERT(res == RES_OK); - va_end(vargs_list); - } + + va_start(vargs_list, msg); + log_msg(dev, LOG_ERROR, msg, vargs_list); + va_end(vargs_list); +} + +void +log_warning(struct s2d_device* dev, const char* msg, ...) +{ + va_list vargs_list; + ASSERT(dev && msg); + + va_start(vargs_list, msg); + log_msg(dev, LOG_WARNING, msg, vargs_list); + va_end(vargs_list); } diff --git a/src/s2d_device_c.h b/src/s2d_device_c.h @@ -50,6 +50,8 @@ struct s2d_device { ref_T ref; }; +/* Conditionally log a message on the LOG_ERROR stream of the device logger, + * with respect to the device verbose flag */ extern LOCAL_SYM void log_error (struct s2d_device* dev, @@ -60,5 +62,17 @@ log_error #endif ; +/* Conditionally log a message on the LOG_WARNING stream of the device logger, + * with respect to the device verbose flag */ +extern LOCAL_SYM void +log_warning + (struct s2d_device* dev, + const char* msg, + ...) +#ifdef COMPILER_GCC + __attribute((format(printf, 2, 3))) +#endif +; + #endif /* S2D_DEVICE_C_H */ diff --git a/src/s2d_geometry.c b/src/s2d_geometry.c @@ -69,6 +69,7 @@ geometry_create(struct s2d_device* dev, struct geometry** out_geom) geom->dev = dev; geom->name = S2D_INVALID_ID; geom->irtc = RTC_INVALID_GEOMETRY_ID; + geom->embree_outdated_mask = 0; geom->flip_contour = 0; geom->is_enabled = 1; geom->lines = NULL; diff --git a/src/s2d_geometry.h b/src/s2d_geometry.h @@ -33,11 +33,21 @@ #include "s2d_backend.h" #include <rsys/ref_count.h> +enum embree_attrib { + EMBREE_ENABLE = BIT(0), + EMBREE_FILTER_FUNCTION = BIT(1), + EMBREE_INDICES = BIT(2), + EMBREE_VERTICES = BIT(4) +}; + /* Backend geometry */ struct geometry { unsigned name; /* Client side identifier */ unsigned irtc; /* Backend identifier */ unsigned scene_prim_id_offset; /* Offset from local to scene prim_id */ + + int embree_outdated_mask; /* Combination of embree_attrib */ + char flip_contour; /* Is the geometry contour flipped? */ char is_enabled; /* Is the geometry enabled? */ diff --git a/src/s2d_scene.c b/src/s2d_scene.c @@ -28,542 +28,33 @@ #include "s2d.h" #include "s2d_device_c.h" -#include "s2d_line_segments.h" -#include "s2d_geometry.h" #include "s2d_scene_c.h" +#include "s2d_scene_view_c.h" #include "s2d_shape_c.h" -#include <rsys/logger.h> -#include <rsys/float2.h> -#include <rsys/float3.h> +#include <rsys/list.h> #include <rsys/mem_allocator.h> -#include <algorithm> - -struct ray_extended : public RTCRay { - struct s2d_scene* scene; - void* data; /* User defined data */ -}; - /******************************************************************************* * Helper functions ******************************************************************************/ -static INLINE void -hit_setup(struct s2d_scene* scn, const RTCRay* ray, struct s2d_hit* hit) -{ - struct geometry* geom; - - if((unsigned)ray->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(&scn->embree2geoms)); - - geom = darray_geom_data_get(&scn->embree2geoms)[ray->geomID]; - ASSERT(geom); - - hit->prim.mesh__ = geom; - hit->prim.prim_id = ray->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 edge parametric coordinate */ - hit->u = ray->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->scene, &ray, &hit); - if(filter->func(&hit, ray_ex->org, ray_ex->dir, ray_ex->data, filter->data)) { - /* Discard the intersection */ - ray.geomID = RTC_INVALID_GEOMETRY_ID; - } -} - -static void -scene_geometry_flush_enable_state - (struct s2d_scene* scn, - struct geometry* geom, - const struct s2d_shape* shape) -{ - ASSERT(scn && geom && shape && geom->irtc != RTC_INVALID_GEOMETRY_ID); - if(geom->is_enabled == shape->is_enabled) - return; - - geom->is_enabled = shape->is_enabled; - if(geom->is_enabled) { - rtcEnable(scn->rtc_scn, geom->irtc); - } else { - rtcDisable(scn->rtc_scn, geom->irtc); - } - scn->is_rtc_scn_outdated = 1; -} - -static void -scene_geometry_flush_filter_function - (struct s2d_scene* scn, - struct geometry* geom, - const struct s2d_shape* shape) -{ - ASSERT(scn && geom && shape && geom->irtc != RTC_INVALID_GEOMETRY_ID); - - if(geom->lines->filter.func == shape->lines->filter.func - && geom->lines->filter.data == shape->lines->filter.data) - return; /* Up to date */ - - geom->lines->filter = shape->lines->filter; - if(!geom->lines->filter.func) { - rtcSetIntersectionFilterFunction(scn->rtc_scn, geom->irtc, NULL); - } else { - rtcSetIntersectionFilterFunction(scn->rtc_scn, geom->irtc, filter_wrapper); - rtcSetUserData(scn->rtc_scn, geom->irtc, &geom->lines->filter); - } - scn->is_rtc_scn_outdated = 1; -} - - -static res_T -scene_register_geometry(struct s2d_scene* scn, struct geometry* geom) -{ - ASSERT(scn && geom); - - /* Create the embree geometry if it is not valid */ - if(geom->irtc == RTC_INVALID_GEOMETRY_ID) { - geom->irtc = rtcNewQuadMesh - (scn->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) - return RES_UNKNOWN_ERR; - scn->is_rtc_scn_outdated = 1; - } - if(geom->irtc >= darray_geom_size_get(&scn->embree2geoms)) { - const res_T res = darray_geom_resize(&scn->embree2geoms, geom->irtc + 1); - if(res != RES_OK) { - rtcDeleteGeometry(scn->rtc_scn, geom->irtc); - geom->irtc = RTC_INVALID_GEOMETRY_ID; - return res; - } - } - geometry_ref_get(geom); - darray_geom_data_get(&scn->embree2geoms)[geom->irtc] = geom; - return RES_OK; -} - -static void -scene_geometry_flush_positions(struct s2d_scene* scn, struct geometry* geom) -{ - size_t nverts; - size_t i; - float* verts; - float* rtc_verts; - ASSERT(scn && geom && geom->irtc != RTC_INVALID_GEOMETRY_ID); - - /* 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(scn->rtc_scn, geom->irtc, RTC_VERTEX_BUFFER); - 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*/; - - 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 */ - } - rtcUnmapBuffer(scn->rtc_scn, geom->irtc, RTC_VERTEX_BUFFER); -} - -static void -scene_geometry_flush_indices(struct s2d_scene* scn, struct geometry* geom) -{ - size_t nsegs; - size_t i; - uint32_t* ids; - uint32_t* rtc_ids; - ASSERT(scn && geom && geom->irtc != RTC_INVALID_GEOMETRY_ID); - - /* 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(scn->rtc_scn, geom->irtc, RTC_INDEX_BUFFER); - FOR_EACH(i, 0, nsegs) { - size_t id = i*2/*#ids per segment*/; - size_t rtc_id = i*4/*#ids per quad*/; - - rtc_ids[rtc_id + 0] = ids[id + 0] * 2/*#rtc vertices per line vertex*/ + 1; - rtc_ids[rtc_id + 1] = ids[id + 0] * 2/*#rtc vertices per line vertex*/ + 0; - 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(scn->rtc_scn, geom->irtc, RTC_INDEX_BUFFER); -} - -static res_T -scene_register_line_segments - (struct s2d_scene* scn, - struct s2d_shape* shape) -{ - struct geometry** pgeom = NULL; - struct geometry* geom = NULL; - size_t iattr; - char upd_pos, upd_ids; - - res_T res = RES_OK; - ASSERT(scn && shape); - - /* Retrieved the cached geometry */ - pgeom = htable_geom_find(&scn->cached_geoms, &shape); - if(pgeom) { - geom = *pgeom; - } else { - res = geometry_create(scn->dev, &geom); - if(res != RES_OK) goto error; - res = line_segments_create(scn->dev, &geom->lines); - if(res != RES_OK) goto error; - res = htable_geom_set(&scn->cached_geoms, &shape, &geom); - if(res != RES_OK) goto error; - 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(scn->rtc_scn, geom->irtc); - geom->irtc = RTC_INVALID_GEOMETRY_ID; - scn->is_rtc_scn_outdated = 1; - } - line_segments_clear(geom->lines); - goto exit; - } - - /* Define which geometry buffers were updated */ - upd_ids = geom->lines->indices != shape->lines->indices - || ((shape->lines->update_mask & INDEX_BUFFER) != 0); - upd_pos = geom->lines->attribs[S2D_POSITION] != shape->lines->attribs[S2D_POSITION] - || ((shape->lines->update_mask & VERTEX_BUFFER) != 0); - - /* Get a reference onto the shape lines segments indices */ - if(geom->lines->indices != shape->lines->indices) { - if(geom->lines->indices) { /* Release previous indices of the geometry */ - index_buffer_ref_put(geom->lines->indices); - geom->lines->indices = NULL; - } - ASSERT(shape->lines->indices); - index_buffer_ref_get(shape->lines->indices); - geom->lines->indices = shape->lines->indices; - } - - /* Get a reference onto the shape line segments attribs */ - FOR_EACH(iattr, 0, S2D_ATTRIBS_COUNT__) { - if(geom->lines->attribs[iattr] == shape->lines->attribs[iattr]) - continue; - - if(geom->lines->attribs[iattr]) { /* Release the previous geometry attribs */ - vertex_buffer_ref_put(geom->lines->attribs[iattr]); - geom->lines->attribs[iattr] = NULL; - } - - if(!shape->lines->attribs[iattr]) continue; - - 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]; - } - - /* The line segments were resize => the Embree geometry is no more valid */ - if(shape->lines->resize_mask && geom->irtc != RTC_INVALID_GEOMETRY_ID) { - rtcDeleteGeometry(scn->rtc_scn, geom->irtc); - geom->irtc = RTC_INVALID_GEOMETRY_ID; - scn->is_rtc_scn_outdated = 1; - } - - res = scene_register_geometry(scn, geom); - if(res != RES_OK) goto error; - - if(upd_pos) { /* Update the Embree vertex buffer if necessary */ - scene_geometry_flush_positions(scn, geom); - } - if(upd_ids) { /* Update the Embree index buffer if necessary */ - scene_geometry_flush_indices(scn, geom); - } - - /* Flush the remaining geometry states */ - scene_geometry_flush_enable_state(scn, geom, shape); - scene_geometry_flush_filter_function(scn, geom, shape); - geom->flip_contour = shape->flip_contour; - - /* Flush the shape line segments states */ - shape->lines->resize_mask = 0; - shape->lines->update_mask = 0; - -exit: - return res; -error: - goto exit; -} - -static void -scene_session_clear(struct s2d_scene* scn) -{ - struct geometry** pgeoms; - size_t ngeoms, i; - ASSERT(scn); - - ngeoms = darray_geom_size_get(&scn->embree2geoms); - pgeoms = darray_geom_data_get(&scn->embree2geoms); - FOR_EACH(i, 0, ngeoms) { - if(!pgeoms[i]) continue; - geometry_ref_put(pgeoms[i]); - } - darray_geom_clear(&scn->embree2geoms); - scn->session_mask = 0; -} - -static res_T -scene_detach_shape - (struct s2d_scene* scn, struct s2d_shape* shape, const char* caller_name) -{ - struct geometry** pgeom; - ASSERT(scn && shape && !is_list_empty(&shape->scene_attachment)); - - pgeom = htable_geom_find(&scn->cached_geoms, &shape); - if(pgeom) { /* Remove the cached geometry */ - struct geometry* geom = *pgeom; - - if(scn->session_mask != 0) { - log_error(scn->dev, - "%s: Cannot detach a shape currently in used in a scene session.\n", - caller_name); - return RES_BAD_OP; - } - if(geom->irtc != RTC_INVALID_GEOMETRY_ID) { - rtcDeleteGeometry(scn->rtc_scn, geom->irtc); - geom->irtc = RTC_INVALID_GEOMETRY_ID; - scn->is_rtc_scn_outdated = 1; - } - geometry_ref_put(geom); - htable_geom_erase(&scn->cached_geoms, &shape); - } - list_del(&shape->scene_attachment); - - S2D(shape_ref_put(shape)); - return RES_OK; -} - -static res_T -scene_compute_cdf(struct s2d_scene* scn) -{ - struct list_node* node; - struct s2d_shape* shape; - struct geometry** pgeom; - struct geometry* geom; - size_t len; - float length = 0.f; - res_T res = RES_OK; - ASSERT(scn); - - darray_fltui_clear(&scn->cdf); - - LIST_FOR_EACH(node, &scn->shapes) { - - shape = CONTAINER_OF(node, struct s2d_shape, scene_attachment); - pgeom = htable_geom_find(&scn->cached_geoms, &shape); - ASSERT(pgeom != NULL); - geom = *pgeom; - - if(!geom->is_enabled) continue; - - res = line_segments_compute_cdf(geom->lines); - if(res != RES_OK) goto error; - len = darray_float_size_get(&geom->lines->cdf); - - if(len) { /* The geometry has valid segments */ - struct fltui fltui; - length += darray_float_cdata_get(&geom->lines->cdf)[len - 1]; - fltui.ui = geom->irtc; - fltui.flt = length; - res = darray_fltui_push_back(&scn->cdf, &fltui); - if(res != RES_OK) goto error; - } - } - -exit: - return res; -error: - darray_fltui_clear(&scn->cdf); - goto exit; -} - -static FINLINE bool -operator < (const struct fltui& it, const float val) -{ - /* 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; -} - -static FINLINE bool -operator < (const struct nprims_cdf& it, const size_t iprim) -{ - /* 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; -} - -static res_T -scene_compute_nprims_cdf(struct s2d_scene* scn, const char store_cdf) -{ - struct list_node* node; - struct s2d_shape* shape; - struct geometry** pgeom; - struct geometry* geom; - size_t len; - unsigned nprims; - res_T res = RES_OK; - ASSERT(scn); - - darray_nprims_cdf_clear(&scn->nprims_cdf); - - nprims = 0; - LIST_FOR_EACH(node, &scn->shapes) { - struct nprims_cdf cdf; - - shape = CONTAINER_OF(node, struct s2d_shape, scene_attachment); - pgeom = htable_geom_find(&scn->cached_geoms, &shape); - ASSERT(pgeom != NULL); - geom = *pgeom; - - if(!geom->is_enabled) continue; - - geom->scene_prim_id_offset = nprims; - len = line_segments_get_nsegments(geom->lines); - nprims += (unsigned)len; - - if(store_cdf && len) { - cdf.nprims = nprims; - cdf.irtc = geom->irtc; - res = darray_nprims_cdf_push_back(&scn->nprims_cdf, &cdf); - if(res != RES_OK) goto error; - } - } - -exit: - return res; -error: - darray_nprims_cdf_clear(&scn->nprims_cdf); - goto exit; -} - -static void -scene_compute_aabb(struct s2d_scene* scn) -{ - struct list_node* node; - struct s2d_shape* shape; - struct geometry** pgeom; - struct geometry* geom; - float lower[2], upper[2]; - - f2_splat(scn->lower, FLT_MAX); - f2_splat(scn->upper,-FLT_MAX); - - LIST_FOR_EACH(node, &scn->shapes) { - shape = CONTAINER_OF(node, struct s2d_shape, scene_attachment); - pgeom = htable_geom_find(&scn->cached_geoms, &shape); - ASSERT(pgeom != NULL); - geom = *pgeom; - - if(!geom->is_enabled) continue; - - line_segments_compute_aabb(geom->lines, lower, upper); - f2_min(scn->lower, scn->lower, lower); - f2_max(scn->upper, scn->upper, upper); - } -} - -static res_T -scene_sync - (struct s2d_scene* scn, const int session_mask, const char* caller_name) -{ - struct list_node* node; - struct s2d_shape* shape; - res_T res = RES_OK; - ASSERT(scn); - - if(scn->session_mask != 0) { - log_error(scn->dev, - "%s: Invalid operation. The scene cannot be synced several times.\n", - caller_name); - res = RES_BAD_OP; - goto error; - } - - LIST_FOR_EACH(node, &scn->shapes) { - shape = CONTAINER_OF(node, struct s2d_shape, scene_attachment); - res = scene_register_line_segments(scn, shape); - if(res != RES_OK) goto error; - } - - if((session_mask & S2D_SAMPLE) != 0) { - res = scene_compute_cdf(scn); - if(res != RES_OK) goto error; - } - - res = scene_compute_nprims_cdf(scn, (session_mask & S2D_GET_PRIMITIVE)!=0); - if(res != RES_OK) goto error; - - if((session_mask & S2D_TRACE) != 0 && scn->is_rtc_scn_outdated) { - rtcCommit(scn->rtc_scn); - scn->is_rtc_scn_outdated = 0; - } - scn->session_mask = session_mask; - scene_compute_aabb(scn); - -exit: - return res; -error: - goto exit; -} - static void scene_release(ref_T* ref) { struct s2d_scene* scn; struct s2d_device* dev; + struct list_node* node; + struct list_node* tmp; + ASSERT(ref); scn = CONTAINER_OF(ref, struct s2d_scene, ref); - S2D(scene_clear(scn)); dev = scn->dev; - scene_session_clear(scn); - if(scn->rtc_scn) rtcDeleteScene(scn->rtc_scn); - htable_geom_release(&scn->cached_geoms); - darray_geom_release(&scn->embree2geoms); - darray_fltui_release(&scn->cdf); - darray_nprims_cdf_release(&scn->nprims_cdf); + + LIST_FOR_EACH_SAFE(node, tmp, &scn->scnviews) { + scene_view_destroy(CONTAINER_OF(node, struct s2d_scene_view, node)); + } + S2D(scene_clear(scn)); + htable_shape_release(&scn->shapes); MEM_RM(dev->allocator, scn); S2D(device_ref_put(dev)); } @@ -575,13 +66,6 @@ res_T s2d_scene_create(struct s2d_device* dev, struct s2d_scene** out_scn) { struct s2d_scene* scn = NULL; - const RTCSceneFlags rtc_scene_mask = - RTC_SCENE_DYNAMIC - | RTC_SCENE_INCOHERENT - | RTC_SCENE_ROBUST; - const RTCAlgorithmFlags rtc_intersect_mask = - RTC_INTERSECT1 - | RTC_INTERSECT4; res_T res = RES_OK; if(!dev || !out_scn) { @@ -595,22 +79,12 @@ s2d_scene_create(struct s2d_device* dev, struct s2d_scene** out_scn) res = RES_MEM_ERR; goto error; } - list_init(&scn->shapes); - htable_geom_init(dev->allocator, &scn->cached_geoms); - darray_geom_init(dev->allocator, &scn->embree2geoms); - darray_fltui_init(dev->allocator, &scn->cdf); - darray_nprims_cdf_init(dev->allocator, &scn->nprims_cdf); + htable_shape_init(dev->allocator, &scn->shapes); + SIG_INIT(&scn->sig_shape_detach); + list_init(&scn->scnviews); ref_init(&scn->ref); S2D(device_ref_get(dev)); scn->dev = dev; - scn->session_mask = 0; - scn->rtc_scn = rtcDeviceNewScene(dev->rtc, rtc_scene_mask, rtc_intersect_mask); - if(!scn->rtc_scn) { - res = RES_MEM_ERR; - goto error; - } - f2_splat(scn->lower, FLT_MAX); - f2_splat(scn->upper,-FLT_MAX); exit: if(out_scn) *out_scn = scn; @@ -642,498 +116,88 @@ s2d_scene_ref_put(struct s2d_scene* scn) res_T s2d_scene_attach_shape(struct s2d_scene* scn, struct s2d_shape* shape) { - if(!scn || !shape) - return RES_BAD_ARG; - if(!is_list_empty(&shape->scene_attachment)) { - log_error(scn->dev, - "%s: Cannot attach a shape that is already attached to a scene.\n", - FUNC_NAME); - return RES_BAD_ARG; - } - list_add_tail(&scn->shapes, &shape->scene_attachment); - S2D(shape_ref_get(shape)); - return RES_OK; -} - -res_T -s2d_scene_detach_shape(struct s2d_scene* scn, struct s2d_shape* shape) -{ + unsigned shape_id; res_T res = RES_OK; - char is_attached; - - - if(!scn || !shape) return RES_BAD_ARG; - if(!(S2D(shape_is_attached(shape, &is_attached)), is_attached)) { - log_error(scn->dev, - "%s: The shape to detach is not attached to any scene.\n", - FUNC_NAME); - return RES_BAD_ARG; - } -#ifndef NDEBUG - { /* Check that the shape is attached to `scn' */ - struct list_node* node; - char is_found = 0; - LIST_FOR_EACH(node, &scn->shapes) { - if(node == &shape->scene_attachment) { - is_found = 1; - break; - } - } - ASSERT(is_found); - } -#endif - res = scene_detach_shape(scn, shape, FUNC_NAME); - if(res != RES_OK) return res; - - return RES_OK; -} - -res_T -s2d_scene_clear(struct s2d_scene* scn) -{ - struct list_node* node, *tmp; - if(!scn) return RES_BAD_ARG; - if(scn->session_mask != 0) { - log_error(scn->dev, - "%s: Invalid operation. A session is active onto the scene.\n", - FUNC_NAME); - return RES_BAD_OP; - } - LIST_FOR_EACH_SAFE(node, tmp, &scn->shapes) { - struct s2d_shape* shape = CONTAINER_OF - (node, struct s2d_shape, scene_attachment); - res_T res = scene_detach_shape(scn, shape, FUNC_NAME); - ASSERT(res == RES_OK); (void)res; - } - return RES_OK; -} -res_T -s2d_scene_begin_session(struct s2d_scene* scn, const int session_mask) -{ - if(!scn) return RES_BAD_ARG; - if(!(session_mask & S2D_TRACE) - && !(session_mask & S2D_SAMPLE) - && !(session_mask & S2D_GET_PRIMITIVE)) { - log_error(scn->dev, - "%s: Invalid session mask. No valid session is defined.\n", - FUNC_NAME); + if(!scn || !shape) { return RES_BAD_ARG; } - return scene_sync(scn, session_mask, FUNC_NAME); -} -res_T -s2d_scene_end_session(struct s2d_scene* scn) -{ - if(!scn) - return RES_BAD_ARG; - if(!scn->session_mask) { - log_error(scn->dev, - "%s: Cannot end session. No session is currently active onto the scene.\n", - FUNC_NAME); - return RES_BAD_ARG; - } - scene_session_clear(scn); - return RES_OK; -} - -res_T -s2d_scene_get_session_mask(struct s2d_scene* scn, int* session_mask) -{ - if(!scn || !session_mask) - return RES_BAD_ARG; - *session_mask = scn->session_mask; - return RES_OK; -} - -res_T -s2d_scene_trace_ray - (struct s2d_scene* scn, - const float org[2], - const float dir[2], - const float range[2], - void* ray_data, - struct s2d_hit* hit) -{ - struct ray_extended ray_ex; - - if(!scn || !org || !dir || !range || !hit) - return RES_BAD_ARG; - if(!f2_is_normalized(dir)) { - log_error(scn->dev, - "%s: The ray direction should be normalized.\n", FUNC_NAME); - return RES_BAD_ARG; - } - if((scn->session_mask & S2D_TRACE) == 0) { - log_error(scn->dev, - "%s: A S2D_TRACE session should be active onto the submitted scene.\n", - FUNC_NAME); - return RES_BAD_OP; - } - if(range[0] > range[1]) { /* Degenerated range <=> disabled ray */ - *hit = S2D_HIT_NULL; + S2D(shape_get_id(shape, &shape_id)); + if(htable_shape_find(&scn->shapes, &shape_id) != NULL) { + log_warning(scn->dev, + "%s: the shape is already attached to the scene.\n", FUNC_NAME); return RES_OK; } - f3(ray_ex.org, org[0], org[1], 0.f); - f3(ray_ex.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.scene = scn; - ray_ex.data = ray_data; - - rtcIntersect(scn->rtc_scn, ray_ex); - hit_setup(scn, &ray_ex, hit); - - return RES_OK; -} - -res_T -s2d_scene_trace_ray_3d - (struct s2d_scene* scn, - const float org[3], - const float dir[3], - const float range[2], - 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(!f3_is_normalized(dir)) { + res = htable_shape_set(&scn->shapes, &shape_id, &shape); + if(res != RES_OK) { log_error(scn->dev, - "%s: The ray direction should be normalized.\n", FUNC_NAME); - return RES_BAD_ARG; - } - if((dir[0] == 0.f && dir[1] == 0.f) || range[0] > range[1]) { - *hit = S2D_HIT_NULL; + "%s: cannot attach the shape to the scene.\n", FUNC_NAME); 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_trace_ray(scn, org, dir_2d, range_2d, ray_data, hit); - if(res != RES_OK) return res; - - if(!S2D_HIT_NONE(hit)) - hit->distance = hit->distance / dot; + S2D(shape_ref_get(shape)); return RES_OK; } res_T -s2d_scene_sample - (struct s2d_scene* scn, - const float u, - const float v, - struct s2d_primitive* primitive, - float* s) -{ - struct geometry* geom; - const struct fltui* fltui_begin, *fltui_end, *fltui_found; - const float* flt_begin, *flt_end, *flt_found; - size_t igeom; - float f; - res_T res = RES_OK; - - if(!scn || !primitive || !s) { - res = RES_BAD_ARG; - goto error; - } - - if(u < 0.f || u >= 1.f || v < 0.f || v >= 1.f) { - log_error(scn->dev, - "%s: The submitted numbers are not canonical, i.e. they ar not in [0, 1[.\n", - FUNC_NAME); - res = RES_BAD_ARG; - goto error; - } - if((scn->session_mask & S2D_SAMPLE) == 0) { - log_error(scn->dev, - "%s: A S2D_SAMPLE session should be active onto the submitted scene.\n", - FUNC_NAME); - res = RES_BAD_OP; - goto error; - } - - /* Find the sampled geometry */ - if(darray_fltui_size_get(&scn->cdf) == 0) { /* No geometry to sample */ - *primitive = S2D_PRIMITIVE_NULL; - goto exit; - } else if(darray_fltui_size_get(&scn->cdf) == 1) { - igeom = darray_fltui_cdata_get(&scn->cdf)[0].ui; - f = u * darray_fltui_cdata_get(&scn->cdf)[0].flt;/* Map u to the CDF bounds */ - } else { - fltui_begin = darray_fltui_cdata_get(&scn->cdf); - fltui_end = fltui_begin + darray_fltui_size_get(&scn->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); - igeom = fltui_found->ui; - - if(fltui_found != fltui_begin) /* Transform u to the geometry CDF bounds */ - f -= fltui_found[-1].flt; - } - geom = darray_geom_data_get(&scn->embree2geoms)[igeom]; - ASSERT(geom); - - /* 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); - - primitive->mesh__ = geom; - primitive->geom_id = geom->name; - primitive->prim_id = (unsigned)(flt_found - flt_begin); - primitive->scene_prim_id = primitive->prim_id + geom->scene_prim_id_offset; - S2D(primitive_sample(primitive, v, s)); - -exit: - return res; -error: - goto exit; -} - -res_T -s2d_scene_get_primitive - (struct s2d_scene* scn, const unsigned iprim, struct s2d_primitive* prim) -{ - struct geometry* geom; - const struct nprims_cdf* begin; - const struct nprims_cdf* end; - const struct nprims_cdf* found; - size_t nprims, igeom, i; - res_T res = RES_OK; - - if(!scn || !prim) { - res = RES_BAD_ARG; - goto error; - } - if((scn->session_mask & S2D_GET_PRIMITIVE) == 0) { - log_error(scn->dev, - "%s: A S2D_GET_PRIMITIVE session should be active onto the submitted scene.\n", - FUNC_NAME); - res = RES_BAD_OP; - goto error; - } - S2D(scene_primitives_count(scn, &nprims)); - if(iprim >= nprims) { - log_error(scn->dev, - "%s: The primitive index %u exceeds the number of scene primitives %u.\n", - FUNC_NAME, iprim, (unsigned)nprims); - res = RES_BAD_ARG; - goto error; - } - - i = iprim; - if(darray_nprims_cdf_size_get(&scn->nprims_cdf) == 1) { - igeom = darray_nprims_cdf_cdata_get(&scn->nprims_cdf)[0].irtc; - } else { - begin = darray_nprims_cdf_cdata_get(&scn->nprims_cdf); - end = begin + darray_nprims_cdf_size_get(&scn->nprims_cdf); - found = std::lower_bound(begin, end, i); - ASSERT(found != end); - igeom = found->irtc; - if(found != begin) { - ASSERT(i >= found[-1].nprims); - i -= found[-1].nprims; - } - } - geom = darray_geom_data_get(&scn->embree2geoms)[igeom]; - ASSERT(geom && i < line_segments_get_nsegments(geom->lines)); - prim->mesh__ = geom; - prim->geom_id = geom->name; - prim->prim_id = (unsigned)i; - prim->scene_prim_id = geom->scene_prim_id_offset + prim->prim_id; - -exit: - return res; -error: - goto exit; -} - -res_T -s2d_scene_primitives_count(struct s2d_scene* scn, size_t* prims_count) -{ - size_t nprims = 0; - res_T res = RES_OK; - - if(!scn || !prims_count) { - res = RES_BAD_ARG; - goto error; - } - if(!scn->session_mask) { - log_error(scn->dev, - "%s: A session must be active on the submitted scene.\n", FUNC_NAME); - res = RES_BAD_OP; - goto error; - } - if((scn->session_mask & S2D_GET_PRIMITIVE) != 0) { - const size_t len = darray_nprims_cdf_size_get(&scn->nprims_cdf); - if(!len) { - nprims = 0; - } else { - nprims = darray_nprims_cdf_cdata_get(&scn->nprims_cdf)[len-1].nprims; - } - } else { - struct list_node* node; - struct s2d_shape* shape; - struct geometry** pgeom; - struct geometry* geom; - - nprims = 0; - LIST_FOR_EACH(node, &scn->shapes) { - shape = CONTAINER_OF(node, struct s2d_shape, scene_attachment); - pgeom = htable_geom_find(&scn->cached_geoms, &shape); - ASSERT(pgeom != NULL); - geom = *pgeom; - - if(geom->is_enabled) { - nprims += line_segments_get_nsegments(geom->lines); - } - } - } -exit: - if(prims_count) *prims_count = nprims; - return res; -error: - goto exit; -} - -res_T -s2d_scene_compute_contour_length(struct s2d_scene* scn, float* out_length) +s2d_scene_detach_shape(struct s2d_scene* scn, struct s2d_shape* shape) { - float length = 0; - res_T res = RES_OK; + size_t n; + unsigned shape_id; - if(!scn || !out_length) { - res = RES_BAD_ARG; - goto error; - } + if(!scn || !shape) return RES_BAD_ARG; - if(!scn->session_mask) { + S2D(shape_get_id(shape, &shape_id)); + if(htable_shape_find(&scn->shapes, &shape_id) == NULL) { log_error(scn->dev, - "%s: A session must be active on the submitted scene.\n", FUNC_NAME); - res = RES_BAD_OP; - goto error; + "%s: the shape is not attached to the scene.\n", FUNC_NAME); + return RES_BAD_ARG; } - if((scn->session_mask & S2D_SAMPLE) != 0) { - /* Retrieve the overall scene contour length from the scene cumulative - * distribution function. Note that the CDF stores the cumulative contour - * length. The real contour length is thus the CDF upper bound */ - size_t len = darray_fltui_size_get(&scn->cdf); - if(!len) { - length = 0.f; - } else { - length = darray_fltui_cdata_get(&scn->cdf)[len-1].flt; - } - } else { - struct list_node* node; - struct s2d_shape* shape; - struct geometry** pgeom; - struct geometry* geom; + n = htable_shape_erase(&scn->shapes, &shape_id); + ASSERT(n == 1); (void)n; - length = 0; - LIST_FOR_EACH(node, &scn->shapes) { - shape = CONTAINER_OF(node, struct s2d_shape, scene_attachment); - pgeom = htable_geom_find(&scn->cached_geoms, &shape); - ASSERT(pgeom != NULL); - geom = *pgeom; + SIG_BROADCAST(&scn->sig_shape_detach, scene_shape_cb_T, ARG2(scn, shape)); - if(geom->is_enabled) { - length += line_segments_compute_length(geom->lines); - } - } - } - -exit: - if(out_length) *out_length = length; - return res; -error: - length = -1.f; - goto exit; + S2D(shape_ref_put(shape)); + return RES_OK; } res_T -s2d_scene_compute_area(struct s2d_scene* scn, float* out_area) +s2d_scene_clear(struct s2d_scene* scn) { - struct list_node* node; - struct s2d_shape* shape; - struct geometry** pgeom; - struct geometry* geom; - float area = 0.f; - res_T res = RES_OK; + struct htable_shape_iterator it, end; - if(!scn || !out_area) { - res = RES_BAD_ARG; - goto error; - } - if(!scn->session_mask) { - log_error(scn->dev, - "%s: A session must be active on the submitted scene.\n", FUNC_NAME); - res = RES_BAD_OP; - goto error; - } - - LIST_FOR_EACH(node, &scn->shapes) { - shape = CONTAINER_OF(node, struct s2d_shape, scene_attachment); - pgeom = htable_geom_find(&scn->cached_geoms, &shape); - ASSERT(pgeom != NULL); - geom = *pgeom; + if(!scn) return RES_BAD_ARG; - if(geom->is_enabled) { - area += line_segments_compute_area(geom->lines, geom->flip_contour); - } - } - if(area < 0.f) { - log_error(scn->dev, - "%s: The area of the scene polygons is negative. The scene shapes might\n" - " not represent closed manifold polygons, or their contour might not point\n" - " inward the polygon.\n", FUNC_NAME); + htable_shape_begin(&scn->shapes, &it); + htable_shape_end(&scn->shapes, &end); + while(!htable_shape_iterator_eq(&it, &end)) { + struct s2d_shape** pshape = htable_shape_iterator_data_get(&it); + struct s2d_shape* shape = *pshape; + SIG_BROADCAST(&scn->sig_shape_detach, scene_shape_cb_T, ARG2(scn, shape)); + S2D(shape_ref_put(shape)); + htable_shape_iterator_next(&it); } + htable_shape_clear(&scn->shapes); -exit: - if(out_area) *out_area = area; - return res; -error: - area = -1.f; - goto exit; + return RES_OK; } res_T -s2d_scene_get_aabb(struct s2d_scene* scn, float lower[2], float upper[2]) +s2d_scene_get_device(struct s2d_scene* scn, struct s2d_device** dev) { - if(!scn || !lower || !upper) return RES_BAD_ARG; - if(!scn->session_mask) { - log_error(scn->dev, - "%s: A session must be active on the submitted scene.\n", FUNC_NAME); - return RES_BAD_OP; - } - f2_set(lower, scn->lower); - f2_set(upper, scn->upper); + if(!scn || !dev) return RES_BAD_ARG; + *dev = scn->dev; return RES_OK; } res_T -s2d_scene_get_device(struct s2d_scene* scn, struct s2d_device** dev) +s2d_scene_get_shapes_count(struct s2d_scene* scn, size_t* nshapes) { - if(!scn || !dev) return RES_BAD_ARG; - *dev = scn->dev; + if(!scn || !nshapes) return RES_BAD_ARG; + *nshapes = htable_shape_size_get(&scn->shapes); return RES_OK; } diff --git a/src/s2d_scene_c.h b/src/s2d_scene_c.h @@ -29,63 +29,29 @@ #ifndef S2D_SCENE_C_H #define S2D_SCENE_C_H -#include "s2d_backend.h" - -#include <rsys/dynamic_array.h> #include <rsys/hash_table.h> #include <rsys/list.h> #include <rsys/ref_count.h> +#include <rsys/signal.h> -/* - * The geometry pointer 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 data type */ -#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* -#define HTABLE_KEY struct s2d_shape* +/* Generate the htable_shape hash table */ +#define HTABLE_NAME shape +#define HTABLE_DATA struct s2d_shape* +#define HTABLE_KEY unsigned /* Id of the shape */ #include <rsys/hash_table.h> -/* Generate the darray_fltui dynamic array */ -struct fltui { float flt; unsigned ui; }; -#define DARRAY_NAME fltui -#define DARRAY_DATA struct fltui -#include <rsys/dynamic_array.h> - -/* Generate the darray_geom_nprims array */ -struct nprims_cdf { unsigned nprims, irtc; }; -#define DARRAY_NAME nprims_cdf -#define DARRAY_DATA struct nprims_cdf -#include <rsys/dynamic_array.h> +/* Declare the scene_shape_cb_T callback data type */ +CLBK(scene_shape_cb_T, ARG2 + (const struct s2d_scene* scn, + const struct s2d_shape* shape)); struct s2d_scene { - struct list_node shapes; /* List of attached shapes */ - struct htable_geom cached_geoms; /* Cached shape geometries */ - struct darray_geom embree2geoms; /* Shape geometries indexed by embree id */ - struct darray_fltui cdf; /* Unormalized CDF */ - struct darray_nprims_cdf nprims_cdf; - - float lower[2], upper[2]; /* AABB of the scene */ + struct htable_shape shapes; /* List of attached shapes */ + struct list_node scnviews; /* Pool of available s3d_scene_view */ - RTCScene rtc_scn; /* Embree scene */ - char is_rtc_scn_outdated; /* Must the embree scene rebuild */ + signal_T sig_shape_detach; - int session_mask; /* Combination of enum s2d_session_flag */ struct s2d_device* dev; - ref_T ref; }; diff --git a/src/s2d_scene_view.c b/src/s2d_scene_view.c @@ -0,0 +1,1155 @@ +/* Copyright (C) |Meso|Star> 2016-2018 (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, + * modify and/or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. */ + +#include "s2d.h" +#include "s2d_device_c.h" +#include "s2d_line_segments.h" +#include "s2d_geometry.h" +#include "s2d_scene_c.h" +#include "s2d_scene_view_c.h" +#include "s2d_shape_c.h" + +#include <rsys/float2.h> +#include <rsys/float3.h> + +#include <algorithm> + +struct ray_extended : public RTCRay { + 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 */ +}; + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static FINLINE bool +operator < (const struct fltui& it, const float val) +{ + /* 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; +} + +static FINLINE bool +operator < (const struct nprims_cdf& it, const size_t iprim) +{ + /* 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; +} + +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; + scnview->rtc_scn_update = 1; /* Notify the scene upd */ + } + geometry_ref_put(geom); +} + +static void +on_shape_detach + (const struct s2d_scene* scn, + const struct s2d_shape* shape, + void* data) +{ + struct geometry** pgeom; + struct geometry* geom; + struct s2d_scene_view* scnview = (struct s2d_scene_view*)data; + unsigned shape_id; + ASSERT(scn && shape && data); + (void)scn; + + S2D(shape_get_id(shape, &shape_id)); + pgeom = htable_geom_find(&scnview->cached_geoms, &shape_id); + + /* The scnview did not register a geometry for this shape. Ignore the signal */ + if(!pgeom) return; + + geom = *pgeom; + if(scnview->mask == 0) { + /* The scnview is NOT in use. Directly rm the cached geometry */ + size_t n; (void)n; + scene_view_destroy_geometry(scnview, geom); + n = htable_geom_erase(&scnview->cached_geoms, &shape_id); + ASSERT(n == 1); + } else { + /* The scnview is in use. Delay the deletion of the cached geometry */ + res_T res = darray_uint_push_back(&scnview->detached_shapes, &shape_id); + if(res != RES_OK) FATAL("Insufficient memory.\n"); + } +} + +static INLINE void +hit_setup(struct s2d_scene_view* scnview, const RTCRay* ray, struct s2d_hit* hit) +{ + struct geometry* geom; + + if((unsigned)ray->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)); + + geom = darray_geom_data_get(&scnview->embree2geoms)[ray->geomID]; + ASSERT(geom); + + hit->prim.mesh__ = geom; + hit->prim.prim_id = ray->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 edge parametric coordinate */ + hit->u = ray->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, + struct geometry* geom) +{ + ASSERT(scnview); + + /* Create the Embree geometry if it is not valid */ + if(geom->irtc == RTC_INVALID_GEOMETRY_ID) { + 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) + 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; + } + } + + darray_geom_data_get(&scnview->embree2geoms)[geom->irtc] = geom; + return RES_OK; +} + +static void +embree_geometry_setup_positions + (struct s2d_scene_view* scnview, struct geometry* geom) +{ + size_t nverts; + size_t i; + float* verts; + float* rtc_verts; + ASSERT(scnview && geom && geom->irtc != RTC_INVALID_GEOMETRY_ID); + + /* 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); + 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*/; + + 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 */ + } + rtcUnmapBuffer(scnview->rtc_scn, geom->irtc, RTC_VERTEX_BUFFER); + rtcUpdateBuffer(scnview->rtc_scn, geom->irtc, RTC_VERTEX_BUFFER); +} + + +static INLINE void +embree_geometry_setup_indices + (struct s2d_scene_view* scnview, struct geometry* geom) +{ + size_t nsegs; + size_t i; + uint32_t* ids; + uint32_t* rtc_ids; + ASSERT(scnview && geom && geom->irtc != RTC_INVALID_GEOMETRY_ID); + + /* 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); + FOR_EACH(i, 0, nsegs) { + size_t id = i*2/*#ids per segment*/; + size_t rtc_id = i*4/*#ids per quad*/; + + rtc_ids[rtc_id + 0] = ids[id + 0] * 2/*#rtc vertices per line vertex*/ + 1; + rtc_ids[rtc_id + 1] = ids[id + 0] * 2/*#rtc vertices per line vertex*/ + 0; + 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); +} + +static INLINE void +embree_geometry_setup_enable_state + (struct s2d_scene_view* scnview, struct geometry* geom) +{ + ASSERT(scnview && geom); + if(geom->is_enabled) { + rtcEnable(scnview->rtc_scn, geom->irtc); + } else { + rtcDisable(scnview->rtc_scn, geom->irtc); + } +} + +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); + + if(!geom->lines->filter.func) { + rtcSetIntersectionFilterFunction(scnview->rtc_scn, geom->irtc, NULL); + } else { + rtcSetIntersectionFilterFunction(scnview->rtc_scn, geom->irtc, filter_wrapper); + rtcSetUserData(scnview->rtc_scn, geom->irtc, &geom->lines->filter); + } +} + +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); + if(!scnview->rtc_scn) { + res = RES_MEM_ERR; + goto error; + } + } + + htable_geom_begin(&scnview->cached_geoms, &it); + htable_geom_end(&scnview->cached_geoms, &end); + + while(!htable_geom_iterator_eq(&it, &end)) { + struct geometry** pgeom = htable_geom_iterator_data_get(&it); + struct geometry* geom = *pgeom; + + htable_geom_iterator_next(&it); + + /* Define whether or not the embree scene is outdated */ + if(geom->embree_outdated_mask) rtc_outdated = 1; + + /* Register the embree geometry */ + res = embree_geometry_register(scnview, geom); + 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_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); + + geom->embree_outdated_mask = 0; + } + + rtc_outdated = rtc_outdated || scnview->rtc_scn_update; + + /* Commit the embree changes */ + if(rtc_outdated) { + rtcCommit(scnview->rtc_scn); + scnview->rtc_commit = 1; /* Notify that the scene view was committed */ + scnview->rtc_scn_update = 0; + } + +exit: + return res; +error: + if(scnview->rtc_scn) { + scnview->rtc_scn = NULL; + rtcDeleteScene(scnview->rtc_scn); + } + darray_geom_clear(&scnview->embree2geoms); + goto exit; +} + +static res_T +scene_view_register_line_segments + (struct s2d_scene_view* scnview, + struct s2d_shape* shape) +{ + struct geometry** pgeom = NULL; + struct geometry* geom = NULL; + size_t iattr; + unsigned shape_id; + res_T res = RES_OK; + ASSERT(scnview && shape); + + /* 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 { + res = geometry_create(scnview->scn->dev, &geom); + if(res != RES_OK) goto error; + res = line_segments_create(scnview->scn->dev, &geom->lines); + if(res != RES_OK) goto error; + res = htable_geom_set(&scnview->cached_geoms, &shape_id, &geom); + if(res != RES_OK) goto error; + 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; + } + + /* Get a reference onto the shape lines segments indices */ + if(geom->lines->indices != shape->lines->indices) { + geom->embree_outdated_mask |= EMBREE_INDICES; + if(geom->lines->indices) { /* Release previous indices of the geometry */ + index_buffer_ref_put(geom->lines->indices); + geom->lines->indices = NULL; + } + ASSERT(shape->lines->indices); + index_buffer_ref_get(shape->lines->indices); + geom->lines->indices = shape->lines->indices; + } + + /* 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; + + if(geom->lines->attribs[iattr]) { /* Release the previous geometry attribs */ + vertex_buffer_ref_put(geom->lines->attribs[iattr]); + geom->lines->attribs[iattr] = NULL; + } + + if(!shape->lines->attribs[iattr]) continue; + + 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]; + } + + /* Update the enable flag */ + if(geom->is_enabled != shape->is_enabled) { + geom->is_enabled = shape->is_enabled; + geom->embree_outdated_mask |= EMBREE_ENABLE; + } + + /* Update the filter function */ + if(geom->lines->filter.func != shape->lines->filter.func + || geom->lines->filter.data != shape->lines->filter.data) { + geom->lines->filter = shape->lines->filter; + 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: + return res; +error: + goto exit; +} + +static res_T +scene_view_compute_nprims_cdf + (struct s2d_scene_view* scnview, const char store_cdf) +{ + struct htable_geom_iterator it, end; + size_t len; + unsigned nprims; + res_T res = RES_OK; + ASSERT(scnview); + ASSERT(darray_nprims_cdf_size_get(&scnview->nprims_cdf) == 0); + + htable_geom_begin(&scnview->cached_geoms, &it); + htable_geom_end(&scnview->cached_geoms, &end); + + nprims = 0; + while(!htable_geom_iterator_eq(&it, &end)) { + const unsigned* shape_id = htable_geom_iterator_key_get(&it); + struct geometry* geom = *htable_geom_iterator_data_get(&it); + struct nprims_cdf cdf; + + htable_geom_iterator_next(&it); + + if(!geom->is_enabled) continue; + + geom->scene_prim_id_offset = nprims; + len = line_segments_get_nsegments(geom->lines); + nprims += (unsigned)len; + + cdf.nprims = nprims; + cdf.ishape = *shape_id; + if(store_cdf && len) { + res = darray_nprims_cdf_push_back(&scnview->nprims_cdf, &cdf); + if(res != RES_OK) goto error; + } + } + +exit: + return res; +error: + darray_nprims_cdf_clear(&scnview->nprims_cdf); + goto exit; +} + +static void +scene_view_compute_scene_aabb(struct s2d_scene_view* scnview) +{ + struct htable_geom_iterator it, end; + float lower[2], upper[2]; + + ASSERT(scnview->lower[0] == FLT_MAX && scnview->upper[0] == -FLT_MAX); + ASSERT(scnview->lower[1] == FLT_MAX && scnview->upper[1] == -FLT_MAX); + + htable_geom_begin(&scnview->cached_geoms, &it); + htable_geom_end(&scnview->cached_geoms, &end); + + while(!htable_geom_iterator_eq(&it, &end)) { + struct geometry* geom = *htable_geom_iterator_data_get(&it); + + htable_geom_iterator_next(&it); + + if(!geom->is_enabled) continue; + + line_segments_compute_aabb(geom->lines, lower, upper); + f2_min(scnview->lower, scnview->lower, lower); + f2_max(scnview->upper, scnview->upper, upper); + } +} + +static res_T +scene_view_compute_cdf(struct s2d_scene_view* scnview) +{ + struct htable_geom_iterator it, end; + size_t len; + float area = 0.f; + res_T res = RES_OK; + ASSERT(scnview); + ASSERT(darray_fltui_size_get(&scnview->cdf) == 0); + + htable_geom_begin(&scnview->cached_geoms, &it); + htable_geom_end(&scnview->cached_geoms, &end); + + while(!htable_geom_iterator_eq(&it, &end)) { + const unsigned* shape_id = htable_geom_iterator_key_get(&it); + struct geometry* geom = *htable_geom_iterator_data_get(&it); + struct fltui fltui; + + htable_geom_iterator_next(&it); + + if(!geom->is_enabled) continue; + + res = line_segments_compute_cdf(geom->lines); + if(res != RES_OK) goto error; + len = darray_float_size_get(&geom->lines->cdf); + + fltui.ui = *shape_id; + fltui.flt = area; + if(len) { + res = darray_fltui_push_back(&scnview->cdf, &fltui); + if(res != RES_OK) goto error; + } + } +exit: + return res; +error: + darray_fltui_clear(&scnview->cdf); + goto exit; +} + +static res_T +scene_view_sync + (struct s2d_scene_view* scnview, + const int mask) +{ + struct htable_shape_iterator it, end; + res_T res = RES_OK; + + ASSERT(scnview); + ASSERT((mask & (S2D_TRACE|S2D_SAMPLE|S2D_GET_PRIMITIVE)) != 0); + + /* Commit the scene shape to the scnview */ + htable_shape_begin(&scnview->scn->shapes, &it); + htable_shape_end(&scnview->scn->shapes, &end); + while(!htable_shape_iterator_eq(&it, &end)) { + struct s2d_shape** pshape = htable_shape_iterator_data_get(&it); + struct s2d_shape* shape = *pshape; + + res = scene_view_register_line_segments(scnview, shape); + if(res != RES_OK) goto error; + htable_shape_iterator_next(&it); + } + + scene_view_compute_scene_aabb(scnview); + + /* Setup the scene for the S2D_TRACE scnview */ + if((mask & S2D_TRACE) != 0) { + res = scene_view_setup_embree(scnview); + if(res != RES_OK) goto error; + } + /* Setup the scene for the S2D_SAMPLE scnview */ + if((mask & S2D_SAMPLE) != 0) { + res = scene_view_compute_cdf(scnview); + if(res != RES_OK) goto error; + } + /* Setup the scene for the scene_primitive_id/S3D_GET_PRIMITIVE scnview */ + res = scene_view_compute_nprims_cdf(scnview, (mask & S2D_GET_PRIMITIVE)!=0); + if(res != RES_OK) goto error; + + scnview->mask = mask; + +exit: + return res; +error: + goto exit; +} + +static res_T +scene_view_create(struct s2d_scene* scn, struct s2d_scene_view** out_scnview) +{ + struct s2d_scene_view* scnview = NULL; + res_T res = RES_OK; + ASSERT(scn && out_scnview); + + if(!is_list_empty(&scn->scnviews)) { + /* Retrieve an already allocated scnview */ + scnview = CONTAINER_OF(list_head(&scn->scnviews), struct s2d_scene_view, node); + list_del(&scnview->node); + ref_get(&scnview->ref); + } else { + scnview = (struct s2d_scene_view*)MEM_CALLOC + (scn->dev->allocator, 1, sizeof(struct s2d_scene_view)); + if(!scnview) { + res = RES_MEM_ERR; + goto error; + } + 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); + f2_splat(scnview->lower, FLT_MAX); + f2_splat(scnview->upper,-FLT_MAX); + ref_init(&scnview->ref); + + CLBK_INIT(&scnview->on_shape_detach_cb); + CLBK_SETUP(&scnview->on_shape_detach_cb, on_shape_detach, scnview); + SIG_CONNECT_CLBK(&scn->sig_shape_detach, &scnview->on_shape_detach_cb); + } + S2D(scene_ref_get(scn)); + scnview->scn = scn; +exit: + *out_scnview = scnview; + return res; +error: + if(scnview) { + S2D(scene_view_ref_put(scnview)); + scnview = NULL; + } + goto exit; +} + +static void +scene_view_release(ref_T* ref) +{ + struct s2d_scene_view* scnview = CONTAINER_OF(ref, struct s2d_scene_view, ref); + size_t i, n; + ASSERT(ref); + + /* Remove the geometry of the shapes detached while the scnview was active */ + n = darray_uint_size_get(&scnview->detached_shapes); + FOR_EACH(i, 0, n) { + const unsigned shape_id = darray_uint_cdata_get(&scnview->detached_shapes)[i]; + struct geometry** pgeom = htable_geom_find(&scnview->cached_geoms, &shape_id); + struct geometry* geom = *pgeom; + size_t tmp; (void)tmp; + scene_view_destroy_geometry(scnview, geom); + tmp = htable_geom_erase(&scnview->cached_geoms, &shape_id); + ASSERT(tmp == 1); + } + darray_uint_clear(&scnview->detached_shapes); + + /* 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); + f2_splat(scnview->upper,-FLT_MAX); + scnview->mask = 0; + scnview->rtc_commit = 0; + + /* Do not physically release the memory space of the scnview. Add it to the + * available scnviews pool of the scene */ + list_add(&scnview->scn->scnviews, &scnview->node); + S2D(scene_ref_put(scnview->scn)); +} + +/******************************************************************************* + * Exported functions + ******************************************************************************/ +res_T +s2d_scene_view_create + (struct s2d_scene* scn, + const int mask, + struct s2d_scene_view** out_scnview) +{ + struct s2d_scene_view* scnview = NULL; + res_T res = RES_OK; + + if(!scn || !out_scnview) { + res = RES_BAD_ARG; + goto error; + } + + if(!(mask & S2D_TRACE) + && !(mask & S2D_SAMPLE) + && !(mask & S2D_GET_PRIMITIVE)) { + log_error(scn->dev, "%s: no valid scene view mask is defined.\n", FUNC_NAME); + res = RES_BAD_ARG; + goto error; + } + + res = scene_view_create(scn, &scnview); + if(res != RES_OK) goto error; + + res = scene_view_sync(scnview, mask); + if(res != RES_OK) goto error; + +exit: + if(out_scnview) *out_scnview = scnview; + return res; +error: + if(scnview) { + S2D(scene_view_ref_put(scnview)); + scnview = NULL; + } + goto exit; +} + +res_T +s2d_scene_view_ref_get(struct s2d_scene_view* scnview) +{ + if(!scnview) return RES_BAD_ARG; + ref_get(&scnview->ref); + return RES_OK; +} + +res_T +s2d_scene_view_ref_put(struct s2d_scene_view* scnview) +{ + if(!scnview) return RES_BAD_ARG; + ref_put(&scnview->ref, scene_view_release); + return RES_OK; +} + +res_T +s2d_scene_view_get_mask(struct s2d_scene_view* scnview, int* mask) +{ + if(scnview || !mask) return RES_BAD_ARG; + *mask = scnview->mask; + return RES_OK; +} + +res_T +s2d_scene_view_trace_ray + (struct s2d_scene_view* scnview, + const float org[2], + const float dir[2], + const float range[2], + 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; +} + +res_T +s2d_scene_view_trace_ray_3d + (struct s2d_scene_view* scnview, + const float org[3], + const float dir[3], + const float range[2], + 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; +} + +res_T +s2d_scene_view_sample + (struct s2d_scene_view* scnview, + const float u, const float v, + struct s2d_primitive* primitive, + float* s) +{ + struct geometry* geom; + const struct fltui* fltui_begin, *fltui_end, *fltui_found; + const float* flt_begin, *flt_end, *flt_found; + size_t igeom; + float f; + res_T res = RES_OK; + + if(!scnview || !primitive || !s) { + res = RES_BAD_ARG; + goto error; + } + + if(u < 0.f || u >= 1.f || v < 0.f || v >= 1.f) { + log_error(scnview->scn->dev, + "%s: The submitted numbers are not canonical, i.e. they ar not in [0, 1[.\n", + FUNC_NAME); + res = RES_BAD_ARG; + goto error; + } + if((scnview->mask & S2D_SAMPLE) == 0) { + log_error(scnview->scn->dev, + "%s: the S2D_SAMPLE flag is not active onto the submitted scene view.\n", + FUNC_NAME); + res = RES_BAD_OP; + goto error; + } + + /* Find the sampled geometry */ + if(darray_fltui_size_get(&scnview->cdf) == 0) { /* No geometry to sample */ + *primitive = S2D_PRIMITIVE_NULL; + goto exit; + } else if(darray_fltui_size_get(&scnview->cdf) == 1) { + igeom = darray_fltui_cdata_get(&scnview->cdf)[0].ui; + /* 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); + igeom = fltui_found->ui; + + if(fltui_found != fltui_begin) /* Transform u to the geometry CDF bounds */ + f -= fltui_found[-1].flt; + } + geom = darray_geom_data_get(&scnview->embree2geoms)[igeom]; + ASSERT(geom); + + /* 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); + + primitive->mesh__ = geom; + primitive->geom_id = geom->name; + primitive->prim_id = (unsigned)(flt_found - flt_begin); + primitive->scene_prim_id = primitive->prim_id + geom->scene_prim_id_offset; + S2D(primitive_sample(primitive, v, s)); + +exit: + return res; +error: + goto exit; +} + +res_T +s2d_scene_view_get_primitive + (struct s2d_scene_view* scnview, + const unsigned iprim, + struct s2d_primitive* prim) +{ + struct geometry** pgeom; + struct geometry* geom; + const struct nprims_cdf* begin; + const struct nprims_cdf* end; + const struct nprims_cdf* found; + size_t nprims; + unsigned ishape; + size_t i; + res_T res = RES_OK; + + if(!scnview || !prim) { + res = RES_BAD_ARG; + goto error; + } + if((scnview->mask & S2D_GET_PRIMITIVE) == 0) { + log_error(scnview->scn->dev, + "%s: the S2D_GET_PRIMITIVE flag is not active onto the submitted scene view.\n", + FUNC_NAME); + res = RES_BAD_OP; + goto error; + } + S2D(scene_view_primitives_count(scnview, &nprims)); + if(iprim >= nprims) { + log_error(scnview->scn->dev, + "%s: The primitive index %u exceeds the number of primitives %u.\n", + FUNC_NAME, iprim, (unsigned)nprims); + res = RES_BAD_ARG; + goto error; + } + + i = iprim; + if(darray_nprims_cdf_size_get(&scnview->nprims_cdf) == 1) { + 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); + ishape = found->ishape; + if(found != begin) { + ASSERT(i >= found[-1].nprims); + i -= found[-1].nprims; + } + } + pgeom = htable_geom_find(&scnview->cached_geoms, &ishape); + ASSERT(pgeom); + geom = *pgeom; + ASSERT(i < line_segments_get_nsegments(geom->lines)); + prim->mesh__ = geom; + prim->geom_id = geom->name; + prim->prim_id = (unsigned)i; + prim->scene_prim_id = geom->scene_prim_id_offset + prim->prim_id; + +exit: + return res; +error: + goto exit; +} + +res_T +s2d_scene_view_primitives_count + (struct s2d_scene_view* scnview, size_t* prims_count) +{ + size_t nprims = 0; + res_T res = RES_OK; + + if(!scnview || !prims_count) { + res = RES_BAD_ARG; + goto error; + } + if((scnview->mask & S2D_GET_PRIMITIVE) != 0) { + const size_t len = darray_nprims_cdf_size_get(&scnview->nprims_cdf); + if(!len) { + nprims = 0; + } else { + nprims = darray_nprims_cdf_cdata_get(&scnview->nprims_cdf)[len-1].nprims; + } + } else { + struct htable_geom_iterator it, end; + + htable_geom_begin(&scnview->cached_geoms, &it); + htable_geom_end(&scnview->cached_geoms, &end); + nprims = 0; + while(!htable_geom_iterator_eq(&it, &end)) { + struct geometry** pgeom = htable_geom_iterator_data_get(&it); + struct geometry* geom = *pgeom; + htable_geom_iterator_next(&it); + + if(geom->is_enabled) { + nprims += line_segments_get_nsegments(geom->lines); + } + } + } + +exit: + if(prims_count) *prims_count = nprims; + return res; +error: + goto exit; +} + +res_T +s2d_scene_view_compute_contour_length + (struct s2d_scene_view* scnview, float* out_length) +{ + float length = 0; + res_T res = RES_OK; + + if(!scnview || !out_length) { + res = RES_BAD_ARG; + goto error; + } + + if((scnview->mask & S2D_SAMPLE) != 0) { + /* Retrieve the overall scene contour length from the scene cumulative + * distribution function. Note that the CDF stores the cumulative contour + * length. The real contour length is thus the CDF upper bound */ + size_t len = darray_fltui_size_get(&scnview->cdf); + if(!len) { + length = 0.f; + } else { + length = darray_fltui_cdata_get(&scnview->cdf)[len-1].flt; + } + } else { + struct htable_geom_iterator it, end; + + htable_geom_begin(&scnview->cached_geoms, &it); + htable_geom_end(&scnview->cached_geoms, &end); + length = 0.f; + while(!htable_geom_iterator_eq(&it, &end)) { + struct geometry** pgeom = htable_geom_iterator_data_get(&it); + struct geometry* geom = *pgeom; + htable_geom_iterator_next(&it); + + if(geom->is_enabled) { + length += line_segments_compute_length(geom->lines); + } + } + } + +exit: + if(out_length) *out_length = length; + return res; +error: + length = -1.f; + goto exit; +} + +res_T +s2d_scene_view_compute_area(struct s2d_scene_view* scnview, float* out_area) +{ + struct htable_geom_iterator it, end; + float area = 0.f; + res_T res = RES_OK; + + if(!scnview || !out_area) { + res = RES_BAD_ARG; + goto error; + } + + htable_geom_begin(&scnview->cached_geoms, &it); + htable_geom_end(&scnview->cached_geoms, &end); + area = 0.f; + while(!htable_geom_iterator_eq(&it, &end)) { + struct geometry** pgeom = htable_geom_iterator_data_get(&it); + struct geometry* geom = *pgeom; + htable_geom_iterator_next(&it); + + if(geom->is_enabled) { + area += line_segments_compute_area(geom->lines, geom->flip_contour); + } + } + +exit: + if(out_area) *out_area = area; + return res; +error: + area = -1.f; + goto exit; +} + +res_T +s2d_scene_view_get_aabb + (struct s2d_scene_view* scnview, float lower[2], float upper[2]) +{ + if(!scnview || !lower || !upper) return RES_BAD_ARG; + f2_set(lower, scnview->lower); + f2_set(upper, scnview->upper); + return RES_OK; +} + +/******************************************************************************* + * Local functions + ******************************************************************************/ +void +scene_view_destroy(struct s2d_scene_view* scnview) +{ + htable_geom_iterator it, end; + ASSERT(scnview && !is_list_empty(&scnview->node)/*Not in use*/); + ASSERT(scnview->mask == 0); + + /* Delete the cached geometries */ + htable_geom_begin(&scnview->cached_geoms, &it); + htable_geom_end(&scnview->cached_geoms, &end); + while(!htable_geom_iterator_eq(&it, &end)) { + struct geometry** pgeom = htable_geom_iterator_data_get(&it); + struct geometry* geom = *pgeom; + scene_view_destroy_geometry(scnview, geom); + htable_geom_iterator_next(&it); + } + + /* Delete the back-end scene */ + if(scnview->rtc_scn) rtcDeleteScene(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); + + /* Remove the scnview from its pool */ + list_del(&scnview->node); + CLBK_DISCONNECT(&scnview->on_shape_detach_cb); + + /* Free the scnview memory space */ + MEM_RM(scnview->scn->dev->allocator, scnview); +} + diff --git a/src/s2d_scene_view_c.h b/src/s2d_scene_view_c.h @@ -0,0 +1,119 @@ +/* Copyright (C) |Meso|Star> 2016-2018 (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, + * modify and/or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. */ + +#ifndef S2D_SCENE_VIEW_C_H +#define S2D_SCENE_VIEW_C_H + +#include "s2d_backend.h" +#include "s2d_scene_c.h" + +#include <rsys/dynamic_array_uint.h> +#include <rsys/hash_table.h> +#include <rsys/list.h> +#include <rsys/ref_count.h> + +/* 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* +#define HTABLE_KEY unsigned /* Id of the shape */ +#include <rsys/hash_table.h> + +/* Generate the darray_fltui dynamic array */ +struct fltui { float flt; unsigned ui; }; +#define DARRAY_NAME fltui +#define DARRAY_DATA struct fltui +#include <rsys/dynamic_array.h> + +/* Generate the darray_geom_nprims array */ +struct nprims_cdf { unsigned nprims, ishape; }; +#define DARRAY_NAME nprims_cdf +#define DARRAY_DATA struct nprims_cdf +#include <rsys/dynamic_array.h> + +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; + + /* Id of Shapes detached while the scnview is active */ + struct darray_uint detached_shapes; + + float lower[2], upper[2]; /* AABB of the scene */ + + /* Callback attached to the sig_shape_detach signal of scn */ + scene_shape_cb_T on_shape_detach_cb; + + int mask; /* Combination of enum s3d_scene_view_flag */ + int rtc_scn_update; /* Define if Embree geometries were deleted/added */ + int rtc_commit; /* Define whether or not the Embree scene was committed */ + RTCScene rtc_scn; /* Embree scene */ + + ref_T ref; + struct s2d_scene* scn; +}; + +extern LOCAL_SYM void +scene_view_destroy + (struct s2d_scene_view* scnview); + +static FINLINE struct geometry* +scene_view_geometry_from_embree_id + (struct s2d_scene_view* scnview, + const unsigned irtc) +{ + struct geometry* geom; + ASSERT(scnview && irtc != RTC_INVALID_GEOMETRY_ID); + ASSERT(irtc < darray_geom_size_get(&scnview->embree2geoms)); + geom = darray_geom_data_get(&scnview->embree2geoms)[irtc]; + ASSERT(geom); + return geom; +} + +#endif /* S2D_SCENE_VIEW_C_H */ diff --git a/src/test_s2d_device.c b/src/test_s2d_device.c @@ -46,40 +46,40 @@ main(int argc, char** argv) struct s2d_device* dev; (void)argc, (void)argv; - CHECK(s2d_device_create(NULL, NULL, 0, NULL), RES_BAD_ARG); - CHECK(s2d_device_create(NULL, NULL, 0, &dev), RES_OK); + CHK(s2d_device_create(NULL, NULL, 0, NULL) == RES_BAD_ARG); + CHK(s2d_device_create(NULL, NULL, 0, &dev) == RES_OK); - CHECK(s2d_device_ref_get(NULL), RES_BAD_ARG); - CHECK(s2d_device_ref_get(dev), RES_OK); - CHECK(s2d_device_ref_put(NULL), RES_BAD_ARG); - CHECK(s2d_device_ref_put(dev), RES_OK); - CHECK(s2d_device_ref_put(dev), RES_OK); + CHK(s2d_device_ref_get(NULL) == RES_BAD_ARG); + CHK(s2d_device_ref_get(dev) == RES_OK); + CHK(s2d_device_ref_put(NULL) == RES_BAD_ARG); + CHK(s2d_device_ref_put(dev) == RES_OK); + CHK(s2d_device_ref_put(dev) == RES_OK); mem_init_proxy_allocator(&allocator, &mem_default_allocator); - CHECK(MEM_ALLOCATED_SIZE(&allocator), 0); - CHECK(s2d_device_create(NULL, &allocator, 0, NULL), RES_BAD_ARG); - CHECK(s2d_device_create(NULL, &allocator, 0, &dev), RES_OK); - CHECK(s2d_device_ref_put(dev), RES_OK); - CHECK(MEM_ALLOCATED_SIZE(&allocator), 0); + CHK(MEM_ALLOCATED_SIZE(&allocator) == 0); + CHK(s2d_device_create(NULL, &allocator, 0, NULL) == RES_BAD_ARG); + CHK(s2d_device_create(NULL, &allocator, 0, &dev) == RES_OK); + CHK(s2d_device_ref_put(dev) == RES_OK); + CHK(MEM_ALLOCATED_SIZE(&allocator) == 0); - CHECK(logger_init(&allocator, &logger), RES_OK); + CHK(logger_init(&allocator, &logger) == RES_OK); logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL); logger_set_stream(&logger, LOG_ERROR, log_stream, NULL); logger_set_stream(&logger, LOG_WARNING, log_stream, NULL); - CHECK(s2d_device_create(&logger, NULL, 0, NULL), RES_BAD_ARG); - CHECK(s2d_device_create(&logger, NULL, 0, &dev), RES_OK); - CHECK(s2d_device_ref_put(dev), RES_OK); + CHK(s2d_device_create(&logger, NULL, 0, NULL) == RES_BAD_ARG); + CHK(s2d_device_create(&logger, NULL, 0, &dev) == RES_OK); + CHK(s2d_device_ref_put(dev) == RES_OK); - CHECK(s2d_device_create(&logger, &allocator, 0, NULL), RES_BAD_ARG); - CHECK(s2d_device_create(&logger, &allocator, 0, &dev), RES_OK); - CHECK(s2d_device_ref_put(dev), RES_OK); + CHK(s2d_device_create(&logger, &allocator, 0, NULL) == RES_BAD_ARG); + CHK(s2d_device_create(&logger, &allocator, 0, &dev) == RES_OK); + CHK(s2d_device_ref_put(dev) == RES_OK); logger_release(&logger); check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator); - CHECK(mem_allocated_size(), 0); + CHK(mem_allocated_size() == 0); return 0; } diff --git a/src/test_s2d_primitive.c b/src/test_s2d_primitive.c @@ -53,11 +53,11 @@ main(int argc, char** argv) mem_init_proxy_allocator(&allocator, &mem_default_allocator); - CHECK(s2d_device_create(NULL, &allocator, 1, &dev), RES_OK); - CHECK(s2d_scene_create(dev, &scn), RES_OK); - CHECK(s2d_shape_create_line_segments(dev, &shape), RES_OK); - CHECK(s2d_shape_get_id(shape, &box_id), RES_OK); - CHECK(s2d_scene_attach_shape(scn, shape), RES_OK); + CHK(s2d_device_create(NULL, &allocator, 1, &dev) == RES_OK); + CHK(s2d_scene_create(dev, &scn) == RES_OK); + CHK(s2d_shape_create_line_segments(dev, &shape) == RES_OK); + CHK(s2d_shape_get_id(shape, &box_id) == RES_OK); + CHK(s2d_scene_attach_shape(scn, shape) == RES_OK); vdata.usage = S2D_POSITION; vdata.type = S2D_FLOAT2; @@ -66,83 +66,83 @@ main(int argc, char** argv) (shape, box_nsegs, line_segments_get_ids, box_nverts, &vdata, 1, (void*)&box_desc), RES_OK); - CHECK(s2d_scene_begin_session(scn, S2D_SAMPLE), RES_OK); - CHECK(s2d_scene_sample(scn, 0, 0, &prim, &s), RES_OK); - CHECK(s2d_scene_end_session(scn), RES_OK); + CHK(s2d_scene_begin_session(scn, S2D_SAMPLE) == RES_OK); + CHK(s2d_scene_sample(scn, 0, 0, &prim, &s) == RES_OK); + CHK(s2d_scene_end_session(scn) == RES_OK); #define GET_ATTRIB s2d_primitive_get_attrib - CHECK(GET_ATTRIB(NULL, S2D_ATTRIBS_COUNT__, 2, NULL), RES_BAD_ARG); - CHECK(GET_ATTRIB(&prim, S2D_ATTRIBS_COUNT__, 2, NULL), RES_BAD_ARG); - CHECK(GET_ATTRIB(NULL, S2D_ATTRIBS_COUNT__, s, NULL), RES_BAD_ARG); - CHECK(GET_ATTRIB(&prim, S2D_ATTRIBS_COUNT__, s, NULL), RES_BAD_ARG); - CHECK(GET_ATTRIB(NULL, S2D_ATTRIBS_COUNT__, 2, &attr), RES_BAD_ARG); - CHECK(GET_ATTRIB(&prim, S2D_ATTRIBS_COUNT__, 2, &attr), RES_BAD_ARG); - CHECK(GET_ATTRIB(NULL, S2D_ATTRIBS_COUNT__, s, &attr), RES_BAD_ARG); - CHECK(GET_ATTRIB(&prim, S2D_ATTRIBS_COUNT__, s, &attr), RES_BAD_ARG); - CHECK(GET_ATTRIB(NULL, S2D_POSITION, 2, NULL), RES_BAD_ARG); - CHECK(GET_ATTRIB(&prim, S2D_POSITION, 2, NULL), RES_BAD_ARG); - CHECK(GET_ATTRIB(NULL, S2D_POSITION, s, NULL), RES_BAD_ARG); - CHECK(GET_ATTRIB(&prim, S2D_POSITION, s, NULL), RES_BAD_ARG); - CHECK(GET_ATTRIB(NULL, S2D_POSITION, 2, &attr), RES_BAD_ARG); - CHECK(GET_ATTRIB(&prim, S2D_POSITION, 2, &attr), RES_BAD_ARG); - CHECK(GET_ATTRIB(NULL, S2D_POSITION, s, &attr), RES_BAD_ARG); - CHECK(GET_ATTRIB(&prim, S2D_POSITION, s, &attr), RES_OK); - CHECK(attr.type, S2D_FLOAT2); - CHECK(attr.usage, S2D_POSITION); - - CHECK(GET_ATTRIB(&prim, S2D_GEOMETRY_NORMAL, s, &attr), RES_OK); + CHK(GET_ATTRIB(NULL, S2D_ATTRIBS_COUNT__, 2, NULL) == RES_BAD_ARG); + CHK(GET_ATTRIB(&prim, S2D_ATTRIBS_COUNT__, 2, NULL) == RES_BAD_ARG); + CHK(GET_ATTRIB(NULL, S2D_ATTRIBS_COUNT__, s, NULL) == RES_BAD_ARG); + CHK(GET_ATTRIB(&prim, S2D_ATTRIBS_COUNT__, s, NULL) == RES_BAD_ARG); + CHK(GET_ATTRIB(NULL, S2D_ATTRIBS_COUNT__, 2, &attr) == RES_BAD_ARG); + CHK(GET_ATTRIB(&prim, S2D_ATTRIBS_COUNT__, 2, &attr) == RES_BAD_ARG); + CHK(GET_ATTRIB(NULL, S2D_ATTRIBS_COUNT__, s, &attr) == RES_BAD_ARG); + CHK(GET_ATTRIB(&prim, S2D_ATTRIBS_COUNT__, s, &attr) == RES_BAD_ARG); + CHK(GET_ATTRIB(NULL, S2D_POSITION, 2, NULL) == RES_BAD_ARG); + CHK(GET_ATTRIB(&prim, S2D_POSITION, 2, NULL) == RES_BAD_ARG); + CHK(GET_ATTRIB(NULL, S2D_POSITION, s, NULL) == RES_BAD_ARG); + CHK(GET_ATTRIB(&prim, S2D_POSITION, s, NULL) == RES_BAD_ARG); + CHK(GET_ATTRIB(NULL, S2D_POSITION, 2, &attr) == RES_BAD_ARG); + CHK(GET_ATTRIB(&prim, S2D_POSITION, 2, &attr) == RES_BAD_ARG); + CHK(GET_ATTRIB(NULL, S2D_POSITION, s, &attr) == RES_BAD_ARG); + CHK(GET_ATTRIB(&prim, S2D_POSITION, s, &attr) == RES_OK); + CHK(attr.type == S2D_FLOAT2); + CHK(attr.usage == S2D_POSITION); + + CHK(GET_ATTRIB(&prim, S2D_GEOMETRY_NORMAL, s, &attr) == RES_OK); f2_normalize(attr.value, attr.value); switch(prim.prim_id) { - case 0: CHECK(f2_eq_eps(attr.value, f2(tmp, 0.f, 1.f), 1.e-6f), 1); break; - case 1: CHECK(f2_eq_eps(attr.value, f2(tmp, 1.f, 0.f), 1.e-6f), 1); break; - case 2: CHECK(f2_eq_eps(attr.value, f2(tmp, 0.f,-1.f), 1.e-6f), 1); break; - case 3: CHECK(f2_eq_eps(attr.value, f2(tmp,-1.f, 0.f), 1.e-6f), 1); break; - default: CHECK(0, 1); /* Invalid primitive id */ + case 0: CHK(f2_eq_eps(attr.value, f2(tmp, 0.f, 1.f), 1.e-6f) == 1); break; + case 1: CHK(f2_eq_eps(attr.value, f2(tmp, 1.f, 0.f), 1.e-6f) == 1); break; + case 2: CHK(f2_eq_eps(attr.value, f2(tmp, 0.f,-1.f), 1.e-6f) == 1); break; + case 3: CHK(f2_eq_eps(attr.value, f2(tmp,-1.f, 0.f), 1.e-6f) == 1); break; + default: CHK(0 == 1); /* Invalid primitive id */ } - CHECK(GET_ATTRIB(&S2D_PRIMITIVE_NULL, S2D_GEOMETRY_NORMAL, s, &attr), + CHK(GET_ATTRIB(&S2D_PRIMITIVE_NULL, S2D_GEOMETRY_NORMAL, s == &attr), RES_BAD_ARG); #undef GET_ATTRIB - CHECK(s2d_scene_begin_session(scn, S2D_GET_PRIMITIVE), RES_OK); - CHECK(s2d_scene_primitives_count(scn, &nprims), RES_OK); - CHECK(nprims, 4); - CHECK(s2d_scene_end_session(scn), RES_OK); - - CHECK(s2d_scene_begin_session(scn, S2D_TRACE), RES_OK); - CHECK(s2d_scene_primitives_count(scn, &nprims), RES_OK); - CHECK(nprims, 4); - CHECK(s2d_scene_end_session(scn), RES_OK); - - CHECK(s2d_primitive_compute_length(NULL, NULL), RES_BAD_ARG); - CHECK(s2d_primitive_compute_length(&prim, NULL), RES_BAD_ARG); - CHECK(s2d_primitive_compute_length(NULL, &length), RES_BAD_ARG); - CHECK(s2d_primitive_compute_length(&prim, &length), RES_OK); - CHECK(eq_epsf(length, 2, 1.e-6f), 1); - - CHECK(s2d_primitive_sample(NULL, 2.f, NULL), RES_BAD_ARG); - CHECK(s2d_primitive_sample(&prim, 2.f, NULL), RES_BAD_ARG); - CHECK(s2d_primitive_sample(NULL, 0.5f, NULL), RES_BAD_ARG); - CHECK(s2d_primitive_sample(&prim, 0.5f, NULL), RES_BAD_ARG); - CHECK(s2d_primitive_sample(NULL, 2.f, &s), RES_BAD_ARG); - CHECK(s2d_primitive_sample(&prim, 2.f, &s), RES_BAD_ARG); - CHECK(s2d_primitive_sample(NULL, 0.5f, &s), RES_BAD_ARG); - CHECK(s2d_primitive_sample(&prim, 0.5f, &s), RES_OK); - CHECK(eq_epsf(s, 0.5f, 1.e-6f), 1); + CHK(s2d_scene_begin_session(scn, S2D_GET_PRIMITIVE) == RES_OK); + CHK(s2d_scene_primitives_count(scn, &nprims) == RES_OK); + CHK(nprims == 4); + CHK(s2d_scene_end_session(scn) == RES_OK); + + CHK(s2d_scene_begin_session(scn, S2D_TRACE) == RES_OK); + CHK(s2d_scene_primitives_count(scn, &nprims) == RES_OK); + CHK(nprims == 4); + CHK(s2d_scene_end_session(scn) == RES_OK); + + CHK(s2d_primitive_compute_length(NULL, NULL) == RES_BAD_ARG); + CHK(s2d_primitive_compute_length(&prim, NULL) == RES_BAD_ARG); + CHK(s2d_primitive_compute_length(NULL, &length) == RES_BAD_ARG); + CHK(s2d_primitive_compute_length(&prim, &length) == RES_OK); + CHK(eq_epsf(length, 2, 1.e-6f) == 1); + + CHK(s2d_primitive_sample(NULL, 2.f, NULL) == RES_BAD_ARG); + CHK(s2d_primitive_sample(&prim, 2.f, NULL) == RES_BAD_ARG); + CHK(s2d_primitive_sample(NULL, 0.5f, NULL) == RES_BAD_ARG); + CHK(s2d_primitive_sample(&prim, 0.5f, NULL) == RES_BAD_ARG); + CHK(s2d_primitive_sample(NULL, 2.f, &s) == RES_BAD_ARG); + CHK(s2d_primitive_sample(&prim, 2.f, &s) == RES_BAD_ARG); + CHK(s2d_primitive_sample(NULL, 0.5f, &s) == RES_BAD_ARG); + CHK(s2d_primitive_sample(&prim, 0.5f, &s) == RES_OK); + CHK(eq_epsf(s, 0.5f, 1.e-6f) == 1); FOR_EACH(i, 0, NSAMPS) { - CHECK(s2d_primitive_sample(&prim, rand_canonic(), &s), RES_OK); - CHECK(s >= 0.f, 1); - CHECK(s <= 1.f, 1); + CHK(s2d_primitive_sample(&prim, rand_canonic(), &s) == RES_OK); + CHK(s >= 0.f == 1); + CHK(s <= 1.f == 1); } - CHECK(s2d_device_ref_put(dev), RES_OK); - CHECK(s2d_scene_ref_put(scn), RES_OK); - CHECK(s2d_shape_ref_put(shape), RES_OK); + CHK(s2d_device_ref_put(dev) == RES_OK); + CHK(s2d_scene_ref_put(scn) == RES_OK); + CHK(s2d_shape_ref_put(shape) == RES_OK); check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator); - CHECK(mem_allocated_size(), 0); + CHK(mem_allocated_size() == 0); return 0; } diff --git a/src/test_s2d_sample.c b/src/test_s2d_sample.c @@ -49,47 +49,47 @@ main(int argc, char** argv) mem_init_proxy_allocator(&allocator, &mem_default_allocator); - CHECK(s2d_device_create(NULL, &allocator, 1, &dev), RES_OK); - CHECK(s2d_scene_create(dev, &scn), RES_OK); - CHECK(s2d_shape_create_line_segments(dev, &shape), RES_OK); - - CHECK(s2d_shape_get_id(shape, &box_id), RES_OK); - CHECK(s2d_scene_attach_shape(scn, shape), RES_OK); - CHECK(s2d_scene_begin_session(scn, S2D_SAMPLE), RES_OK); - - CHECK(s2d_scene_sample(NULL, 1, 1, NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_sample(scn, 1, 1, NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_sample(NULL, 0, 1, NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_sample(scn, 0, 1, NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_sample(NULL, 1, 0, NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_sample(scn, 1, 0, NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_sample(NULL, 0, 0, NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_sample(scn, 0, 0, NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_sample(NULL, 1, 1, &prim, NULL), RES_BAD_ARG); - CHECK(s2d_scene_sample(scn, 1, 1, &prim, NULL), RES_BAD_ARG); - CHECK(s2d_scene_sample(NULL, 0, 1, &prim, NULL), RES_BAD_ARG); - CHECK(s2d_scene_sample(scn, 0, 1, &prim, NULL), RES_BAD_ARG); - CHECK(s2d_scene_sample(NULL, 1, 0, &prim, NULL), RES_BAD_ARG); - CHECK(s2d_scene_sample(scn, 1, 0, &prim, NULL), RES_BAD_ARG); - CHECK(s2d_scene_sample(NULL, 0, 0, &prim, NULL), RES_BAD_ARG); - CHECK(s2d_scene_sample(scn, 0, 0, &prim, NULL), RES_BAD_ARG); - CHECK(s2d_scene_sample(NULL, 1, 1, NULL, &s), RES_BAD_ARG); - CHECK(s2d_scene_sample(scn, 1, 1, NULL, &s), RES_BAD_ARG); - CHECK(s2d_scene_sample(NULL, 0, 1, NULL,&s), RES_BAD_ARG); - CHECK(s2d_scene_sample(scn, 0, 1, NULL, &s), RES_BAD_ARG); - CHECK(s2d_scene_sample(NULL, 1, 0, NULL, &s), RES_BAD_ARG); - CHECK(s2d_scene_sample(scn, 1, 0, NULL, &s), RES_BAD_ARG); - CHECK(s2d_scene_sample(NULL, 0, 0, NULL, &s), RES_BAD_ARG); - CHECK(s2d_scene_sample(scn, 0, 0, NULL, &s), RES_BAD_ARG); - CHECK(s2d_scene_sample(NULL, 1, 1, &prim, &s), RES_BAD_ARG); - CHECK(s2d_scene_sample(scn, 1, 1, &prim, &s), RES_BAD_ARG); - CHECK(s2d_scene_sample(NULL, 0, 1, &prim, &s), RES_BAD_ARG); - CHECK(s2d_scene_sample(scn, 0, 1, &prim, &s), RES_BAD_ARG); - CHECK(s2d_scene_sample(NULL, 1, 0, &prim, &s), RES_BAD_ARG); - CHECK(s2d_scene_sample(scn, 1, 0, &prim, &s), RES_BAD_ARG); - CHECK(s2d_scene_sample(NULL, 0, 0, &prim, &s), RES_BAD_ARG); - CHECK(s2d_scene_sample(scn, 0, 0, &prim, &s), RES_OK); - CHECK(S2D_PRIMITIVE_EQ(&prim, &S2D_PRIMITIVE_NULL), 1); + CHK(s2d_device_create(NULL, &allocator, 1, &dev) == RES_OK); + CHK(s2d_scene_create(dev, &scn) == RES_OK); + CHK(s2d_shape_create_line_segments(dev, &shape) == RES_OK); + + CHK(s2d_shape_get_id(shape, &box_id) == RES_OK); + CHK(s2d_scene_attach_shape(scn, shape) == RES_OK); + CHK(s2d_scene_begin_session(scn, S2D_SAMPLE) == RES_OK); + + CHK(s2d_scene_sample(NULL, 1, 1, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_sample(scn, 1, 1, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_sample(NULL, 0, 1, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_sample(scn, 0, 1, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_sample(NULL, 1, 0, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_sample(scn, 1, 0, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_sample(NULL, 0, 0, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_sample(scn, 0, 0, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_sample(NULL, 1, 1, &prim, NULL) == RES_BAD_ARG); + CHK(s2d_scene_sample(scn, 1, 1, &prim, NULL) == RES_BAD_ARG); + CHK(s2d_scene_sample(NULL, 0, 1, &prim, NULL) == RES_BAD_ARG); + CHK(s2d_scene_sample(scn, 0, 1, &prim, NULL) == RES_BAD_ARG); + CHK(s2d_scene_sample(NULL, 1, 0, &prim, NULL) == RES_BAD_ARG); + CHK(s2d_scene_sample(scn, 1, 0, &prim, NULL) == RES_BAD_ARG); + CHK(s2d_scene_sample(NULL, 0, 0, &prim, NULL) == RES_BAD_ARG); + CHK(s2d_scene_sample(scn, 0, 0, &prim, NULL) == RES_BAD_ARG); + CHK(s2d_scene_sample(NULL, 1, 1, NULL, &s) == RES_BAD_ARG); + CHK(s2d_scene_sample(scn, 1, 1, NULL, &s) == RES_BAD_ARG); + CHK(s2d_scene_sample(NULL, 0, 1, NULL,&s) == RES_BAD_ARG); + CHK(s2d_scene_sample(scn, 0, 1, NULL, &s) == RES_BAD_ARG); + CHK(s2d_scene_sample(NULL, 1, 0, NULL, &s) == RES_BAD_ARG); + CHK(s2d_scene_sample(scn, 1, 0, NULL, &s) == RES_BAD_ARG); + CHK(s2d_scene_sample(NULL, 0, 0, NULL, &s) == RES_BAD_ARG); + CHK(s2d_scene_sample(scn, 0, 0, NULL, &s) == RES_BAD_ARG); + CHK(s2d_scene_sample(NULL, 1, 1, &prim, &s) == RES_BAD_ARG); + CHK(s2d_scene_sample(scn, 1, 1, &prim, &s) == RES_BAD_ARG); + CHK(s2d_scene_sample(NULL, 0, 1, &prim, &s) == RES_BAD_ARG); + CHK(s2d_scene_sample(scn, 0, 1, &prim, &s) == RES_BAD_ARG); + CHK(s2d_scene_sample(NULL, 1, 0, &prim, &s) == RES_BAD_ARG); + CHK(s2d_scene_sample(scn, 1, 0, &prim, &s) == RES_BAD_ARG); + CHK(s2d_scene_sample(NULL, 0, 0, &prim, &s) == RES_BAD_ARG); + CHK(s2d_scene_sample(scn, 0, 0, &prim, &s) == RES_OK); + CHK(S2D_PRIMITIVE_EQ(&prim, &S2D_PRIMITIVE_NULL) == 1); vdata.usage = S2D_POSITION; vdata.type = S2D_FLOAT2; @@ -98,20 +98,20 @@ main(int argc, char** argv) (shape, box_nsegs, line_segments_get_ids, box_nverts, &vdata, 1, (void*)&box_desc), RES_OK); - CHECK(s2d_scene_sample(scn, 0, 0, &prim, &s), RES_OK); - CHECK(S2D_PRIMITIVE_EQ(&prim, &S2D_PRIMITIVE_NULL), 1); - CHECK(s2d_scene_end_session(scn), RES_OK); + CHK(s2d_scene_sample(scn, 0, 0, &prim, &s) == RES_OK); + CHK(S2D_PRIMITIVE_EQ(&prim, &S2D_PRIMITIVE_NULL) == 1); + CHK(s2d_scene_end_session(scn) == RES_OK); - CHECK(s2d_scene_begin_session(scn, S2D_SAMPLE), RES_OK); - CHECK(s2d_scene_sample(scn, 0, 0, &prim, &s), RES_OK); - CHECK(S2D_PRIMITIVE_EQ(&prim, &S2D_PRIMITIVE_NULL), 0); + CHK(s2d_scene_begin_session(scn, S2D_SAMPLE) == RES_OK); + CHK(s2d_scene_sample(scn, 0, 0, &prim, &s) == RES_OK); + CHK(S2D_PRIMITIVE_EQ(&prim, &S2D_PRIMITIVE_NULL) == 0); - CHECK(prim.prim_id < 4, 1); - CHECK(prim.geom_id, box_id); - CHECK(s, 0); + CHK(prim.prim_id < 4 == 1); + CHK(prim.geom_id == box_id); + CHK(s == 0); /* Should take effect on the next session */ - CHECK(s2d_shape_flip_contour(shape), RES_OK); + CHK(s2d_shape_flip_contour(shape) == RES_OK); FOR_EACH(i, 0, NSAMPS) { struct s2d_attrib attr_position; @@ -120,10 +120,10 @@ main(int argc, char** argv) const float v = rand_canonic(); float N[2], P[2]; - CHECK(s2d_scene_sample(scn, u, v, &prim, &s), RES_OK); - CHECK(S2D_PRIMITIVE_EQ(&prim, &S2D_PRIMITIVE_NULL), 0); - CHECK(prim.prim_id < 4, 1); - CHECK(prim.geom_id, box_id); + CHK(s2d_scene_sample(scn, u, v, &prim, &s) == RES_OK); + CHK(S2D_PRIMITIVE_EQ(&prim, &S2D_PRIMITIVE_NULL) == 0); + CHK(prim.prim_id < 4 == 1); + CHK(prim.geom_id == box_id); CHECK(s2d_primitive_get_attrib (&prim, S2D_POSITION, s, &attr_position), RES_OK); @@ -137,32 +137,32 @@ main(int argc, char** argv) case 1: f2(P, -1.f, 1.f*s + (1-s)*-1.f); f2(N, 1.f, 0.f); break; case 2: f2(P, 1.f*s + (1-s)* -1.f, 1.f); f2(N, 0.f,-1.f); break; case 3: f2(P, 1.f, -1.f*s + (1-s)* 1.f); f2(N,-1.f, 0.f); break; - default: CHECK(0, 1); break; /* Invalid primitive id */ + default: CHK(0 == 1); break; /* Invalid primitive id */ } - CHECK(f2_eq_eps(P, attr_position.value, 1.e-6f), 1); - CHECK(f2_eq_eps(N, attr_normal.value, 1.e-6f), 1); + CHK(f2_eq_eps(P, attr_position.value, 1.e-6f) == 1); + CHK(f2_eq_eps(N, attr_normal.value, 1.e-6f) == 1); } - CHECK(s2d_scene_end_session(scn), RES_OK); + CHK(s2d_scene_end_session(scn) == RES_OK); - CHECK(s2d_scene_begin_session(scn, S2D_TRACE), RES_OK); - CHECK(s2d_scene_sample(scn, 0, 0, &prim, &s), RES_BAD_OP); - CHECK(s2d_scene_end_session(scn), RES_OK); + CHK(s2d_scene_begin_session(scn, S2D_TRACE) == RES_OK); + CHK(s2d_scene_sample(scn, 0, 0, &prim, &s) == RES_BAD_OP); + CHK(s2d_scene_end_session(scn) == RES_OK); - CHECK(s2d_scene_begin_session(scn, S2D_SAMPLE), RES_OK); + CHK(s2d_scene_begin_session(scn, S2D_SAMPLE) == RES_OK); FOR_EACH(i, 0, NSAMPS) { struct s2d_attrib attr; const float u = rand_canonic(); const float v = rand_canonic(); float N[2]; - CHECK(s2d_scene_sample(scn, u, v, &prim, &s), RES_OK); - CHECK(S2D_PRIMITIVE_EQ(&prim, &S2D_PRIMITIVE_NULL), 0); - CHECK(prim.prim_id < 4, 1); - CHECK(prim.geom_id, box_id); + CHK(s2d_scene_sample(scn, u, v, &prim, &s) == RES_OK); + CHK(S2D_PRIMITIVE_EQ(&prim, &S2D_PRIMITIVE_NULL) == 0); + CHK(prim.prim_id < 4 == 1); + CHK(prim.geom_id == box_id); - CHECK(s2d_primitive_get_attrib(&prim, S2D_GEOMETRY_NORMAL, s, &attr), RES_OK); + CHK(s2d_primitive_get_attrib(&prim, S2D_GEOMETRY_NORMAL, s, &attr) == RES_OK); f2_normalize(attr.value, attr.value); switch(prim.prim_id) { @@ -170,21 +170,21 @@ main(int argc, char** argv) case 1: f2(N,-1.f, 0.f); break; case 2: f2(N, 0.f, 1.f); break; case 3: f2(N, 1.f, 0.f); break; - default: CHECK(0, 1); break; /* Invalid primitive id */ + default: CHK(0 == 1); break; /* Invalid primitive id */ } - CHECK(f2_eq_eps(N, attr.value, 1.e-6f), 1); + CHK(f2_eq_eps(N, attr.value, 1.e-6f) == 1); } - CHECK(s2d_scene_end_session(scn), RES_OK); + CHK(s2d_scene_end_session(scn) == RES_OK); - CHECK(s2d_device_ref_put(dev), RES_OK); - CHECK(s2d_scene_ref_put(scn), RES_OK); - CHECK(s2d_shape_ref_put(shape), RES_OK); + CHK(s2d_device_ref_put(dev) == RES_OK); + CHK(s2d_scene_ref_put(scn) == RES_OK); + CHK(s2d_shape_ref_put(shape) == RES_OK); check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator); - CHECK(mem_allocated_size(), 0); + CHK(mem_allocated_size() == 0); return 0; } diff --git a/src/test_s2d_scene.c b/src/test_s2d_scene.c @@ -52,66 +52,66 @@ main(int argc, char** argv) mem_init_proxy_allocator(&allocator, &mem_default_allocator); - CHECK(s2d_device_create(NULL, &allocator, 1, &dev), RES_OK); - - CHECK(s2d_scene_create(NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_create(dev, NULL), RES_BAD_ARG); - CHECK(s2d_scene_create(NULL, &scn), RES_BAD_ARG); - CHECK(s2d_scene_create(dev, &scn), RES_OK); - - CHECK(s2d_scene_ref_get(NULL), RES_BAD_ARG); - CHECK(s2d_scene_ref_get(scn), RES_OK); - CHECK(s2d_scene_ref_put(NULL), RES_BAD_ARG); - CHECK(s2d_scene_ref_put(scn), RES_OK); - CHECK(s2d_scene_ref_put(scn), RES_OK); - - CHECK(s2d_scene_create(dev, &scn), RES_OK); - CHECK(s2d_shape_create_line_segments(dev, &shape), RES_OK); - - CHECK(s2d_scene_attach_shape(NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_attach_shape(scn, NULL), RES_BAD_ARG); - CHECK(s2d_scene_attach_shape(NULL, shape), RES_BAD_ARG); - CHECK(s2d_scene_attach_shape(scn, shape), RES_OK); - CHECK(s2d_scene_attach_shape(scn, shape), RES_BAD_ARG); - - CHECK(s2d_scene_detach_shape(NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_detach_shape(scn, NULL), RES_BAD_ARG); - CHECK(s2d_scene_detach_shape(NULL, shape), RES_BAD_ARG); - CHECK(s2d_scene_detach_shape(scn, shape), RES_OK); - CHECK(s2d_scene_detach_shape(scn, shape), RES_BAD_ARG); - - CHECK(s2d_scene_clear(NULL), RES_BAD_ARG); - CHECK(s2d_scene_clear(scn), RES_OK); - CHECK(s2d_scene_clear(scn), RES_OK); - CHECK(s2d_scene_attach_shape(scn, shape), RES_OK); - CHECK(s2d_scene_clear(scn), RES_OK); - - CHECK(s2d_scene_begin_session(NULL, 0), RES_BAD_ARG); - CHECK(s2d_scene_begin_session(scn, 0), RES_BAD_ARG); - CHECK(s2d_scene_begin_session(NULL, S2D_TRACE), RES_BAD_ARG); - CHECK(s2d_scene_begin_session(scn, S2D_TRACE), RES_OK); - - CHECK(s2d_scene_get_session_mask(NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_get_session_mask(scn, NULL), RES_BAD_ARG); - CHECK(s2d_scene_get_session_mask(NULL, &mask), RES_BAD_ARG); - CHECK(s2d_scene_get_session_mask(scn, &mask), RES_OK); - CHECK(mask, S2D_TRACE); - - CHECK(s2d_scene_primitives_count(NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_primitives_count(scn, NULL), RES_BAD_ARG); - CHECK(s2d_scene_primitives_count(NULL, &nprims), RES_BAD_ARG); - CHECK(s2d_scene_primitives_count(scn, &nprims), RES_OK); - CHECK(nprims, 0); - - CHECK(s2d_scene_attach_shape(scn, shape), RES_OK); - CHECK(s2d_scene_clear(scn), RES_BAD_OP); - CHECK(s2d_scene_detach_shape(scn, shape), RES_OK); - - CHECK(s2d_scene_end_session(NULL), RES_BAD_ARG); - CHECK(s2d_scene_end_session(scn), RES_OK); - CHECK(s2d_scene_end_session(scn), RES_BAD_ARG); - CHECK(s2d_scene_get_session_mask(scn, &mask), RES_OK); - CHECK(mask, 0); + CHK(s2d_device_create(NULL, &allocator, 1, &dev) == RES_OK); + + CHK(s2d_scene_create(NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_create(dev, NULL) == RES_BAD_ARG); + CHK(s2d_scene_create(NULL, &scn) == RES_BAD_ARG); + CHK(s2d_scene_create(dev, &scn) == RES_OK); + + CHK(s2d_scene_ref_get(NULL) == RES_BAD_ARG); + CHK(s2d_scene_ref_get(scn) == RES_OK); + CHK(s2d_scene_ref_put(NULL) == RES_BAD_ARG); + CHK(s2d_scene_ref_put(scn) == RES_OK); + CHK(s2d_scene_ref_put(scn) == RES_OK); + + CHK(s2d_scene_create(dev, &scn) == RES_OK); + CHK(s2d_shape_create_line_segments(dev, &shape) == RES_OK); + + CHK(s2d_scene_attach_shape(NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_attach_shape(scn, NULL) == RES_BAD_ARG); + CHK(s2d_scene_attach_shape(NULL, shape) == RES_BAD_ARG); + CHK(s2d_scene_attach_shape(scn, shape) == RES_OK); + CHK(s2d_scene_attach_shape(scn, shape) == RES_BAD_ARG); + + CHK(s2d_scene_detach_shape(NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_detach_shape(scn, NULL) == RES_BAD_ARG); + CHK(s2d_scene_detach_shape(NULL, shape) == RES_BAD_ARG); + CHK(s2d_scene_detach_shape(scn, shape) == RES_OK); + CHK(s2d_scene_detach_shape(scn, shape) == RES_BAD_ARG); + + CHK(s2d_scene_clear(NULL) == RES_BAD_ARG); + CHK(s2d_scene_clear(scn) == RES_OK); + CHK(s2d_scene_clear(scn) == RES_OK); + CHK(s2d_scene_attach_shape(scn, shape) == RES_OK); + CHK(s2d_scene_clear(scn) == RES_OK); + + CHK(s2d_scene_begin_session(NULL, 0) == RES_BAD_ARG); + CHK(s2d_scene_begin_session(scn, 0) == RES_BAD_ARG); + CHK(s2d_scene_begin_session(NULL, S2D_TRACE) == RES_BAD_ARG); + CHK(s2d_scene_begin_session(scn, S2D_TRACE) == RES_OK); + + CHK(s2d_scene_get_session_mask(NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_get_session_mask(scn, NULL) == RES_BAD_ARG); + CHK(s2d_scene_get_session_mask(NULL, &mask) == RES_BAD_ARG); + CHK(s2d_scene_get_session_mask(scn, &mask) == RES_OK); + CHK(mask == S2D_TRACE); + + CHK(s2d_scene_primitives_count(NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_primitives_count(scn, NULL) == RES_BAD_ARG); + CHK(s2d_scene_primitives_count(NULL, &nprims) == RES_BAD_ARG); + CHK(s2d_scene_primitives_count(scn, &nprims) == RES_OK); + CHK(nprims == 0); + + CHK(s2d_scene_attach_shape(scn, shape) == RES_OK); + CHK(s2d_scene_clear(scn) == RES_BAD_OP); + CHK(s2d_scene_detach_shape(scn, shape) == RES_OK); + + CHK(s2d_scene_end_session(NULL) == RES_BAD_ARG); + CHK(s2d_scene_end_session(scn) == RES_OK); + CHK(s2d_scene_end_session(scn) == RES_BAD_ARG); + CHK(s2d_scene_get_session_mask(scn, &mask) == RES_OK); + CHK(mask == 0); attrib.type = S2D_FLOAT2; attrib.usage = S2D_POSITION; @@ -120,36 +120,36 @@ main(int argc, char** argv) (shape, box_nsegs, line_segments_get_ids, box_nverts, &attrib, 1, (void*)&box_desc), RES_OK); - CHECK(s2d_scene_attach_shape(scn, shape), RES_OK); - CHECK(s2d_scene_begin_session(scn, S2D_TRACE), RES_OK); - CHECK(s2d_scene_detach_shape(scn, shape), RES_BAD_OP); - CHECK(s2d_scene_end_session(scn), RES_OK); + CHK(s2d_scene_attach_shape(scn, shape) == RES_OK); + CHK(s2d_scene_begin_session(scn, S2D_TRACE) == RES_OK); + CHK(s2d_scene_detach_shape(scn, shape) == RES_BAD_OP); + CHK(s2d_scene_end_session(scn) == RES_OK); - CHECK(s2d_scene_primitives_count(scn, &nprims), RES_BAD_OP); - CHECK(s2d_scene_begin_session(scn, S2D_GET_PRIMITIVE), RES_OK); - CHECK(s2d_scene_primitives_count(scn, &nprims), RES_OK); - CHECK(nprims, 4); + CHK(s2d_scene_primitives_count(scn, &nprims) == RES_BAD_OP); + CHK(s2d_scene_begin_session(scn, S2D_GET_PRIMITIVE) == RES_OK); + CHK(s2d_scene_primitives_count(scn, &nprims) == RES_OK); + CHK(nprims == 4); - CHECK(s2d_scene_get_primitive(NULL, 5, NULL), RES_BAD_ARG); - CHECK(s2d_scene_get_primitive(scn, 5, NULL), RES_BAD_ARG); - CHECK(s2d_scene_get_primitive(NULL, 0, NULL), RES_BAD_ARG); - CHECK(s2d_scene_get_primitive(scn, 0, NULL), RES_BAD_ARG); - CHECK(s2d_scene_get_primitive(NULL, 5, &prim), RES_BAD_ARG); - CHECK(s2d_scene_get_primitive(scn, 5, &prim), RES_BAD_ARG); - CHECK(s2d_scene_get_primitive(NULL, 0, &prim), RES_BAD_ARG); - CHECK(s2d_scene_get_primitive(scn, 0, &prim), RES_OK); + CHK(s2d_scene_get_primitive(NULL, 5, NULL) == RES_BAD_ARG); + CHK(s2d_scene_get_primitive(scn, 5, NULL) == RES_BAD_ARG); + CHK(s2d_scene_get_primitive(NULL, 0, NULL) == RES_BAD_ARG); + CHK(s2d_scene_get_primitive(scn, 0, NULL) == RES_BAD_ARG); + CHK(s2d_scene_get_primitive(NULL, 5, &prim) == RES_BAD_ARG); + CHK(s2d_scene_get_primitive(scn, 5, &prim) == RES_BAD_ARG); + CHK(s2d_scene_get_primitive(NULL, 0, &prim) == RES_BAD_ARG); + CHK(s2d_scene_get_primitive(scn, 0, &prim) == RES_OK); - CHECK(s2d_scene_end_session(scn), RES_OK); + CHK(s2d_scene_end_session(scn) == RES_OK); - CHECK(s2d_scene_get_primitive(scn, 0, &prim), RES_BAD_OP); + CHK(s2d_scene_get_primitive(scn, 0, &prim) == RES_BAD_OP); - CHECK(s2d_scene_begin_session(scn, S2D_GET_PRIMITIVE), RES_OK); + CHK(s2d_scene_begin_session(scn, S2D_GET_PRIMITIVE) == RES_OK); FOR_EACH(i, 0, nprims) { struct s2d_attrib attr; float tmp[2]; - CHECK(s2d_scene_get_primitive(scn, (unsigned)i, &prim), RES_OK); - CHECK(s2d_primitive_get_attrib(&prim, S2D_GEOMETRY_NORMAL, 0, &attr), RES_OK); + CHK(s2d_scene_get_primitive(scn, (unsigned)i, &prim) == RES_OK); + CHK(s2d_primitive_get_attrib(&prim, S2D_GEOMETRY_NORMAL, 0, &attr) == RES_OK); f2_normalize(attr.value, attr.value); switch(i) { case 0: f2_eq_eps(attr.value, f2(tmp, 0.f, 1.f), 1.e-6f); break; @@ -160,71 +160,71 @@ main(int argc, char** argv) } } - CHECK(s2d_scene_compute_contour_length(NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_compute_contour_length(scn, NULL), RES_BAD_ARG); - CHECK(s2d_scene_compute_contour_length(NULL, &length), RES_BAD_ARG); - CHECK(s2d_scene_compute_contour_length(scn, &length), RES_OK); - CHECK(eq_epsf(length, 8.f, 1.e-6f), 1); - - CHECK(s2d_scene_compute_area(NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_compute_area(scn, NULL), RES_BAD_ARG); - CHECK(s2d_scene_compute_area(NULL, &area), RES_BAD_ARG); - CHECK(s2d_scene_compute_area(scn, &area), RES_OK); - CHECK(eq_epsf(area, 4.f, 1.e-6f), 1); - - CHECK(s2d_scene_get_aabb(NULL, NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_get_aabb(scn, NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_get_aabb(NULL, lower, NULL), RES_BAD_ARG); - CHECK(s2d_scene_get_aabb(scn, lower, NULL), RES_BAD_ARG); - CHECK(s2d_scene_get_aabb(NULL, NULL, upper), RES_BAD_ARG); - CHECK(s2d_scene_get_aabb(scn, NULL, upper), RES_BAD_ARG); - CHECK(s2d_scene_get_aabb(NULL, lower, upper), RES_BAD_ARG); - CHECK(s2d_scene_get_aabb(scn, lower, upper), RES_OK); - CHECK(f2_eq_eps(lower, f2(tmp, -1.f, -1.f), 1.e-6f), 1); - CHECK(f2_eq_eps(upper, f2(tmp, 1.f, 1.f), 1.e-6f), 1); - - CHECK(s2d_scene_end_session(scn), RES_OK); - - CHECK(s2d_scene_compute_contour_length(scn, &length), RES_BAD_OP); - CHECK(s2d_scene_compute_area(scn, &area), RES_BAD_OP); - CHECK(s2d_scene_get_aabb(scn, lower, upper), RES_BAD_OP); - - CHECK(s2d_shape_flip_contour(shape), RES_OK); - - CHECK(s2d_scene_begin_session(scn, S2D_SAMPLE), RES_OK); - - CHECK(s2d_scene_compute_contour_length(scn, &length), RES_OK); - CHECK(eq_epsf(length, 8.f, 1.e-6f), 1); - - CHECK(s2d_scene_compute_area(scn, &area), RES_OK); - CHECK(eq_epsf(area, -4.f, 1.e-6f), 1); - - CHECK(s2d_scene_end_session(scn), RES_OK); - - CHECK(s2d_scene_clear(scn), RES_OK); - CHECK(s2d_scene_begin_session(scn, S2D_SAMPLE), RES_OK); - CHECK(s2d_scene_compute_contour_length(scn, &length), RES_OK); - CHECK(length, 0.f); - CHECK(s2d_scene_compute_area(scn, &area), RES_OK); - CHECK(area, 0.f); - CHECK(s2d_scene_get_aabb(scn, lower, upper), RES_OK); - CHECK(lower[0] > upper[0], 1); - CHECK(lower[1] > upper[1], 1); - CHECK(s2d_scene_end_session(scn), RES_OK); - - CHECK(s2d_scene_get_device(NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_get_device(scn, NULL), RES_BAD_ARG); - CHECK(s2d_scene_get_device(NULL, &dev2), RES_BAD_ARG); - CHECK(s2d_scene_get_device(scn, &dev2), RES_OK); - CHECK(dev2, dev); - - CHECK(s2d_shape_ref_put(shape), RES_OK); - CHECK(s2d_scene_ref_put(scn), RES_OK); - CHECK(s2d_device_ref_put(dev), RES_OK); + CHK(s2d_scene_compute_contour_length(NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_compute_contour_length(scn, NULL) == RES_BAD_ARG); + CHK(s2d_scene_compute_contour_length(NULL, &length) == RES_BAD_ARG); + CHK(s2d_scene_compute_contour_length(scn, &length) == RES_OK); + CHK(eq_epsf(length, 8.f, 1.e-6f) == 1); + + CHK(s2d_scene_compute_area(NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_compute_area(scn, NULL) == RES_BAD_ARG); + CHK(s2d_scene_compute_area(NULL, &area) == RES_BAD_ARG); + CHK(s2d_scene_compute_area(scn, &area) == RES_OK); + CHK(eq_epsf(area, 4.f, 1.e-6f) == 1); + + CHK(s2d_scene_get_aabb(NULL, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_get_aabb(scn, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_get_aabb(NULL, lower, NULL) == RES_BAD_ARG); + CHK(s2d_scene_get_aabb(scn, lower, NULL) == RES_BAD_ARG); + CHK(s2d_scene_get_aabb(NULL, NULL, upper) == RES_BAD_ARG); + CHK(s2d_scene_get_aabb(scn, NULL, upper) == RES_BAD_ARG); + CHK(s2d_scene_get_aabb(NULL, lower, upper) == RES_BAD_ARG); + CHK(s2d_scene_get_aabb(scn, lower, upper) == RES_OK); + CHK(f2_eq_eps(lower, f2(tmp, -1.f, -1.f), 1.e-6f) == 1); + CHK(f2_eq_eps(upper, f2(tmp, 1.f, 1.f), 1.e-6f) == 1); + + CHK(s2d_scene_end_session(scn) == RES_OK); + + CHK(s2d_scene_compute_contour_length(scn, &length) == RES_BAD_OP); + CHK(s2d_scene_compute_area(scn, &area) == RES_BAD_OP); + CHK(s2d_scene_get_aabb(scn, lower, upper) == RES_BAD_OP); + + CHK(s2d_shape_flip_contour(shape) == RES_OK); + + CHK(s2d_scene_begin_session(scn, S2D_SAMPLE) == RES_OK); + + CHK(s2d_scene_compute_contour_length(scn, &length) == RES_OK); + CHK(eq_epsf(length, 8.f, 1.e-6f) == 1); + + CHK(s2d_scene_compute_area(scn, &area) == RES_OK); + CHK(eq_epsf(area, -4.f, 1.e-6f) == 1); + + CHK(s2d_scene_end_session(scn) == RES_OK); + + CHK(s2d_scene_clear(scn) == RES_OK); + CHK(s2d_scene_begin_session(scn, S2D_SAMPLE) == RES_OK); + CHK(s2d_scene_compute_contour_length(scn, &length) == RES_OK); + CHK(length == 0.f); + CHK(s2d_scene_compute_area(scn, &area) == RES_OK); + CHK(area == 0.f); + CHK(s2d_scene_get_aabb(scn, lower, upper) == RES_OK); + CHK(lower[0] > upper[0] == 1); + CHK(lower[1] > upper[1] == 1); + CHK(s2d_scene_end_session(scn) == RES_OK); + + CHK(s2d_scene_get_device(NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_get_device(scn, NULL) == RES_BAD_ARG); + CHK(s2d_scene_get_device(NULL, &dev2) == RES_BAD_ARG); + CHK(s2d_scene_get_device(scn, &dev2) == RES_OK); + CHK(dev2 == dev); + + CHK(s2d_shape_ref_put(shape) == RES_OK); + CHK(s2d_scene_ref_put(scn) == RES_OK); + CHK(s2d_device_ref_put(dev) == RES_OK); check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator); - CHECK(mem_allocated_size(), 0); + CHK(mem_allocated_size() == 0); return 0; } diff --git a/src/test_s2d_session_advanced.c b/src/test_s2d_session_advanced.c @@ -48,11 +48,11 @@ static INLINE float* ran_semi_disk_cos(const float up[2], float samp[2]) { float tmp[2], v[2]; - CHECK(f2_is_normalized(samp), 1); + CHK(f2_is_normalized(samp) == 1); ran_semi_disk_cos_local(tmp); v[0] = -up[1] * tmp[0] + up[0]*tmp[1]; v[1] = up[0] * tmp[0] + up[1]*tmp[1];; - CHECK(f2_is_normalized(v), 1); + CHK(f2_is_normalized(v) == 1); return f2_set(samp, v); } @@ -65,10 +65,10 @@ discard_self_hit void* filter_data) { struct s2d_primitive* prim_from = ray_data; - NCHECK(hit, NULL); - NCHECK(org, NULL); - NCHECK(dir, NULL); - CHECK((intptr_t)filter_data, (intptr_t)0xDECAFBAD); + CHK(hit != NULL); + CHK(org != NULL); + CHK(dir != NULL); + CHK((intptr_t)filter_data == (intptr_t)0xDECAFBAD); if(!ray_data) return 0; return S2D_PRIMITIVE_EQ(prim_from, &hit->prim); } @@ -88,14 +88,14 @@ create_circle_shape const double step = 2.0*PI/(double)nsteps; unsigned i; - CHECK(s2d_shape_create_line_segments(dev, &shape), RES_OK); + CHK(s2d_shape_create_line_segments(dev, &shape) == RES_OK); CHECK(s2d_line_segments_set_hit_filter_function (shape, discard_self_hit, (void*)0xDECAFBAD), RES_OK); - CHECK(nsteps > 4, 1); - NCHECK(center, NULL); - NCHECK(sa_add(positions, nsteps*2/*#coords per vertex*/), NULL); - NCHECK(sa_add(indices, nsteps*2/*#ids per segment*/), NULL); + CHK(nsteps > 4 == 1); + CHK(center != NULL); + CHK(sa_add(positions, nsteps*2/*#coords per vertex*/) != NULL); + CHK(sa_add(indices, nsteps*2/*#ids per segment*/) != NULL); FOR_EACH(i, 0, nsteps) { const double theta = i*step; @@ -121,7 +121,7 @@ create_circle_shape (shape, nsteps, line_segments_get_ids, nsteps, &vdata, 1, (void*)&desc), RES_OK); - CHECK(s2d_shape_flip_contour(shape), RES_OK); + CHK(s2d_shape_flip_contour(shape) == RES_OK); sa_release(positions); sa_release(indices); @@ -151,35 +151,35 @@ main(int argc, char** argv) mem_init_proxy_allocator(&allocator, &mem_default_allocator); - CHECK(s2d_device_create(NULL, &allocator, 0, &dev), RES_OK); - CHECK(s2d_scene_create(dev, &scn), RES_OK); + CHK(s2d_device_create(NULL, &allocator, 0, &dev) == RES_OK); + CHK(s2d_scene_create(dev, &scn) == RES_OK); - NCHECK(sa_add(shape_prims[0], shape_nsteps[0]), NULL); - NCHECK(sa_add(shape_prims[1], shape_nsteps[1]), NULL); - NCHECK(sa_add(shape_prims[2], shape_nsteps[2]), NULL); + CHK(sa_add(shape_prims[0], shape_nsteps[0]) != NULL); + CHK(sa_add(shape_prims[1], shape_nsteps[1]) != NULL); + CHK(sa_add(shape_prims[2], shape_nsteps[2]) != NULL); NCHECK(sa_add (scene_prims, shape_nsteps[0]+shape_nsteps[1]+shape_nsteps[2]), NULL); shape = create_circle_shape(dev, 1.f, f2(tmp, 0.f, 0.f), shape_nsteps[0]); - CHECK(s2d_shape_get_id(shape, &shape_ids[0]), RES_OK); - NCHECK(shape_ids[0], S2D_INVALID_ID); - CHECK(s2d_scene_attach_shape(scn, shape), RES_OK); - CHECK(s2d_shape_ref_put(shape), RES_OK); + CHK(s2d_shape_get_id(shape, &shape_ids[0]) == RES_OK); + CHK(shape_ids[0] != S2D_INVALID_ID); + CHK(s2d_scene_attach_shape(scn, shape) == RES_OK); + CHK(s2d_shape_ref_put(shape) == RES_OK); shape = create_circle_shape(dev, 0.5f, f2(tmp, 2.f, 0.5f), shape_nsteps[1]); - CHECK(s2d_shape_get_id(shape, &shape_ids[1]), RES_OK); - NCHECK(shape_ids[1], S2D_INVALID_ID); - NCHECK(shape_ids[1], shape_ids[0]); - CHECK(s2d_scene_attach_shape(scn, shape), RES_OK); - CHECK(s2d_shape_ref_put(shape), RES_OK); + CHK(s2d_shape_get_id(shape, &shape_ids[1]) == RES_OK); + CHK(shape_ids[1] != S2D_INVALID_ID); + CHK(shape_ids[1] != shape_ids[0]); + CHK(s2d_scene_attach_shape(scn, shape) == RES_OK); + CHK(s2d_shape_ref_put(shape) == RES_OK); shape = create_circle_shape(dev, 0.25f, f2(tmp, 1.5f, -0.25f), shape_nsteps[2]); - CHECK(s2d_shape_get_id(shape, &shape_ids[2]), RES_OK); - NCHECK(shape_ids[2], S2D_INVALID_ID); - NCHECK(shape_ids[2], shape_ids[0]); - NCHECK(shape_ids[2], shape_ids[1]); - CHECK(s2d_scene_attach_shape(scn, shape), RES_OK); - CHECK(s2d_shape_ref_put(shape), RES_OK); + CHK(s2d_shape_get_id(shape, &shape_ids[2]) == RES_OK); + CHK(shape_ids[2] != S2D_INVALID_ID); + CHK(shape_ids[2] != shape_ids[0]); + CHK(shape_ids[2] != shape_ids[1]); + CHK(s2d_scene_attach_shape(scn, shape) == RES_OK); + CHK(s2d_shape_ref_put(shape) == RES_OK); CHECK(s2d_scene_begin_session (scn, S2D_SAMPLE|S2D_GET_PRIMITIVE|S2D_TRACE), RES_OK); @@ -192,55 +192,55 @@ main(int argc, char** argv) FOR_EACH(i, 0, 1024) { struct s2d_attrib attr; float s; - CHECK(s2d_scene_sample(scn, rand_canonic(), rand_canonic(), &prim, &s), RES_OK); - CHECK(s2d_primitive_get_attrib(&prim, S2D_POSITION, s, &attr), RES_OK); - CHECK(attr.type, S2D_FLOAT2); + CHK(s2d_scene_sample(scn, rand_canonic(), rand_canonic(), &prim, &s) == RES_OK); + CHK(s2d_primitive_get_attrib(&prim, S2D_POSITION, s, &attr) == RES_OK); + CHK(attr.type == S2D_FLOAT2); FOR_EACH(ishape, 0, 3) if(prim.geom_id == shape_ids[ishape]) break; - NCHECK(ishape, 3); + CHK(ishape != 3); /* Mark the shape primitive as sampled */ - CHECK(prim.prim_id < shape_nsteps[ishape], 1); + CHK(prim.prim_id < shape_nsteps[ishape] == 1); shape_prims[ishape][prim.prim_id] = 1; /* Mark the scene primitive as sampled */ - CHECK(prim.scene_prim_id < sa_size(scene_prims), 1); + CHK(prim.scene_prim_id < sa_size(scene_prims) == 1); scene_prims[prim.scene_prim_id] = 1; } /* Check that all primitives were sampled */ - FOR_EACH(i, 0, sa_size(shape_prims[0])) CHECK(shape_prims[0][i], 1); - FOR_EACH(i, 0, sa_size(shape_prims[1])) CHECK(shape_prims[1][i], 1); - FOR_EACH(i, 0, sa_size(shape_prims[2])) CHECK(shape_prims[2][i], 1); - FOR_EACH(i, 0, sa_size(scene_prims)) CHECK(scene_prims[i], 1); + FOR_EACH(i, 0, sa_size(shape_prims[0])) CHK(shape_prims[0][i] == 1); + FOR_EACH(i, 0, sa_size(shape_prims[1])) CHK(shape_prims[1][i] == 1); + FOR_EACH(i, 0, sa_size(shape_prims[2])) CHK(shape_prims[2][i] == 1); + FOR_EACH(i, 0, sa_size(scene_prims)) CHK(scene_prims[i] == 1); /* Check iteration */ memset(shape_prims[0], 0, sa_size(shape_prims[0])*sizeof(shape_prims[0][0])); memset(shape_prims[1], 0, sa_size(shape_prims[1])*sizeof(shape_prims[1][0])); memset(shape_prims[2], 0, sa_size(shape_prims[2])*sizeof(shape_prims[2][0])); memset(scene_prims, 0, sa_size(scene_prims)*sizeof(scene_prims[0])); - CHECK(s2d_scene_primitives_count(scn, &nprims), RES_OK); - CHECK(sa_size(scene_prims), nprims); + CHK(s2d_scene_primitives_count(scn, &nprims) == RES_OK); + CHK(sa_size(scene_prims) == nprims); FOR_EACH(i, 0, nprims) { - CHECK(s2d_scene_get_primitive(scn, (unsigned)i, &prim), RES_OK); + CHK(s2d_scene_get_primitive(scn, (unsigned)i, &prim) == RES_OK); FOR_EACH(ishape, 0, 3) if(prim.geom_id == shape_ids[ishape]) break; - NCHECK(ishape, 3); + CHK(ishape != 3); /* Mark the shape primitive as visited */ - CHECK(prim.prim_id < shape_nsteps[ishape], 1); + CHK(prim.prim_id < shape_nsteps[ishape] == 1); shape_prims[ishape][prim.prim_id] = 1; /* Mark the scene primitive as visited */ - CHECK(prim.scene_prim_id < sa_size(scene_prims), 1); + CHK(prim.scene_prim_id < sa_size(scene_prims) == 1); scene_prims[prim.scene_prim_id] = 1; } /* Check that all primitives were visited */ - FOR_EACH(i, 0, sa_size(shape_prims[0])) CHECK(shape_prims[0][i], 1); - FOR_EACH(i, 0, sa_size(shape_prims[1])) CHECK(shape_prims[1][i], 1); - FOR_EACH(i, 0, sa_size(shape_prims[2])) CHECK(shape_prims[2][i], 1); - FOR_EACH(i, 0, sa_size(scene_prims)) CHECK(scene_prims[i], 1); + FOR_EACH(i, 0, sa_size(shape_prims[0])) CHK(shape_prims[0][i] == 1); + FOR_EACH(i, 0, sa_size(shape_prims[1])) CHK(shape_prims[1][i] == 1); + FOR_EACH(i, 0, sa_size(shape_prims[2])) CHK(shape_prims[2][i] == 1); + FOR_EACH(i, 0, sa_size(scene_prims)) CHK(scene_prims[i] == 1); /* Check the ray tracing by numerically compute PI*S/P aka 4V/S in 2D */ sum = sum_sqr = 0; @@ -251,39 +251,39 @@ main(int argc, char** argv) float P[2], N[2]; float s; - CHECK(s2d_scene_sample(scn, rand_canonic(), rand_canonic(), &prim, &s), RES_OK); + CHK(s2d_scene_sample(scn, rand_canonic(), rand_canonic(), &prim, &s) == RES_OK); - CHECK(s2d_primitive_get_attrib(&prim, S2D_POSITION, s, &attr), RES_OK); - CHECK(attr.type, S2D_FLOAT2); + CHK(s2d_primitive_get_attrib(&prim, S2D_POSITION, s, &attr) == RES_OK); + CHK(attr.type == S2D_FLOAT2); f2_set(P, attr.value); - CHECK(s2d_primitive_get_attrib(&prim, S2D_GEOMETRY_NORMAL, s, &attr), RES_OK); - CHECK(attr.type, S2D_FLOAT2); - NCHECK(f2_normalize(N, attr.value), 0.f); + CHK(s2d_primitive_get_attrib(&prim, S2D_GEOMETRY_NORMAL, s, &attr) == RES_OK); + CHK(attr.type == S2D_FLOAT2); + CHK(f2_normalize(N, attr.value) != 0.f); f2_normalize(tmp, f2(tmp, 1, 1)); ran_semi_disk_cos(N, tmp); - CHECK(s2d_scene_trace_ray(scn, P, tmp, range, &prim, &hit), RES_OK); - CHECK(S2D_HIT_NONE(&hit), 0); + CHK(s2d_scene_trace_ray(scn, P, tmp, range, &prim, &hit) == RES_OK); + CHK(S2D_HIT_NONE(&hit) == 0); sum += hit.distance; sum_sqr += hit.distance*hit.distance; } - CHECK(s2d_scene_compute_contour_length(scn, &length), RES_OK); - CHECK(s2d_scene_compute_area(scn, &area), RES_OK); + CHK(s2d_scene_compute_contour_length(scn, &length) == RES_OK); + CHK(s2d_scene_compute_area(scn, &area) == RES_OK); E = sum / (float)NSAMPS; V = sum_sqr / (float)NSAMPS - E*E; SE = (float)sqrt(V/(float)NSAMPS); printf("PI*S / P = %g ~ %g +/- %g\n",(float)PI*area / length, E, SE); - CHECK(eq_epsf((float)PI*area / length, E, SE), 1); + CHK(eq_epsf((float)PI*area / length, E, SE) == 1); - CHECK(s2d_scene_end_session(scn), RES_OK); + CHK(s2d_scene_end_session(scn) == RES_OK); - CHECK(s2d_scene_ref_put(scn), RES_OK); - CHECK(s2d_device_ref_put(dev), RES_OK); + CHK(s2d_scene_ref_put(scn) == RES_OK); + CHK(s2d_device_ref_put(dev) == RES_OK); sa_release(scene_prims); sa_release(shape_prims[0]); @@ -292,7 +292,7 @@ main(int argc, char** argv) check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator); - CHECK(mem_allocated_size(), 0); + CHK(mem_allocated_size() == 0); return 0; } diff --git a/src/test_s2d_shape.c b/src/test_s2d_shape.c @@ -63,32 +63,32 @@ main(int argc, char** argv) mem_init_proxy_allocator(&allocator, &mem_default_allocator); - CHECK(s2d_device_create(NULL, &allocator, 0, &dev), RES_OK); + CHK(s2d_device_create(NULL, &allocator, 0, &dev) == RES_OK); - CHECK(s2d_shape_create_line_segments(NULL, NULL), RES_BAD_ARG); - CHECK(s2d_shape_create_line_segments(dev, NULL), RES_BAD_ARG); - CHECK(s2d_shape_create_line_segments(NULL, &shape), RES_BAD_ARG); - CHECK(s2d_shape_create_line_segments(dev, &shape), RES_OK); + CHK(s2d_shape_create_line_segments(NULL, NULL) == RES_BAD_ARG); + CHK(s2d_shape_create_line_segments(dev, NULL) == RES_BAD_ARG); + CHK(s2d_shape_create_line_segments(NULL, &shape) == RES_BAD_ARG); + CHK(s2d_shape_create_line_segments(dev, &shape) == RES_OK); - CHECK(s2d_shape_ref_get(NULL), RES_BAD_ARG); - CHECK(s2d_shape_ref_get(shape), RES_OK); - CHECK(s2d_shape_ref_put(NULL), RES_BAD_ARG); - CHECK(s2d_shape_ref_put(shape), RES_OK); - CHECK(s2d_shape_ref_put(shape), RES_OK); + CHK(s2d_shape_ref_get(NULL) == RES_BAD_ARG); + CHK(s2d_shape_ref_get(shape) == RES_OK); + CHK(s2d_shape_ref_put(NULL) == RES_BAD_ARG); + CHK(s2d_shape_ref_put(shape) == RES_OK); + CHK(s2d_shape_ref_put(shape) == RES_OK); - CHECK(s2d_shape_create_line_segments(dev, &shape), RES_OK); + CHK(s2d_shape_create_line_segments(dev, &shape) == RES_OK); - CHECK(s2d_shape_get_id(NULL, NULL), RES_BAD_ARG); - CHECK(s2d_shape_get_id(shape, NULL), RES_BAD_ARG); - CHECK(s2d_shape_get_id(NULL, &id), RES_BAD_ARG); - CHECK(s2d_shape_get_id(shape, &id), RES_OK); - NCHECK(id, S2D_INVALID_ID); + CHK(s2d_shape_get_id(NULL, NULL) == RES_BAD_ARG); + CHK(s2d_shape_get_id(shape, NULL) == RES_BAD_ARG); + CHK(s2d_shape_get_id(NULL, &id) == RES_BAD_ARG); + CHK(s2d_shape_get_id(shape, &id) == RES_OK); + CHK(id != S2D_INVALID_ID); - CHECK(s2d_shape_is_attached(NULL, NULL), RES_BAD_ARG); - CHECK(s2d_shape_is_attached(shape, NULL), RES_BAD_ARG); - CHECK(s2d_shape_is_attached(NULL, &c), RES_BAD_ARG); - CHECK(s2d_shape_is_attached(shape, &c), RES_OK); - CHECK(c, 0); + CHK(s2d_shape_is_attached(NULL, NULL) == RES_BAD_ARG); + CHK(s2d_shape_is_attached(shape, NULL) == RES_BAD_ARG); + CHK(s2d_shape_is_attached(NULL, &c) == RES_BAD_ARG); + CHK(s2d_shape_is_attached(shape, &c) == RES_OK); + CHK(c == 0); vdata[0].type = S2D_FLOAT2; vdata[0].usage = S2D_POSITION; @@ -96,189 +96,189 @@ main(int argc, char** argv) #define SETUP s2d_line_segments_setup_indexed_vertices #define box_get_ids line_segments_get_ids - CHECK(SETUP(NULL, 0, NULL, 0, NULL, 0, data), RES_BAD_ARG); - CHECK(SETUP(shape, 0, NULL, 0, NULL, 0, data), RES_BAD_ARG); - CHECK(SETUP(NULL, nsegs, NULL, 0, NULL, 0, data), RES_BAD_ARG); - CHECK(SETUP(shape, nsegs, NULL, 0, NULL, 0, data), RES_BAD_ARG); - CHECK(SETUP(NULL, 0, box_get_ids, 0, NULL, 0, data), RES_BAD_ARG); - CHECK(SETUP(shape, 0, box_get_ids, 0, NULL, 0, data), RES_BAD_ARG); - CHECK(SETUP(NULL, nsegs, box_get_ids, 0, NULL, 0, data), RES_BAD_ARG); - CHECK(SETUP(shape, nsegs, box_get_ids, 0, NULL, 0, data), RES_BAD_ARG); - CHECK(SETUP(NULL, 0, NULL, nverts, NULL, 0, data), RES_BAD_ARG); - CHECK(SETUP(shape, 0, NULL, nverts, NULL, 0, data), RES_BAD_ARG); - CHECK(SETUP(NULL, nsegs, NULL, nverts, NULL, 0, data), RES_BAD_ARG); - CHECK(SETUP(shape, nsegs, NULL, nverts, NULL, 0, data), RES_BAD_ARG); - CHECK(SETUP(NULL, 0, box_get_ids, nverts, NULL, 0, data), RES_BAD_ARG); - CHECK(SETUP(shape, 0, box_get_ids, nverts, NULL, 0, data), RES_BAD_ARG); - CHECK(SETUP(NULL, nsegs, box_get_ids, nverts, NULL, 0, data), RES_BAD_ARG); - CHECK(SETUP(shape, nsegs, box_get_ids, nverts, NULL, 0, data), RES_BAD_ARG); - CHECK(SETUP(NULL, 0, NULL, 0, vdata, 0, data), RES_BAD_ARG); - CHECK(SETUP(shape, 0, NULL, 0, vdata, 0, data), RES_BAD_ARG); - CHECK(SETUP(NULL, nsegs, NULL, 0, vdata, 0, data), RES_BAD_ARG); - CHECK(SETUP(shape, nsegs, NULL, 0, vdata, 0, data), RES_BAD_ARG); - CHECK(SETUP(NULL, 0, box_get_ids, 0, vdata, 0, data), RES_BAD_ARG); - CHECK(SETUP(shape, 0, box_get_ids, 0, vdata, 0, data), RES_BAD_ARG); - CHECK(SETUP(NULL, nsegs, box_get_ids, 0, vdata, 0, data), RES_BAD_ARG); - CHECK(SETUP(shape, nsegs, box_get_ids, 0, vdata, 0, data), RES_BAD_ARG); - CHECK(SETUP(NULL, 0, NULL, nverts, vdata, 0, data), RES_BAD_ARG); - CHECK(SETUP(shape, 0, NULL, nverts, vdata, 0, data), RES_BAD_ARG); - CHECK(SETUP(NULL, nsegs, NULL, nverts, vdata, 0, data), RES_BAD_ARG); - CHECK(SETUP(shape, nsegs, NULL, nverts, vdata, 0, data), RES_BAD_ARG); - CHECK(SETUP(NULL, 0, box_get_ids, nverts, vdata, 0, data), RES_BAD_ARG); - CHECK(SETUP(shape, 0, box_get_ids, nverts, vdata, 0, data), RES_BAD_ARG); - CHECK(SETUP(NULL, nsegs, box_get_ids, nverts, vdata, 0, data), RES_BAD_ARG); - CHECK(SETUP(shape, nsegs, box_get_ids, nverts, vdata, 0, data), RES_BAD_ARG); - CHECK(SETUP(NULL, 0, NULL, 0, NULL, 1, data), RES_BAD_ARG); - CHECK(SETUP(shape, 0, NULL, 0, NULL, 1, data), RES_BAD_ARG); - CHECK(SETUP(NULL, nsegs, NULL, 0, NULL, 1, data), RES_BAD_ARG); - CHECK(SETUP(shape, nsegs, NULL, 0, NULL, 1, data), RES_BAD_ARG); - CHECK(SETUP(NULL, 0, box_get_ids, 0, NULL, 1, data), RES_BAD_ARG); - CHECK(SETUP(shape, 0, box_get_ids, 0, NULL, 1, data), RES_BAD_ARG); - CHECK(SETUP(NULL, nsegs, box_get_ids, 0, NULL, 1, data), RES_BAD_ARG); - CHECK(SETUP(shape, nsegs, box_get_ids, 0, NULL, 1, data), RES_BAD_ARG); - CHECK(SETUP(NULL, 0, NULL, nverts, NULL, 1, data), RES_BAD_ARG); - CHECK(SETUP(shape, 0, NULL, nverts, NULL, 1, data), RES_BAD_ARG); - CHECK(SETUP(NULL, nsegs, NULL, nverts, NULL, 1, data), RES_BAD_ARG); - CHECK(SETUP(shape, nsegs, NULL, nverts, NULL, 1, data), RES_BAD_ARG); - CHECK(SETUP(NULL, 0, box_get_ids, nverts, NULL, 1, data), RES_BAD_ARG); - CHECK(SETUP(shape, 0, box_get_ids, nverts, NULL, 1, data), RES_BAD_ARG); - CHECK(SETUP(NULL, nsegs, box_get_ids, nverts, NULL, 1, data), RES_BAD_ARG); - CHECK(SETUP(shape, nsegs, box_get_ids, nverts, NULL, 1, data), RES_BAD_ARG); - CHECK(SETUP(NULL, 0, NULL, 0, vdata, 1, data), RES_BAD_ARG); - CHECK(SETUP(shape, 0, NULL, 0, vdata, 1, data), RES_BAD_ARG); - CHECK(SETUP(NULL, nsegs, NULL, 0, vdata, 1, data), RES_BAD_ARG); - CHECK(SETUP(shape, nsegs, NULL, 0, vdata, 1, data), RES_BAD_ARG); - CHECK(SETUP(NULL, 0, box_get_ids, 0, vdata, 1, data), RES_BAD_ARG); - CHECK(SETUP(shape, 0, box_get_ids, 0, vdata, 1, data), RES_BAD_ARG); - CHECK(SETUP(NULL, nsegs, box_get_ids, 0, vdata, 1, data), RES_BAD_ARG); - CHECK(SETUP(shape, nsegs, box_get_ids, 0, vdata, 1, data), RES_BAD_ARG); - CHECK(SETUP(NULL, 0, NULL, nverts, vdata, 1, data), RES_BAD_ARG); - CHECK(SETUP(shape, 0, NULL, nverts, vdata, 1, data), RES_BAD_ARG); - CHECK(SETUP(NULL, nsegs, NULL, nverts, vdata, 1, data), RES_BAD_ARG); - CHECK(SETUP(shape, nsegs, NULL, nverts, vdata, 1, data), RES_BAD_ARG); - CHECK(SETUP(NULL, 0, box_get_ids, nverts, vdata, 1, data), RES_BAD_ARG); - CHECK(SETUP(shape, 0, box_get_ids, nverts, vdata, 1, data), RES_BAD_ARG); - CHECK(SETUP(NULL, nsegs, box_get_ids, nverts, vdata, 1, data), RES_BAD_ARG); - CHECK(SETUP(shape, nsegs, box_get_ids, nverts, vdata, 1, data), RES_OK); + CHK(SETUP(NULL, 0, NULL, 0, NULL, 0, data) == RES_BAD_ARG); + CHK(SETUP(shape, 0, NULL, 0, NULL, 0, data) == RES_BAD_ARG); + CHK(SETUP(NULL, nsegs, NULL, 0, NULL, 0, data) == RES_BAD_ARG); + CHK(SETUP(shape, nsegs, NULL, 0, NULL, 0, data) == RES_BAD_ARG); + CHK(SETUP(NULL, 0, box_get_ids, 0, NULL, 0, data) == RES_BAD_ARG); + CHK(SETUP(shape, 0, box_get_ids, 0, NULL, 0, data) == RES_BAD_ARG); + CHK(SETUP(NULL, nsegs, box_get_ids, 0, NULL, 0, data) == RES_BAD_ARG); + CHK(SETUP(shape, nsegs, box_get_ids, 0, NULL, 0, data) == RES_BAD_ARG); + CHK(SETUP(NULL, 0, NULL, nverts, NULL, 0, data) == RES_BAD_ARG); + CHK(SETUP(shape, 0, NULL, nverts, NULL, 0, data) == RES_BAD_ARG); + CHK(SETUP(NULL, nsegs, NULL, nverts, NULL, 0, data) == RES_BAD_ARG); + CHK(SETUP(shape, nsegs, NULL, nverts, NULL, 0, data) == RES_BAD_ARG); + CHK(SETUP(NULL, 0, box_get_ids, nverts, NULL, 0, data) == RES_BAD_ARG); + CHK(SETUP(shape, 0, box_get_ids, nverts, NULL, 0, data) == RES_BAD_ARG); + CHK(SETUP(NULL, nsegs, box_get_ids, nverts, NULL, 0, data) == RES_BAD_ARG); + CHK(SETUP(shape, nsegs, box_get_ids, nverts, NULL, 0, data) == RES_BAD_ARG); + CHK(SETUP(NULL, 0, NULL, 0, vdata, 0, data) == RES_BAD_ARG); + CHK(SETUP(shape, 0, NULL, 0, vdata, 0, data) == RES_BAD_ARG); + CHK(SETUP(NULL, nsegs, NULL, 0, vdata, 0, data) == RES_BAD_ARG); + CHK(SETUP(shape, nsegs, NULL, 0, vdata, 0, data) == RES_BAD_ARG); + CHK(SETUP(NULL, 0, box_get_ids, 0, vdata, 0, data) == RES_BAD_ARG); + CHK(SETUP(shape, 0, box_get_ids, 0, vdata, 0, data) == RES_BAD_ARG); + CHK(SETUP(NULL, nsegs, box_get_ids, 0, vdata, 0, data) == RES_BAD_ARG); + CHK(SETUP(shape, nsegs, box_get_ids, 0, vdata, 0, data) == RES_BAD_ARG); + CHK(SETUP(NULL, 0, NULL, nverts, vdata, 0, data) == RES_BAD_ARG); + CHK(SETUP(shape, 0, NULL, nverts, vdata, 0, data) == RES_BAD_ARG); + CHK(SETUP(NULL, nsegs, NULL, nverts, vdata, 0, data) == RES_BAD_ARG); + CHK(SETUP(shape, nsegs, NULL, nverts, vdata, 0, data) == RES_BAD_ARG); + CHK(SETUP(NULL, 0, box_get_ids, nverts, vdata, 0, data) == RES_BAD_ARG); + CHK(SETUP(shape, 0, box_get_ids, nverts, vdata, 0, data) == RES_BAD_ARG); + CHK(SETUP(NULL, nsegs, box_get_ids, nverts, vdata, 0, data) == RES_BAD_ARG); + CHK(SETUP(shape, nsegs, box_get_ids, nverts, vdata, 0, data) == RES_BAD_ARG); + CHK(SETUP(NULL, 0, NULL, 0, NULL, 1, data) == RES_BAD_ARG); + CHK(SETUP(shape, 0, NULL, 0, NULL, 1, data) == RES_BAD_ARG); + CHK(SETUP(NULL, nsegs, NULL, 0, NULL, 1, data) == RES_BAD_ARG); + CHK(SETUP(shape, nsegs, NULL, 0, NULL, 1, data) == RES_BAD_ARG); + CHK(SETUP(NULL, 0, box_get_ids, 0, NULL, 1, data) == RES_BAD_ARG); + CHK(SETUP(shape, 0, box_get_ids, 0, NULL, 1, data) == RES_BAD_ARG); + CHK(SETUP(NULL, nsegs, box_get_ids, 0, NULL, 1, data) == RES_BAD_ARG); + CHK(SETUP(shape, nsegs, box_get_ids, 0, NULL, 1, data) == RES_BAD_ARG); + CHK(SETUP(NULL, 0, NULL, nverts, NULL, 1, data) == RES_BAD_ARG); + CHK(SETUP(shape, 0, NULL, nverts, NULL, 1, data) == RES_BAD_ARG); + CHK(SETUP(NULL, nsegs, NULL, nverts, NULL, 1, data) == RES_BAD_ARG); + CHK(SETUP(shape, nsegs, NULL, nverts, NULL, 1, data) == RES_BAD_ARG); + CHK(SETUP(NULL, 0, box_get_ids, nverts, NULL, 1, data) == RES_BAD_ARG); + CHK(SETUP(shape, 0, box_get_ids, nverts, NULL, 1, data) == RES_BAD_ARG); + CHK(SETUP(NULL, nsegs, box_get_ids, nverts, NULL, 1, data) == RES_BAD_ARG); + CHK(SETUP(shape, nsegs, box_get_ids, nverts, NULL, 1, data) == RES_BAD_ARG); + CHK(SETUP(NULL, 0, NULL, 0, vdata, 1, data) == RES_BAD_ARG); + CHK(SETUP(shape, 0, NULL, 0, vdata, 1, data) == RES_BAD_ARG); + CHK(SETUP(NULL, nsegs, NULL, 0, vdata, 1, data) == RES_BAD_ARG); + CHK(SETUP(shape, nsegs, NULL, 0, vdata, 1, data) == RES_BAD_ARG); + CHK(SETUP(NULL, 0, box_get_ids, 0, vdata, 1, data) == RES_BAD_ARG); + CHK(SETUP(shape, 0, box_get_ids, 0, vdata, 1, data) == RES_BAD_ARG); + CHK(SETUP(NULL, nsegs, box_get_ids, 0, vdata, 1, data) == RES_BAD_ARG); + CHK(SETUP(shape, nsegs, box_get_ids, 0, vdata, 1, data) == RES_BAD_ARG); + CHK(SETUP(NULL, 0, NULL, nverts, vdata, 1, data) == RES_BAD_ARG); + CHK(SETUP(shape, 0, NULL, nverts, vdata, 1, data) == RES_BAD_ARG); + CHK(SETUP(NULL, nsegs, NULL, nverts, vdata, 1, data) == RES_BAD_ARG); + CHK(SETUP(shape, nsegs, NULL, nverts, vdata, 1, data) == RES_BAD_ARG); + CHK(SETUP(NULL, 0, box_get_ids, nverts, vdata, 1, data) == RES_BAD_ARG); + CHK(SETUP(shape, 0, box_get_ids, nverts, vdata, 1, data) == RES_BAD_ARG); + CHK(SETUP(NULL, nsegs, box_get_ids, nverts, vdata, 1, data) == RES_BAD_ARG); + CHK(SETUP(shape, nsegs, box_get_ids, nverts, vdata, 1, data) == RES_OK); vdata[0] = S2D_VERTEX_DATA_NULL; - CHECK(SETUP(shape, nsegs, box_get_ids, nverts, vdata, 1, data), RES_BAD_ARG); + CHK(SETUP(shape, nsegs, box_get_ids, nverts, vdata, 1, data) == RES_BAD_ARG); vdata[0].type = S2D_FLOAT2; vdata[0].usage = S2D_POSITION; vdata[0].get = S2D_KEEP; - CHECK(SETUP(shape, nsegs, box_get_ids, nverts, vdata, 1, data), RES_OK); + CHK(SETUP(shape, nsegs, box_get_ids, nverts, vdata, 1, data) == RES_OK); vdata[0].get = line_segments_get_position; - CHECK(SETUP(shape, nsegs, box_get_ids, nverts, vdata, 1, data), RES_OK); + CHK(SETUP(shape, nsegs, box_get_ids, nverts, vdata, 1, data) == RES_OK); #undef box_get_ids #undef SETUP - CHECK(s2d_line_segments_get_vertices_count(NULL, NULL), RES_BAD_ARG); - CHECK(s2d_line_segments_get_vertices_count(shape, NULL), RES_BAD_ARG); - CHECK(s2d_line_segments_get_vertices_count(NULL, &n), RES_BAD_ARG); - CHECK(s2d_line_segments_get_vertices_count(shape, &n), RES_OK); - CHECK(n, nverts); + CHK(s2d_line_segments_get_vertices_count(NULL, NULL) == RES_BAD_ARG); + CHK(s2d_line_segments_get_vertices_count(shape, NULL) == RES_BAD_ARG); + CHK(s2d_line_segments_get_vertices_count(NULL, &n) == RES_BAD_ARG); + CHK(s2d_line_segments_get_vertices_count(shape, &n) == RES_OK); + CHK(n == nverts); - CHECK(s2d_line_segments_get_segments_count(NULL, NULL), RES_BAD_ARG); - CHECK(s2d_line_segments_get_segments_count(shape, NULL), RES_BAD_ARG); - CHECK(s2d_line_segments_get_segments_count(NULL, &n), RES_BAD_ARG); - CHECK(s2d_line_segments_get_segments_count(shape, &n), RES_OK); - CHECK(n, nsegs); + CHK(s2d_line_segments_get_segments_count(NULL, NULL) == RES_BAD_ARG); + CHK(s2d_line_segments_get_segments_count(shape, NULL) == RES_BAD_ARG); + CHK(s2d_line_segments_get_segments_count(NULL, &n) == RES_BAD_ARG); + CHK(s2d_line_segments_get_segments_count(shape, &n) == RES_OK); + CHK(n == nsegs); #define GET_ATTR s2d_line_segments_get_vertex_attrib - CHECK(GET_ATTR(NULL, nverts, S2D_ATTRIBS_COUNT__, NULL), RES_BAD_ARG); - CHECK(GET_ATTR(shape, nverts, S2D_ATTRIBS_COUNT__, NULL), RES_BAD_ARG); - CHECK(GET_ATTR(NULL, 0, S2D_ATTRIBS_COUNT__, NULL), RES_BAD_ARG); - CHECK(GET_ATTR(shape, 0, S2D_ATTRIBS_COUNT__, NULL), RES_BAD_ARG); - CHECK(GET_ATTR(NULL, nverts, S2D_POSITION, NULL), RES_BAD_ARG); - CHECK(GET_ATTR(shape, nverts, S2D_POSITION, NULL), RES_BAD_ARG); - CHECK(GET_ATTR(NULL, 0, S2D_POSITION, NULL), RES_BAD_ARG); - CHECK(GET_ATTR(shape, 0, S2D_POSITION, NULL), RES_BAD_ARG); - CHECK(GET_ATTR(NULL, nverts, S2D_ATTRIBS_COUNT__, &attr), RES_BAD_ARG); - CHECK(GET_ATTR(shape, nverts, S2D_ATTRIBS_COUNT__, &attr), RES_BAD_ARG); - CHECK(GET_ATTR(NULL, 0, S2D_ATTRIBS_COUNT__, &attr), RES_BAD_ARG); - CHECK(GET_ATTR(shape, 0, S2D_ATTRIBS_COUNT__, &attr), RES_BAD_ARG); - CHECK(GET_ATTR(NULL, nverts, S2D_POSITION, &attr), RES_BAD_ARG); - CHECK(GET_ATTR(shape, nverts, S2D_POSITION, &attr), RES_BAD_ARG); - CHECK(GET_ATTR(NULL, 0, S2D_POSITION, &attr), RES_BAD_ARG); + CHK(GET_ATTR(NULL, nverts, S2D_ATTRIBS_COUNT__, NULL) == RES_BAD_ARG); + CHK(GET_ATTR(shape, nverts, S2D_ATTRIBS_COUNT__, NULL) == RES_BAD_ARG); + CHK(GET_ATTR(NULL, 0, S2D_ATTRIBS_COUNT__, NULL) == RES_BAD_ARG); + CHK(GET_ATTR(shape, 0, S2D_ATTRIBS_COUNT__, NULL) == RES_BAD_ARG); + CHK(GET_ATTR(NULL, nverts, S2D_POSITION, NULL) == RES_BAD_ARG); + CHK(GET_ATTR(shape, nverts, S2D_POSITION, NULL) == RES_BAD_ARG); + CHK(GET_ATTR(NULL, 0, S2D_POSITION, NULL) == RES_BAD_ARG); + CHK(GET_ATTR(shape, 0, S2D_POSITION, NULL) == RES_BAD_ARG); + CHK(GET_ATTR(NULL, nverts, S2D_ATTRIBS_COUNT__, &attr) == RES_BAD_ARG); + CHK(GET_ATTR(shape, nverts, S2D_ATTRIBS_COUNT__, &attr) == RES_BAD_ARG); + CHK(GET_ATTR(NULL, 0, S2D_ATTRIBS_COUNT__, &attr) == RES_BAD_ARG); + CHK(GET_ATTR(shape, 0, S2D_ATTRIBS_COUNT__, &attr) == RES_BAD_ARG); + CHK(GET_ATTR(NULL, nverts, S2D_POSITION, &attr) == RES_BAD_ARG); + CHK(GET_ATTR(shape, nverts, S2D_POSITION, &attr) == RES_BAD_ARG); + CHK(GET_ATTR(NULL, 0, S2D_POSITION, &attr) == RES_BAD_ARG); FOR_EACH(id, 0, nverts) { float pos[2]; line_segments_get_position(id, pos, data); - CHECK(GET_ATTR(shape, id, S2D_POSITION, &attr), RES_OK); - CHECK(attr.type, S2D_FLOAT2); - CHECK(attr.usage, S2D_POSITION); - CHECK(f2_eq_eps(attr.value, pos, 1.e-6f), 1); + CHK(GET_ATTR(shape, id, S2D_POSITION, &attr) == RES_OK); + CHK(attr.type == S2D_FLOAT2); + CHK(attr.usage == S2D_POSITION); + CHK(f2_eq_eps(attr.value, pos, 1.e-6f) == 1); } #undef GET_ATTR - CHECK(s2d_line_segments_get_segment_indices(NULL, nsegs, NULL), RES_BAD_ARG); - CHECK(s2d_line_segments_get_segment_indices(shape, nsegs, NULL), RES_BAD_ARG); - CHECK(s2d_line_segments_get_segment_indices(NULL, nsegs, ids), RES_BAD_ARG); - CHECK(s2d_line_segments_get_segment_indices(shape, nsegs, ids), RES_BAD_ARG); - CHECK(s2d_line_segments_get_segment_indices(NULL, 0, NULL), RES_BAD_ARG); - CHECK(s2d_line_segments_get_segment_indices(shape, 0, NULL), RES_BAD_ARG); - CHECK(s2d_line_segments_get_segment_indices(NULL, 0, ids), RES_BAD_ARG); + CHK(s2d_line_segments_get_segment_indices(NULL, nsegs, NULL) == RES_BAD_ARG); + CHK(s2d_line_segments_get_segment_indices(shape, nsegs, NULL) == RES_BAD_ARG); + CHK(s2d_line_segments_get_segment_indices(NULL, nsegs, ids) == RES_BAD_ARG); + CHK(s2d_line_segments_get_segment_indices(shape, nsegs, ids) == RES_BAD_ARG); + CHK(s2d_line_segments_get_segment_indices(NULL, 0, NULL) == RES_BAD_ARG); + CHK(s2d_line_segments_get_segment_indices(shape, 0, NULL) == RES_BAD_ARG); + CHK(s2d_line_segments_get_segment_indices(NULL, 0, ids) == RES_BAD_ARG); FOR_EACH(id, 0, nsegs) { unsigned indices[2]; line_segments_get_ids(id, indices, data); - CHECK(s2d_line_segments_get_segment_indices(shape, id, ids), RES_OK); - CHECK(ids[0], indices[0]); - CHECK(ids[1], indices[1]); + CHK(s2d_line_segments_get_segment_indices(shape, id, ids) == RES_OK); + CHK(ids[0] == indices[0]); + CHK(ids[1] == indices[1]); } - CHECK(s2d_shape_is_enabled(NULL, NULL), RES_BAD_ARG); - CHECK(s2d_shape_is_enabled(shape, NULL), RES_BAD_ARG); - CHECK(s2d_shape_is_enabled(NULL, &c), RES_BAD_ARG); - CHECK(s2d_shape_is_enabled(shape, &c), RES_OK); - NCHECK(c, 0); + CHK(s2d_shape_is_enabled(NULL, NULL) == RES_BAD_ARG); + CHK(s2d_shape_is_enabled(shape, NULL) == RES_BAD_ARG); + CHK(s2d_shape_is_enabled(NULL, &c) == RES_BAD_ARG); + CHK(s2d_shape_is_enabled(shape, &c) == RES_OK); + CHK(c != 0); - CHECK(s2d_shape_enable(NULL, 0), RES_BAD_ARG); - CHECK(s2d_shape_enable(shape, 0), RES_OK); - CHECK(s2d_shape_is_enabled(shape, &c), RES_OK); - CHECK(c, 0); + CHK(s2d_shape_enable(NULL, 0) == RES_BAD_ARG); + CHK(s2d_shape_enable(shape, 0) == RES_OK); + CHK(s2d_shape_is_enabled(shape, &c) == RES_OK); + CHK(c == 0); - CHECK(s2d_shape_flip_contour(NULL), RES_BAD_ARG); - CHECK(s2d_shape_flip_contour(shape), RES_OK); - CHECK(s2d_shape_flip_contour(shape), RES_OK); + CHK(s2d_shape_flip_contour(NULL) == RES_BAD_ARG); + CHK(s2d_shape_flip_contour(shape) == RES_OK); + CHK(s2d_shape_flip_contour(shape) == RES_OK); #define SET_FILTER_FUNC s2d_line_segments_set_hit_filter_function #define GET_FILTER_DATA s2d_line_segments_get_hit_filter_data - CHECK(SET_FILTER_FUNC(NULL, NULL, NULL), RES_BAD_ARG); - CHECK(SET_FILTER_FUNC(shape, NULL, NULL), RES_OK); - CHECK(SET_FILTER_FUNC(NULL, filter_none, NULL), RES_BAD_ARG); - CHECK(SET_FILTER_FUNC(shape, filter_none, NULL), RES_OK); - - CHECK(GET_FILTER_DATA(NULL, NULL), RES_BAD_ARG); - CHECK(GET_FILTER_DATA(shape, NULL), RES_BAD_ARG); - CHECK(GET_FILTER_DATA(NULL, &data), RES_BAD_ARG); - CHECK(GET_FILTER_DATA(shape, &data), RES_OK); - CHECK(data, NULL); - - CHECK(SET_FILTER_FUNC(shape, NULL, NULL), RES_OK); - CHECK(GET_FILTER_DATA(shape, &data), RES_OK); - CHECK(data, NULL); - CHECK(SET_FILTER_FUNC(shape, filter_none, (void*)(uintptr_t)0xDEADBEEF), RES_OK); - CHECK(GET_FILTER_DATA(shape, &data), RES_OK); - CHECK((uintptr_t)data, 0xDEADBEEF); + CHK(SET_FILTER_FUNC(NULL, NULL, NULL) == RES_BAD_ARG); + CHK(SET_FILTER_FUNC(shape, NULL, NULL) == RES_OK); + CHK(SET_FILTER_FUNC(NULL, filter_none, NULL) == RES_BAD_ARG); + CHK(SET_FILTER_FUNC(shape, filter_none, NULL) == RES_OK); + + CHK(GET_FILTER_DATA(NULL, NULL) == RES_BAD_ARG); + CHK(GET_FILTER_DATA(shape, NULL) == RES_BAD_ARG); + CHK(GET_FILTER_DATA(NULL, &data) == RES_BAD_ARG); + CHK(GET_FILTER_DATA(shape, &data) == RES_OK); + CHK(data == NULL); + + CHK(SET_FILTER_FUNC(shape, NULL, NULL) == RES_OK); + CHK(GET_FILTER_DATA(shape, &data) == RES_OK); + CHK(data == NULL); + CHK(SET_FILTER_FUNC(shape, filter_none, (void*)(uintptr_t)0xDEADBEEF) == RES_OK); + CHK(GET_FILTER_DATA(shape, &data) == RES_OK); + CHK((uintptr_t)data == 0xDEADBEEF); #undef SET_FILTER_FUNC #undef GET_FILTER_DATA - CHECK(s2d_shape_create_line_segments(dev, &shape_copy), RES_OK); - CHECK(s2d_line_segments_copy(NULL, NULL), RES_BAD_ARG); - CHECK(s2d_line_segments_copy(shape, NULL), RES_BAD_ARG); - CHECK(s2d_line_segments_copy(NULL, shape_copy), RES_BAD_ARG); - CHECK(s2d_line_segments_copy(shape, shape_copy), RES_OK); + CHK(s2d_shape_create_line_segments(dev, &shape_copy) == RES_OK); + CHK(s2d_line_segments_copy(NULL, NULL) == RES_BAD_ARG); + CHK(s2d_line_segments_copy(shape, NULL) == RES_BAD_ARG); + CHK(s2d_line_segments_copy(NULL, shape_copy) == RES_BAD_ARG); + CHK(s2d_line_segments_copy(shape, shape_copy) == RES_OK); - CHECK(s2d_shape_ref_put(shape), RES_OK); - CHECK(s2d_shape_ref_put(shape_copy), RES_OK); - CHECK(s2d_device_ref_put(dev), RES_OK); + CHK(s2d_shape_ref_put(shape) == RES_OK); + CHK(s2d_shape_ref_put(shape_copy) == RES_OK); + CHK(s2d_device_ref_put(dev) == RES_OK); check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator); - CHECK(mem_allocated_size(), 0); + CHK(mem_allocated_size() == 0); return 0; } diff --git a/src/test_s2d_trace_ray.c b/src/test_s2d_trace_ray.c @@ -40,8 +40,8 @@ filter_hit void* filter_data) { (void)dir, (void)org; - NCHECK(hit, NULL); - CHECK((intptr_t)filter_data, 0xDEADBEEF); + CHK(hit != NULL); + CHK((intptr_t)filter_data == 0xDEADBEEF); if(!ray_data) return 0; return S2D_PRIMITIVE_EQ((struct s2d_primitive*)ray_data, &hit->prim); } @@ -62,9 +62,9 @@ main(int argc, char** argv) mem_init_proxy_allocator(&allocator, &mem_default_allocator); - CHECK(s2d_device_create(NULL, &allocator, 1, &dev), RES_OK); - CHECK(s2d_shape_create_line_segments(dev, &shape), RES_OK); - CHECK(s2d_scene_create(dev, &scn), RES_OK); + CHK(s2d_device_create(NULL, &allocator, 1, &dev) == RES_OK); + CHK(s2d_shape_create_line_segments(dev, &shape) == RES_OK); + CHK(s2d_scene_create(dev, &scn) == RES_OK); vdata.type = S2D_FLOAT2; vdata.usage = S2D_POSITION; @@ -74,166 +74,166 @@ main(int argc, char** argv) (void*)&box_desc), RES_OK); #define SET_FILTER_FUNC s2d_line_segments_set_hit_filter_function - CHECK(SET_FILTER_FUNC(NULL, NULL, NULL), RES_BAD_ARG); - CHECK(SET_FILTER_FUNC(shape, NULL, NULL), RES_OK); - CHECK(SET_FILTER_FUNC(NULL, filter_hit, NULL), RES_BAD_ARG); - CHECK(SET_FILTER_FUNC(shape, filter_hit, NULL), RES_OK); - CHECK(SET_FILTER_FUNC(shape, filter_hit, (void*)0xDEADBEEF), RES_OK); + CHK(SET_FILTER_FUNC(NULL, NULL, NULL) == RES_BAD_ARG); + CHK(SET_FILTER_FUNC(shape, NULL, NULL) == RES_OK); + CHK(SET_FILTER_FUNC(NULL, filter_hit, NULL) == RES_BAD_ARG); + CHK(SET_FILTER_FUNC(shape, filter_hit, NULL) == RES_OK); + CHK(SET_FILTER_FUNC(shape, filter_hit, (void*)0xDEADBEEF) == RES_OK); #undef SET_FILTER_FUNC - CHECK(s2d_scene_attach_shape(scn, shape), RES_OK); + CHK(s2d_scene_attach_shape(scn, shape) == RES_OK); f2(org, 0.f, 0.f); f2(dir, 0.f, -1.f); f2(range, 0, FLT_MAX); - CHECK(s2d_scene_begin_session(scn, S2D_TRACE), RES_OK); - - CHECK(s2d_scene_trace_ray(NULL, NULL, NULL, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(scn, NULL, NULL, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(NULL, org, NULL, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(scn, org, NULL, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(NULL, NULL, dir, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(scn, NULL, dir, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(NULL, org, dir, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(scn, org, dir, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(NULL, NULL, NULL, range, NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(scn, NULL, NULL, range, NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(NULL, org, NULL, range, NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(scn, org, NULL, range, NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(NULL, NULL, dir, range, NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(scn, NULL, dir, range, NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(NULL, org, dir, range, NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(scn, org, dir, range, NULL, NULL), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(NULL, NULL, NULL, NULL, NULL, &hit), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(scn, NULL, NULL, NULL, NULL, &hit), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(NULL, org, NULL, NULL, NULL, &hit), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(scn, org, NULL, NULL, NULL, &hit), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(NULL, NULL, dir, NULL, NULL, &hit), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(scn, NULL, dir, NULL, NULL, &hit), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(NULL, org, dir, NULL, NULL, &hit), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(scn, org, dir, NULL, NULL, &hit), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(NULL, NULL, NULL, range, NULL, &hit), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(scn, NULL, NULL, range, NULL, &hit), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(NULL, org, NULL, range, NULL, &hit), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(scn, org, NULL, range, NULL, &hit), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(NULL, NULL, dir, range, NULL, &hit), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(scn, NULL, dir, range, NULL, &hit), RES_BAD_ARG); - CHECK(s2d_scene_trace_ray(NULL, org, dir, range, NULL, &hit), RES_BAD_ARG); + CHK(s2d_scene_begin_session(scn, S2D_TRACE) == RES_OK); + + CHK(s2d_scene_trace_ray(NULL, NULL, NULL, NULL, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(scn, NULL, NULL, NULL, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(NULL, org, NULL, NULL, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(scn, org, NULL, NULL, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(NULL, NULL, dir, NULL, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(scn, NULL, dir, NULL, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(NULL, org, dir, NULL, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(scn, org, dir, NULL, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(NULL, NULL, NULL, range, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(scn, NULL, NULL, range, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(NULL, org, NULL, range, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(scn, org, NULL, range, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(NULL, NULL, dir, range, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(scn, NULL, dir, range, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(NULL, org, dir, range, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(scn, org, dir, range, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(NULL, NULL, NULL, NULL, NULL, &hit) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(scn, NULL, NULL, NULL, NULL, &hit) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(NULL, org, NULL, NULL, NULL, &hit) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(scn, org, NULL, NULL, NULL, &hit) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(NULL, NULL, dir, NULL, NULL, &hit) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(scn, NULL, dir, NULL, NULL, &hit) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(NULL, org, dir, NULL, NULL, &hit) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(scn, org, dir, NULL, NULL, &hit) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(NULL, NULL, NULL, range, NULL, &hit) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(scn, NULL, NULL, range, NULL, &hit) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(NULL, org, NULL, range, NULL, &hit) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(scn, org, NULL, range, NULL, &hit) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(NULL, NULL, dir, range, NULL, &hit) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(scn, NULL, dir, range, NULL, &hit) == RES_BAD_ARG); + CHK(s2d_scene_trace_ray(NULL, org, dir, range, NULL, &hit) == RES_BAD_ARG); f2(dir, 0.f, -1.f); - CHECK(s2d_scene_trace_ray(scn, org, dir, range, NULL, &hit), RES_OK); - CHECK(S2D_HIT_NONE(&hit), 0); - CHECK(hit.prim.prim_id, 0); + CHK(s2d_scene_trace_ray(scn, org, dir, range, NULL, &hit) == RES_OK); + CHK(S2D_HIT_NONE(&hit) == 0); + CHK(hit.prim.prim_id == 0); f2_normalize(N, hit.normal); - CHECK(f2_eq_eps(N, f2(dir, 0.f, 1.f), 1.e-6f), 1); - CHECK(eq_epsf(hit.u, 0.5f, 1.e-6f), 1); - CHECK(eq_epsf(hit.distance, 1.0f, 1.e-6f), 1); + CHK(f2_eq_eps(N, f2(dir, 0.f, 1.f), 1.e-6f) == 1); + CHK(eq_epsf(hit.u, 0.5f, 1.e-6f) == 1); + CHK(eq_epsf(hit.distance, 1.0f, 1.e-6f) == 1); prim = hit.prim; f2(dir, 0.f, -1.f); range[1] = 0.5f; - CHECK(s2d_scene_trace_ray(scn, org, dir, range, NULL, &hit), RES_OK); - CHECK(S2D_HIT_NONE(&hit), 1); + CHK(s2d_scene_trace_ray(scn, org, dir, range, NULL, &hit) == RES_OK); + CHK(S2D_HIT_NONE(&hit) == 1); range[1] = FLT_MAX; f2(dir, 0.f, -1.f); - CHECK(s2d_scene_trace_ray(scn, org, dir, range, &prim, &hit), RES_OK); - CHECK(S2D_HIT_NONE(&hit), 1); + CHK(s2d_scene_trace_ray(scn, org, dir, range, &prim, &hit) == RES_OK); + CHK(S2D_HIT_NONE(&hit) == 1); f2(dir, -1.f, 0.f); - CHECK(s2d_scene_trace_ray(scn, org, dir, range, NULL, &hit), RES_OK); - CHECK(S2D_HIT_NONE(&hit), 0); - CHECK(hit.prim.prim_id, 1); + CHK(s2d_scene_trace_ray(scn, org, dir, range, NULL, &hit) == RES_OK); + CHK(S2D_HIT_NONE(&hit) == 0); + CHK(hit.prim.prim_id == 1); f2_normalize(N, hit.normal); - CHECK(f2_eq_eps(N, f2(dir, 1.f, 0.f), 1.e-6f), 1); - CHECK(eq_epsf(hit.u, 0.5f, 1.e-6f), 1); - CHECK(eq_epsf(hit.distance, 1.0f, 1.e-6f), 1); + CHK(f2_eq_eps(N, f2(dir, 1.f, 0.f), 1.e-6f) == 1); + CHK(eq_epsf(hit.u, 0.5f, 1.e-6f) == 1); + CHK(eq_epsf(hit.distance, 1.0f, 1.e-6f) == 1); f2(dir, 0.f, 1.f); - CHECK(s2d_scene_trace_ray(scn, org, dir, range, NULL, &hit), RES_OK); - CHECK(S2D_HIT_NONE(&hit), 0); - CHECK(hit.prim.prim_id, 2); + CHK(s2d_scene_trace_ray(scn, org, dir, range, NULL, &hit) == RES_OK); + CHK(S2D_HIT_NONE(&hit) == 0); + CHK(hit.prim.prim_id == 2); f2_normalize(N, hit.normal); - CHECK(f2_eq_eps(N, f2(dir, 0.f, -1.f), 1.e-6f), 1); - CHECK(eq_epsf(hit.u, 0.5f, 1.e-6f), 1); - CHECK(eq_epsf(hit.distance, 1.0f, 1.e-6f), 1); + CHK(f2_eq_eps(N, f2(dir, 0.f, -1.f), 1.e-6f) == 1); + CHK(eq_epsf(hit.u, 0.5f, 1.e-6f) == 1); + CHK(eq_epsf(hit.distance, 1.0f, 1.e-6f) == 1); prim2 = hit.prim; f2(org, 0.f, 2.f); f2(dir, 0.f, -1.f); - CHECK(s2d_scene_trace_ray(scn, org, dir, range, NULL, &hit), RES_OK); - CHECK(S2D_HIT_NONE(&hit), 0); - CHECK(S2D_PRIMITIVE_EQ(&hit.prim, &prim2), 1); + CHK(s2d_scene_trace_ray(scn, org, dir, range, NULL, &hit) == RES_OK); + CHK(S2D_HIT_NONE(&hit) == 0); + CHK(S2D_PRIMITIVE_EQ(&hit.prim, &prim2) == 1); - CHECK(s2d_scene_trace_ray(scn, org, dir, range, &prim2, &hit), RES_OK); - CHECK(S2D_HIT_NONE(&hit), 0); - CHECK(S2D_PRIMITIVE_EQ(&hit.prim, &prim), 1); + CHK(s2d_scene_trace_ray(scn, org, dir, range, &prim2, &hit) == RES_OK); + CHK(S2D_HIT_NONE(&hit) == 0); + CHK(S2D_PRIMITIVE_EQ(&hit.prim, &prim) == 1); f2_splat(org, 0.f); f2(dir, 1.f, 0.f); - CHECK(s2d_scene_trace_ray(scn, org, dir, range, NULL, &hit), RES_OK); - CHECK(S2D_HIT_NONE(&hit), 0); - CHECK(hit.prim.prim_id, 3); + CHK(s2d_scene_trace_ray(scn, org, dir, range, NULL, &hit) == RES_OK); + CHK(S2D_HIT_NONE(&hit) == 0); + CHK(hit.prim.prim_id == 3); f2_normalize(N, hit.normal); - CHECK(f2_eq_eps(N, f2(dir, -1.f, 0.f), 1.e-6f), 1); - CHECK(eq_epsf(hit.u, 0.5f, 1.e-6f), 1); - CHECK(eq_epsf(hit.distance, 1.0f, 1.e-6f), 1); + CHK(f2_eq_eps(N, f2(dir, -1.f, 0.f), 1.e-6f) == 1); + CHK(eq_epsf(hit.u, 0.5f, 1.e-6f) == 1); + CHK(eq_epsf(hit.distance, 1.0f, 1.e-6f) == 1); f2(range, 1.f, -1.f); - CHECK(s2d_scene_trace_ray(scn, org, dir, range, NULL, &hit), RES_OK); - CHECK(S2D_HIT_NONE(&hit), 1); + CHK(s2d_scene_trace_ray(scn, org, dir, range, NULL, &hit) == RES_OK); + CHK(S2D_HIT_NONE(&hit) == 1); f2(dir, 1.f, 1.f); f2(range, 0.f, FLT_MAX); - CHECK(s2d_scene_trace_ray(scn, org, dir, range, NULL, &hit), RES_BAD_ARG); + CHK(s2d_scene_trace_ray(scn, org, dir, range, NULL, &hit) == RES_BAD_ARG); - CHECK(s2d_scene_end_session(scn), RES_OK); + CHK(s2d_scene_end_session(scn) == RES_OK); f2(dir, 1.f, 0.f); f2(range, 0.f, FLT_MAX); - CHECK(s2d_scene_trace_ray(scn, org, dir, range, NULL, &hit), RES_BAD_OP); + CHK(s2d_scene_trace_ray(scn, org, dir, range, NULL, &hit) == RES_BAD_OP); - CHECK(s2d_scene_begin_session(scn, S2D_TRACE), RES_OK); + CHK(s2d_scene_begin_session(scn, S2D_TRACE) == RES_OK); f2_sub(dir, f2(dir, 0.75f, -1.f), org); f2_normalize(dir, dir); - CHECK(s2d_scene_trace_ray(scn, org, dir, range, NULL, &hit), RES_OK); - CHECK(S2D_HIT_NONE(&hit), 0); - CHECK(eq_epsf(hit.u, 0.125f, 1.e-6f), 1); - CHECK(eq_epsf(hit.distance, 1.25, 1.E-6f), 1); + CHK(s2d_scene_trace_ray(scn, org, dir, range, NULL, &hit) == RES_OK); + CHK(S2D_HIT_NONE(&hit) == 0); + CHK(eq_epsf(hit.u, 0.125f, 1.e-6f) == 1); + CHK(eq_epsf(hit.distance, 1.25, 1.E-6f) == 1); f2_sub(dir, f2(dir, -1.f, 0.25f), org); f2_normalize(dir, dir); - CHECK(s2d_scene_trace_ray(scn, org, dir, range, NULL, &hit), RES_OK); - CHECK(S2D_HIT_NONE(&hit), 0); - CHECK(eq_epsf(hit.u, 0.625, 1.e-6f), 1); - CHECK(eq_epsf(hit.distance, (float)sqrt(1.0625f), 1e-6f), 1); + CHK(s2d_scene_trace_ray(scn, org, dir, range, NULL, &hit) == RES_OK); + CHK(S2D_HIT_NONE(&hit) == 0); + CHK(eq_epsf(hit.u, 0.625, 1.e-6f) == 1); + CHK(eq_epsf(hit.distance, (float)sqrt(1.0625f), 1e-6f) == 1); f2(org, -1.25f, 0.f); f2(dir, -1, 0.f); - CHECK(s2d_scene_trace_ray(scn, org, dir, range, NULL, &hit), RES_OK); - CHECK(S2D_HIT_NONE(&hit), 1); + CHK(s2d_scene_trace_ray(scn, org, dir, range, NULL, &hit) == RES_OK); + CHK(S2D_HIT_NONE(&hit) == 1); f2(dir, 1, 0.f); - CHECK(s2d_scene_trace_ray(scn, org, dir, range, NULL, &hit), RES_OK); - CHECK(S2D_HIT_NONE(&hit), 0); - CHECK(hit.prim.prim_id, 1); + CHK(s2d_scene_trace_ray(scn, org, dir, range, NULL, &hit) == RES_OK); + CHK(S2D_HIT_NONE(&hit) == 0); + CHK(hit.prim.prim_id == 1); f2_normalize(N, hit.normal); - CHECK(f2_eq_eps(N, f2(dir, 1.f, 0.f), 1.e-6f), 1); - CHECK(eq_epsf(hit.u, 0.5f, 1.e-6f), 1); - CHECK(eq_epsf(hit.distance, 0.25f, 1.e-6f), 1); + CHK(f2_eq_eps(N, f2(dir, 1.f, 0.f), 1.e-6f) == 1); + CHK(eq_epsf(hit.u, 0.5f, 1.e-6f) == 1); + CHK(eq_epsf(hit.distance, 0.25f, 1.e-6f) == 1); - CHECK(s2d_scene_end_session(scn), RES_OK); + CHK(s2d_scene_end_session(scn) == RES_OK); - CHECK(s2d_device_ref_put(dev), RES_OK); - CHECK(s2d_shape_ref_put(shape), RES_OK); - CHECK(s2d_scene_ref_put(scn), RES_OK); + CHK(s2d_device_ref_put(dev) == RES_OK); + CHK(s2d_shape_ref_put(shape) == RES_OK); + CHK(s2d_scene_ref_put(scn) == RES_OK); check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator); - CHECK(mem_allocated_size(), 0); + CHK(mem_allocated_size() == 0); return 0; } diff --git a/src/test_s2d_trace_ray_3d.c b/src/test_s2d_trace_ray_3d.c @@ -50,10 +50,10 @@ main(int argc, char** argv) mem_init_proxy_allocator(&allocator, &mem_default_allocator); - CHECK(s2d_device_create(NULL, &allocator, 1, &dev), RES_OK); - CHECK(s2d_scene_create(dev, &scn), RES_OK); - CHECK(s2d_shape_create_line_segments(dev, &shape), RES_OK); - CHECK(s2d_scene_attach_shape(scn, shape), RES_OK); + CHK(s2d_device_create(NULL, &allocator, 1, &dev) == RES_OK); + CHK(s2d_scene_create(dev, &scn) == RES_OK); + CHK(s2d_shape_create_line_segments(dev, &shape) == RES_OK); + CHK(s2d_scene_attach_shape(scn, shape) == RES_OK); vdata.get = line_segments_get_position; vdata.type = S2D_FLOAT2; @@ -66,74 +66,74 @@ main(int argc, char** argv) f3(dir, 1, 0, 0); f2(range, 0, FLT_MAX); - CHECK(s2d_scene_begin_session(scn, S2D_TRACE), RES_OK); + CHK(s2d_scene_begin_session(scn, S2D_TRACE) == RES_OK); #define TRACE_3D s2d_scene_trace_ray_3d - CHECK(TRACE_3D(NULL, NULL, NULL, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(TRACE_3D(scn, NULL, NULL, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(TRACE_3D(NULL, org, NULL, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(TRACE_3D(scn, org, NULL, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(TRACE_3D(NULL, NULL, dir, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(TRACE_3D(scn, NULL, dir, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(TRACE_3D(NULL, org, dir, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(TRACE_3D(scn, org, dir, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(TRACE_3D(NULL, NULL, NULL, range, NULL, NULL), RES_BAD_ARG); - CHECK(TRACE_3D(scn, NULL, NULL, range, NULL, NULL), RES_BAD_ARG); - CHECK(TRACE_3D(NULL, org, NULL, range, NULL, NULL), RES_BAD_ARG); - CHECK(TRACE_3D(scn, org, NULL, range, NULL, NULL), RES_BAD_ARG); - CHECK(TRACE_3D(NULL, NULL, dir, range, NULL, NULL), RES_BAD_ARG); - CHECK(TRACE_3D(scn, NULL, dir, range, NULL, NULL), RES_BAD_ARG); - CHECK(TRACE_3D(NULL, org, dir, range, NULL, NULL), RES_BAD_ARG); - CHECK(TRACE_3D(scn, org, dir, range, NULL, NULL), RES_BAD_ARG); - CHECK(TRACE_3D(NULL, NULL, NULL, NULL, NULL, &hit), RES_BAD_ARG); - CHECK(TRACE_3D(scn, NULL, NULL, NULL, NULL, &hit), RES_BAD_ARG); - CHECK(TRACE_3D(NULL, org, NULL, NULL, NULL, &hit), RES_BAD_ARG); - CHECK(TRACE_3D(scn, org, NULL, NULL, NULL, &hit), RES_BAD_ARG); - CHECK(TRACE_3D(NULL, NULL, dir, NULL, NULL, &hit), RES_BAD_ARG); - CHECK(TRACE_3D(scn, NULL, dir, NULL, NULL, &hit), RES_BAD_ARG); - CHECK(TRACE_3D(NULL, org, dir, NULL, NULL, &hit), RES_BAD_ARG); - CHECK(TRACE_3D(scn, org, dir, NULL, NULL, &hit), RES_BAD_ARG); - CHECK(TRACE_3D(NULL, NULL, NULL, range, NULL, &hit), RES_BAD_ARG); - CHECK(TRACE_3D(scn, NULL, NULL, range, NULL, &hit), RES_BAD_ARG); - CHECK(TRACE_3D(NULL, org, NULL, range, NULL, &hit), RES_BAD_ARG); - CHECK(TRACE_3D(scn, org, NULL, range, NULL, &hit), RES_BAD_ARG); - CHECK(TRACE_3D(NULL, NULL, dir, range, NULL, &hit), RES_BAD_ARG); - CHECK(TRACE_3D(scn, NULL, dir, range, NULL, &hit), RES_BAD_ARG); - CHECK(TRACE_3D(NULL, org, dir, range, NULL, &hit), RES_BAD_ARG); - CHECK(TRACE_3D(scn, org, dir, range, NULL, &hit), RES_OK); - - CHECK(S2D_HIT_NONE(&hit), 0); + CHK(TRACE_3D(NULL, NULL, NULL, NULL, NULL, NULL) == RES_BAD_ARG); + CHK(TRACE_3D(scn, NULL, NULL, NULL, NULL, NULL) == RES_BAD_ARG); + CHK(TRACE_3D(NULL, org, NULL, NULL, NULL, NULL) == RES_BAD_ARG); + CHK(TRACE_3D(scn, org, NULL, NULL, NULL, NULL) == RES_BAD_ARG); + CHK(TRACE_3D(NULL, NULL, dir, NULL, NULL, NULL) == RES_BAD_ARG); + CHK(TRACE_3D(scn, NULL, dir, NULL, NULL, NULL) == RES_BAD_ARG); + CHK(TRACE_3D(NULL, org, dir, NULL, NULL, NULL) == RES_BAD_ARG); + CHK(TRACE_3D(scn, org, dir, NULL, NULL, NULL) == RES_BAD_ARG); + CHK(TRACE_3D(NULL, NULL, NULL, range, NULL, NULL) == RES_BAD_ARG); + CHK(TRACE_3D(scn, NULL, NULL, range, NULL, NULL) == RES_BAD_ARG); + CHK(TRACE_3D(NULL, org, NULL, range, NULL, NULL) == RES_BAD_ARG); + CHK(TRACE_3D(scn, org, NULL, range, NULL, NULL) == RES_BAD_ARG); + CHK(TRACE_3D(NULL, NULL, dir, range, NULL, NULL) == RES_BAD_ARG); + CHK(TRACE_3D(scn, NULL, dir, range, NULL, NULL) == RES_BAD_ARG); + CHK(TRACE_3D(NULL, org, dir, range, NULL, NULL) == RES_BAD_ARG); + CHK(TRACE_3D(scn, org, dir, range, NULL, NULL) == RES_BAD_ARG); + CHK(TRACE_3D(NULL, NULL, NULL, NULL, NULL, &hit) == RES_BAD_ARG); + CHK(TRACE_3D(scn, NULL, NULL, NULL, NULL, &hit) == RES_BAD_ARG); + CHK(TRACE_3D(NULL, org, NULL, NULL, NULL, &hit) == RES_BAD_ARG); + CHK(TRACE_3D(scn, org, NULL, NULL, NULL, &hit) == RES_BAD_ARG); + CHK(TRACE_3D(NULL, NULL, dir, NULL, NULL, &hit) == RES_BAD_ARG); + CHK(TRACE_3D(scn, NULL, dir, NULL, NULL, &hit) == RES_BAD_ARG); + CHK(TRACE_3D(NULL, org, dir, NULL, NULL, &hit) == RES_BAD_ARG); + CHK(TRACE_3D(scn, org, dir, NULL, NULL, &hit) == RES_BAD_ARG); + CHK(TRACE_3D(NULL, NULL, NULL, range, NULL, &hit) == RES_BAD_ARG); + CHK(TRACE_3D(scn, NULL, NULL, range, NULL, &hit) == RES_BAD_ARG); + CHK(TRACE_3D(NULL, org, NULL, range, NULL, &hit) == RES_BAD_ARG); + CHK(TRACE_3D(scn, org, NULL, range, NULL, &hit) == RES_BAD_ARG); + CHK(TRACE_3D(NULL, NULL, dir, range, NULL, &hit) == RES_BAD_ARG); + CHK(TRACE_3D(scn, NULL, dir, range, NULL, &hit) == RES_BAD_ARG); + CHK(TRACE_3D(NULL, org, dir, range, NULL, &hit) == RES_BAD_ARG); + CHK(TRACE_3D(scn, org, dir, range, NULL, &hit) == RES_OK); + + CHK(S2D_HIT_NONE(&hit) == 0); f2_normalize(hit.normal, hit.normal); - CHECK(f2_eq_eps(hit.normal, f2(tmp, -1.f, 0.f), 1.e-6f), 1); - CHECK(eq_epsf(hit.distance, 1.f, 1.e-6f), 1); - CHECK(eq_epsf(hit.u, 0.5f, 1.e-6f), 1); + CHK(f2_eq_eps(hit.normal, f2(tmp, -1.f, 0.f), 1.e-6f) == 1); + CHK(eq_epsf(hit.distance, 1.f, 1.e-6f) == 1); + CHK(eq_epsf(hit.u, 0.5f, 1.e-6f) == 1); f3_normalize(dir, f3(dir, 1.f, 0.f, 1.f)); - CHECK(TRACE_3D(scn, org, dir, range, NULL, &hit), RES_OK); - CHECK(S2D_HIT_NONE(&hit), 0); + CHK(TRACE_3D(scn, org, dir, range, NULL, &hit) == RES_OK); + CHK(S2D_HIT_NONE(&hit) == 0); f2_normalize(hit.normal, hit.normal); - CHECK(f2_eq_eps(hit.normal, f2(tmp, -1.f, 0.f), 1.e-6f), 1); - CHECK(eq_epsf(hit.u, 0.5f, 1.e-6f), 1); + CHK(f2_eq_eps(hit.normal, f2(tmp, -1.f, 0.f), 1.e-6f) == 1); + CHK(eq_epsf(hit.u, 0.5f, 1.e-6f) == 1); dot = dir[0]; - CHECK(eq_epsf(hit.distance, 1.f / dot, 1.e-6f), 1); + CHK(eq_epsf(hit.distance, 1.f / dot, 1.e-6f) == 1); range[1] = 1.2f; - CHECK(TRACE_3D(scn, org, dir, range, NULL, &hit), RES_OK); - CHECK(S2D_HIT_NONE(&hit), 1); + CHK(TRACE_3D(scn, org, dir, range, NULL, &hit) == RES_OK); + CHK(S2D_HIT_NONE(&hit) == 1); - CHECK(s2d_scene_end_session(scn), RES_OK); + CHK(s2d_scene_end_session(scn) == RES_OK); - CHECK(TRACE_3D(scn, org, dir, range, NULL, &hit), RES_BAD_OP); + CHK(TRACE_3D(scn, org, dir, range, NULL, &hit) == RES_BAD_OP); #undef TRACE_3D - CHECK(s2d_scene_ref_put(scn), RES_OK); - CHECK(s2d_shape_ref_put(shape), RES_OK); - CHECK(s2d_device_ref_put(dev), RES_OK); + CHK(s2d_scene_ref_put(scn) == RES_OK); + CHK(s2d_shape_ref_put(shape) == RES_OK); + CHK(s2d_device_ref_put(dev) == RES_OK); check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator); - CHECK(mem_allocated_size(), 0); + CHK(mem_allocated_size() == 0); return 0; } diff --git a/src/test_s2d_utils.h b/src/test_s2d_utils.h @@ -63,7 +63,7 @@ line_segments_get_ids(const unsigned isegment, unsigned ids[2], void* data) { const unsigned id = isegment * 2; const struct line_segments_desc* desc = data; - NCHECK(desc, NULL); + CHK(desc != NULL); ids[0] = desc->indices[id + 0]; ids[1] = desc->indices[id + 1]; } @@ -73,7 +73,7 @@ line_segments_get_position(const unsigned ivert, float position[2], void* data) { const unsigned id = ivert * 2; const struct line_segments_desc* desc = data; - NCHECK(desc, NULL); + CHK(desc != NULL); position[0] = desc->vertices[id + 0]; position[1] = desc->vertices[id + 1]; }