star-3d

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

commit e3e536e1a075572a6c01b8262151950cf7be963d
parent 6bbd7d19755a04c283db5bd189b97ba5fff0c09f
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Fri,  1 Jul 2016 12:26:00 +0200

Add verbosity to the s3d_scene API

Conditionally print error/warning messages with respect to the
verbosity of the Star-3D device.

Diffstat:
Mcmake/CMakeLists.txt | 2+-
Msrc/s3d_device.c | 40++++++++++++++++++++++++++++++++++++++++
Msrc/s3d_device_c.h | 24++++++++++++++++++++++++
Msrc/s3d_scene.c | 123++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Msrc/test_s3d_scene.c | 8+++++++-
5 files changed, 169 insertions(+), 28 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -44,7 +44,7 @@ set(Embree_DIR ${_current_source_dir}/) find_package(Embree REQUIRED) find_package(RCMake 0.2.2 REQUIRED) -find_package(RSys 0.2.1 REQUIRED) +find_package(RSys 0.3.1 REQUIRED) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${RCMAKE_SOURCE_DIR}) include(rcmake) include(rcmake_runtime) diff --git a/src/s3d_device.c b/src/s3d_device.c @@ -40,6 +40,21 @@ /******************************************************************************* * Helper functions ******************************************************************************/ +static INLINE void +log_msg + (struct s3d_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) { @@ -110,3 +125,28 @@ s3d_device_ref_put(struct s3d_device* dev) return RES_OK; } +/******************************************************************************* + * Local functions + ******************************************************************************/ +void +log_error(struct s3d_device* dev, const char* msg, ...) +{ + va_list vargs_list; + ASSERT(dev && msg); + + va_start(vargs_list, msg); + log_msg(dev, LOG_ERROR, msg, vargs_list); + va_end(vargs_list); +} + +void +log_warning(struct s3d_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/s3d_device_c.h b/src/s3d_device_c.h @@ -54,5 +54,29 @@ struct s3d_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 s3d_device* dev, + const char* msg, + ...) +#ifdef COMPILER_GCC + __attribute((format(printf, 2, 3))) +#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 s3d_device* dev, + const char* msg, + ...) +#ifdef COMPILER_GCC + __attribute((format(printf, 2, 3))) +#endif +; + #endif /* S3D_DEVICE_C_H */ diff --git a/src/s3d_scene.c b/src/s3d_scene.c @@ -443,7 +443,8 @@ error: } static res_T -scene_detach_shape(struct s3d_scene* scn, struct s3d_shape* shape) +scene_detach_shape + (struct s3d_scene* scn, struct s3d_shape* shape, const char* caller_name) { struct geometry** pgeom; ASSERT(scn && shape && !is_list_empty(&shape->scene_attachment)); @@ -452,7 +453,11 @@ scene_detach_shape(struct s3d_scene* scn, struct s3d_shape* shape) pgeom = htable_geom_find(&scn->cached_geoms, &shape); if(pgeom) { /* Remove the cached shape mesh */ struct geometry* geom = *pgeom; - if(scn->session_mask != 0) return RES_BAD_OP; + if(scn->session_mask != 0) { + log_error(scn->dev, + "%s: the shape is currently 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); @@ -835,10 +840,16 @@ s3d_scene_attach_shape(struct s3d_scene* scn, struct s3d_shape* shape) { if(!scn || !shape) return RES_BAD_ARG; - if(!is_list_empty(&shape->scene_attachment)) + if(!is_list_empty(&shape->scene_attachment)) { + log_error(scn->dev, + "%s: the shape is already attached to a scene.\n", FUNC_NAME); return RES_BAD_ARG; - if(shape->type == GEOM_INSTANCE && shape->data.instance->scene == scn) + } + if(shape->type == GEOM_INSTANCE && shape->data.instance->scene == scn) { + log_error(scn->dev, + "%s: the instantiated scene cannot be attached to itself.\n", FUNC_NAME); return RES_BAD_ARG; + } list_add_tail(&scn->shapes, &shape->scene_attachment); S3D(shape_ref_get(shape)); @@ -853,8 +864,11 @@ s3d_scene_detach_shape(struct s3d_scene* scn, struct s3d_shape* shape) char is_attached; if(!scn || !shape) return RES_BAD_ARG; - if(!(S3D(shape_is_attached(shape, &is_attached)), is_attached)) + if(!(S3D(shape_is_attached(shape, &is_attached)), is_attached)) { + log_error(scn->dev, + "%s: the shape is not attached to a scene.\n", FUNC_NAME); return RES_BAD_ARG; + } #ifndef NDEBUG { /* Check that the shape is attached to `scn' */ struct list_node* node; @@ -868,7 +882,7 @@ s3d_scene_detach_shape(struct s3d_scene* scn, struct s3d_shape* shape) ASSERT(is_found); } #endif - res = scene_detach_shape(scn, shape); + res = scene_detach_shape(scn, shape, FUNC_NAME); if(res != RES_OK) return res; return RES_OK; } @@ -878,11 +892,15 @@ s3d_scene_clear(struct s3d_scene* scn) { struct list_node* node, *tmp; if(!scn) return RES_BAD_ARG; - if(scn->session_mask != 0) return RES_BAD_OP; + if(scn->session_mask != 0) { + log_error(scn->dev, + "%s: cannot clear a scene with an active session.\n", FUNC_NAME); + return RES_BAD_OP; + } LIST_FOR_EACH_SAFE(node, tmp, &scn->shapes) { struct s3d_shape* shape = CONTAINER_OF (node, struct s3d_shape, scene_attachment); - const res_T res = scene_detach_shape(scn, shape); + const res_T res = scene_detach_shape(scn, shape, FUNC_NAME); ASSERT(res == RES_OK); (void)res; } return RES_OK; @@ -895,8 +913,10 @@ s3d_scene_begin_session(struct s3d_scene* scn, const int session_mask) return RES_BAD_ARG; if(!(session_mask&S3D_TRACE) && !(session_mask&S3D_SAMPLE) - && !(session_mask&S3D_GET_PRIMITIVE)) + && !(session_mask&S3D_GET_PRIMITIVE)) { + log_error(scn->dev, "%s: no valid session is defined.\n", FUNC_NAME); return RES_BAD_ARG; + } return scene_sync(scn, session_mask); } @@ -905,8 +925,16 @@ s3d_scene_end_session(struct s3d_scene* scn) { if(!scn) return RES_BAD_ARG; - if(scn->session_mask & S3D_INSTANCE || !scn->session_mask) + if(scn->session_mask & S3D_INSTANCE) { + log_error(scn->dev, + "%s: the scene session was enabled through scene instantiation.\n", + FUNC_NAME); + return RES_BAD_OP; + } + if(!scn->session_mask) { + log_error(scn->dev, "%s: the scene has no active session.\n", FUNC_NAME); return RES_BAD_OP; + } scene_session_clear(scn); return RES_OK; } @@ -932,11 +960,18 @@ s3d_scene_trace_ray struct ray_extended ray_ex; if(!scn || !org || !dir || !range || !hit) return RES_BAD_ARG; - if(!f3_is_normalized(dir)) + if(!f3_is_normalized(dir)) { + log_error(scn->dev, + "%s: unnormalized ray direction {%g, %g, %g}.\n", + FUNC_NAME, SPLIT3(dir)); return RES_BAD_ARG; - if((scn->session_mask & S3D_TRACE) == 0) + } + if((scn->session_mask & S3D_TRACE) == 0) { + log_error(scn->dev, + "%s: no active S3D_TRACE session on the submitted scene.\n", FUNC_NAME); return RES_BAD_OP; - if(range[0] > range[1]) { + } + if(range[0] > range[1]) { /* Degenerated range <=> disabled ray */ *hit = S3D_HIT_NULL; return RES_OK; } @@ -1020,10 +1055,16 @@ s3d_scene_sample } /* Expecting canonic numbers */ if(u < 0.f || u >= 1.f || v < 0.f || v >= 1.f || w < 0.f || w >= 1.f) { + log_error(scn->dev, + "%s: the submitted numbers are not canonical, i.e. they are not in [0, 1[.\n", + FUNC_NAME); res = RES_BAD_ARG; goto error; } if((scn->session_mask & S3D_SAMPLE) == 0) { + log_error(scn->dev, + "%s: no active S3D_SAMPLE session on the submitted scene.\n", + FUNC_NAME); res = RES_BAD_OP; goto error; } @@ -1115,11 +1156,17 @@ s3d_scene_get_primitive goto error; } if((scn->session_mask & S3D_GET_PRIMITIVE) == 0) { + log_error(scn->dev, + "%s: no active S3D_GET_PRIMITIVE session on the submitted scene.\n", + FUNC_NAME); res = RES_BAD_OP; goto error; } S3D(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; } @@ -1194,6 +1241,8 @@ s3d_scene_primitives_count(struct s3d_scene* scn, size_t* prims_count) goto error; } if(!scn->session_mask) { + log_error(scn->dev, + "%s: no active session on the submitted scene.\n", FUNC_NAME); res = RES_BAD_OP; goto error; } @@ -1238,15 +1287,18 @@ error: } res_T -s3d_scene_compute_area(struct s3d_scene* scn, float* area) +s3d_scene_compute_area(struct s3d_scene* scn, float* out_area) { + float area; res_T res = RES_OK; - if(!scn || !area) { + if(!scn || !out_area) { res = RES_BAD_ARG; goto error; } if(!scn->session_mask) { + log_error(scn->dev, + "%s: no active session on the submitted scene.\n", FUNC_NAME); res = RES_BAD_OP; goto error; } @@ -1257,9 +1309,9 @@ s3d_scene_compute_area(struct s3d_scene* scn, float* area) * multiplied by 2; the real scene area is thus the CDF upper bound / 2 */ size_t len = darray_fltui_size_get(&scn->cdf); if(!len) { - *area = 0.f; + area = 0.f; } else { - *area = darray_fltui_cdata_get(&scn->cdf)[len - 1].flt * 0.5f; + area = darray_fltui_cdata_get(&scn->cdf)[len - 1].flt * 0.5f; } } else { struct list_node* node; @@ -1268,7 +1320,7 @@ s3d_scene_compute_area(struct s3d_scene* scn, float* area) struct geometry* geom; float inst_area; - *area = 0.f; + area = 0.f; LIST_FOR_EACH(node, &scn->shapes) { shape = CONTAINER_OF(node, struct s3d_shape, scene_attachment); pgeom = htable_geom_find(&scn->cached_geoms, &shape); @@ -1279,12 +1331,12 @@ s3d_scene_compute_area(struct s3d_scene* scn, float* area) switch(geom->type) { case GEOM_MESH: - *area += mesh_compute_area(geom->data.mesh); + area += mesh_compute_area(geom->data.mesh); break; case GEOM_INSTANCE: /* TODO take into account the instance scale factor */ S3D(scene_compute_area(geom->data.instance->scene, &inst_area)); - *area += inst_area; + area += inst_area; break; default: FATAL("Unreachable code\n"); break; } @@ -1292,30 +1344,35 @@ s3d_scene_compute_area(struct s3d_scene* scn, float* area) } exit: + if(out_area) *out_area = area; return res; error: + area = -1.f; goto exit; } res_T -s3d_scene_compute_volume(struct s3d_scene* scn, float* volume) +s3d_scene_compute_volume(struct s3d_scene* scn, float* out_volume) { struct list_node* node; struct s3d_shape* shape; struct geometry** pgeom; struct geometry* geom; + float volume; res_T res = RES_OK; - if(!scn || !volume) { + if(!scn || !out_volume) { res = RES_BAD_ARG; goto error; } if(!scn->session_mask) { + log_error(scn->dev, + "%s: no active session on the submitted scene.\n", FUNC_NAME); res = RES_BAD_OP; goto error; } - *volume = 0.f; + volume = 0.f; LIST_FOR_EACH(node, &scn->shapes) { shape = CONTAINER_OF(node, struct s3d_shape, scene_attachment); pgeom = htable_geom_find(&scn->cached_geoms, &shape); @@ -1326,18 +1383,28 @@ s3d_scene_compute_volume(struct s3d_scene* scn, float* volume) switch(geom->type) { case GEOM_MESH: - *volume += mesh_compute_volume(geom->data.mesh, geom->flip_surface); + volume += mesh_compute_volume(geom->data.mesh, geom->flip_surface); break; case GEOM_INSTANCE: - *volume += instance_compute_volume(geom->data.instance, geom->flip_surface); + volume += instance_compute_volume(geom->data.instance, geom->flip_surface); break; default: FATAL("Unreachable code\n"); break; } } + if(volume < 0.f) { + log_warning(scn->dev, +"%s:\n" +"\tthe volume is negative. The scene shapes might not represent closed 2D\n" +"\tmanifold volumes, or their surface normal might not point inward the volume.\n", + FUNC_NAME); + } + exit: + if(out_volume) *out_volume = volume; return res; error: + volume = -1.f; goto exit; } @@ -1345,7 +1412,11 @@ res_T s3d_scene_get_aabb(struct s3d_scene* scn, float lower[3], float upper[3]) { if(!scn || !lower || !upper) return RES_BAD_ARG; - if(!scn->session_mask) return RES_BAD_OP; + if(!scn->session_mask) { + log_error(scn->dev, + "%s: no active session on the submitted scene.\n", FUNC_NAME); + return RES_BAD_OP; + } f3_set(lower, scn->lower); f3_set(upper, scn->upper); return RES_OK; diff --git a/src/test_s3d_scene.c b/src/test_s3d_scene.c @@ -105,7 +105,7 @@ main(int argc, char** argv) mem_init_proxy_allocator(&allocator, &mem_default_allocator); - CHECK(s3d_device_create(NULL, &allocator, 0, &dev), RES_OK); + CHECK(s3d_device_create(NULL, &allocator, 1, &dev), RES_OK); FOR_EACH(i, 0, nshapes) CHECK(s3d_shape_create_mesh(dev, shapes + i), RES_OK); @@ -323,6 +323,12 @@ main(int argc, char** argv) CHECK(eq_epsf(volume, 1.f, 1.e-6f), 1); CHECK(s3d_scene_end_session(scn), RES_OK); + CHECK(s3d_shape_flip_surface(shapes[0]), RES_OK); + CHECK(s3d_scene_begin_session(scn, S3D_GET_PRIMITIVE), RES_OK); + CHECK(s3d_scene_compute_volume(scn, &volume), RES_OK); + CHECK(eq_epsf(volume, -1.f, 1.e-6f), 1); + CHECK(s3d_scene_end_session(scn), RES_OK); + CHECK(s3d_scene_get_device(NULL, NULL), RES_BAD_ARG); CHECK(s3d_scene_get_device(scn, NULL), RES_BAD_ARG); CHECK(s3d_scene_get_device(NULL, &dev2), RES_BAD_ARG);