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 4ef3ee2c6998edd30867b1087ac20d226da4a8ff
parent 20d16c1f590b9f43b8ace2f39a49c53b92336aaa
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Fri, 22 Jul 2016 10:50:23 +0200

Add support of multi attachment to the shape

The attached shapes are no more linked listed into the scene. They are
registered into a hash table that map its id to its pointer. Note that
with this update, the shape has no way to know if it is attached to a
scene and consequently the s3d_shape_is_attached function was removed.

Diffstat:
Msrc/s3d_instance.c | 12++++++++----
Msrc/s3d_scene.c | 193++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Msrc/s3d_scene_c.h | 8+++++++-
Msrc/s3d_shape.c | 11-----------
Msrc/s3d_shape_c.h | 1-
Msrc/test_s3d_scene.c | 2+-
Msrc/test_s3d_shape.c | 10----------
7 files changed, 129 insertions(+), 108 deletions(-)

diff --git a/src/s3d_instance.c b/src/s3d_instance.c @@ -106,17 +106,21 @@ instance_ref_put(struct instance* inst) float instance_compute_volume(struct instance* inst, const char flip_surface) { - struct list_node* node; + struct htable_shape_iterator it, end; float volume = 0.f; ASSERT(inst); + htable_shape_begin(&inst->scene->shapes, &it); + htable_shape_end(&inst->scene->shapes, &end); + /* TODO take into account the scale factor of the instance */ - LIST_FOR_EACH(node, &inst->scene->shapes) { - struct s3d_shape* shape = CONTAINER_OF - (node, struct s3d_shape, scene_attachment); + while(!htable_shape_iterator_eq(&it, &end)) { + struct s3d_shape** pshape = htable_shape_iterator_data_get(&it); + struct s3d_shape* shape = *pshape; const char flip = flip_surface ^ shape->flip_surface; ASSERT(shape->type == GEOM_MESH); /* One instancing level is supported */ volume += mesh_compute_volume(shape->data.mesh, flip); + htable_shape_iterator_next(&it); } return volume; } diff --git a/src/s3d_scene.c b/src/s3d_scene.c @@ -447,15 +447,19 @@ error: } static res_T -scene_detach_shape - (struct s3d_scene* scn, struct s3d_shape* shape, const char* caller_name) +scene_clear_cached_geometry + (struct s3d_scene* scn, + struct s3d_shape* shape, + const char* caller_name) { struct geometry** pgeom; unsigned shape_id; - ASSERT(scn && shape && !is_list_empty(&shape->scene_attachment)); + ASSERT(scn && shape); ASSERT(shape->type == GEOM_MESH || shape->type == GEOM_INSTANCE); S3D(shape_get_id(shape, &shape_id)); + ASSERT(htable_shape_find(&scn->shapes, &shape_id) != NULL); + pgeom = htable_geom_find(&scn->cached_geoms, &shape_id); if(pgeom) { /* Remove the cached shape mesh */ struct geometry* geom = *pgeom; @@ -475,22 +479,19 @@ scene_detach_shape nerased = htable_geom_erase(&scn->cached_geoms, &shape_id); ASSERT(nerased == 1); } - list_del(&shape->scene_attachment); if(shape->type == GEOM_INSTANCE) { ASSERT(scn->instances_count != 0); --scn->instances_count; } - S3D(shape_ref_put(shape)); return RES_OK; } static res_T scene_compute_cdf(struct s3d_scene* scn) { - struct list_node* node; - struct s3d_shape* shape; + struct htable_shape_iterator it, end; struct geometry** pgeom; struct geometry* geom; size_t len; @@ -498,13 +499,16 @@ scene_compute_cdf(struct s3d_scene* scn) res_T res = RES_OK; ASSERT(scn); + htable_shape_begin(&scn->shapes, &it); + htable_shape_end(&scn->shapes, &end); + darray_fltui_clear(&scn->cdf); - LIST_FOR_EACH(node, &scn->shapes) { - unsigned shape_id; - shape = CONTAINER_OF(node, struct s3d_shape, scene_attachment); - S3D(shape_get_id(shape, &shape_id)); - pgeom = htable_geom_find(&scn->cached_geoms, &shape_id); + while(!htable_shape_iterator_eq(&it, &end)) { + const unsigned* shape_id = htable_shape_iterator_key_get(&it); + htable_shape_iterator_next(&it); + + pgeom = htable_geom_find(&scn->cached_geoms, shape_id); ASSERT(pgeom != NULL); geom = *pgeom; struct fltui fltui; @@ -548,8 +552,7 @@ error: static void scene_compute_aabb(struct s3d_scene* scn) { - struct list_node* node; - struct s3d_shape* shape; + struct htable_shape_iterator it, end; struct geometry** pgeom; struct geometry* geom; struct instance* inst; @@ -558,11 +561,14 @@ scene_compute_aabb(struct s3d_scene* scn) f3_splat(scn->lower, FLT_MAX); f3_splat(scn->upper,-FLT_MAX); - LIST_FOR_EACH(node, &scn->shapes) { - unsigned shape_id; - shape = CONTAINER_OF(node, struct s3d_shape, scene_attachment); - S3D(shape_get_id(shape, &shape_id)); - pgeom = htable_geom_find(&scn->cached_geoms, &shape_id); + htable_shape_begin(&scn->shapes, &it); + htable_shape_end(&scn->shapes, &end); + + while(!htable_shape_iterator_eq(&it, &end)) { + const unsigned* shape_id = htable_shape_iterator_key_get(&it); + htable_shape_iterator_next(&it); + + pgeom = htable_geom_find(&scn->cached_geoms, shape_id); ASSERT(pgeom != NULL); geom = *pgeom; @@ -601,8 +607,7 @@ scene_compute_nprims_cdf (struct s3d_scene* scn, const char store_cdf) { - struct list_node* node; - struct s3d_shape* shape; + struct htable_shape_iterator it, end; struct geometry** pgeom; struct geometry* geom; size_t len; @@ -612,12 +617,15 @@ scene_compute_nprims_cdf darray_nprims_cdf_clear(&scn->nprims_cdf); + htable_shape_begin(&scn->shapes, &it); + htable_shape_end(&scn->shapes, &end); + nprims = 0; - LIST_FOR_EACH(node, &scn->shapes) { - unsigned shape_id; - shape = CONTAINER_OF(node, struct s3d_shape, scene_attachment); - S3D(shape_get_id(shape, &shape_id)); - pgeom = htable_geom_find(&scn->cached_geoms, &shape_id); + while(!htable_shape_iterator_eq(&it, &end)) { + const unsigned* shape_id = htable_shape_iterator_key_get(&it); + htable_shape_iterator_next(&it); + + pgeom = htable_geom_find(&scn->cached_geoms, shape_id); ASSERT(pgeom != NULL); geom = *pgeom; struct nprims_cdf cdf; @@ -669,8 +677,7 @@ operator < (const struct nprims_cdf& it, const size_t iprim) static res_T scene_sync(struct s3d_scene* scn, const int session_mask) { - struct list_node* node; - struct s3d_shape* shape; + struct htable_shape_iterator it, end; res_T res = RES_OK; ASSERT(scn); @@ -689,8 +696,14 @@ scene_sync(struct s3d_scene* scn, const int session_mask) goto error; } - LIST_FOR_EACH(node, &scn->shapes) { - shape = CONTAINER_OF(node, struct s3d_shape, scene_attachment); + htable_shape_begin(&scn->shapes, &it); + htable_shape_end(&scn->shapes, &end); + + while(!htable_shape_iterator_eq(&it, &end)) { + struct s3d_shape** pshape = htable_shape_iterator_data_get(&it); + struct s3d_shape* shape = *pshape; + htable_shape_iterator_next(&it); + switch(shape->type) { case GEOM_INSTANCE: /* One instancing level is supported */ @@ -744,6 +757,7 @@ scene_release(ref_T* ref) dev = scn->dev; scene_session_clear(scn); if(scn->rtc_scn) rtcDeleteScene(scn->rtc_scn); + htable_shape_release(&scn->shapes); htable_geom_release(&scn->cached_geoms); darray_geom_release(&scn->embree2geoms); darray_fltui_release(&scn->cdf); @@ -771,7 +785,7 @@ s3d_scene_create(struct s3d_device* dev, struct s3d_scene** out_scn) res = RES_MEM_ERR; goto error; } - list_init(&scn->shapes); + htable_shape_init(dev->allocator, &scn->shapes); htable_geom_init(dev->allocator, &scn->cached_geoms); darray_geom_init(dev->allocator, &scn->embree2geoms); darray_fltui_init(dev->allocator, &scn->cdf); @@ -852,20 +866,30 @@ error: res_T s3d_scene_attach_shape(struct s3d_scene* scn, struct s3d_shape* shape) { + unsigned shape_id; + res_T res = RES_OK; + if(!scn || !shape) return RES_BAD_ARG; - 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) { 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_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; + } + + res = htable_shape_set(&scn->shapes, &shape_id, &shape); + if(res != RES_OK) { + log_error(scn->dev, + "%s: cannot attach the shape to the scene.\n", FUNC_NAME); + return RES_OK; + } S3D(shape_ref_get(shape)); scn->instances_count += shape->type == GEOM_INSTANCE; return RES_OK; @@ -874,49 +898,52 @@ s3d_scene_attach_shape(struct s3d_scene* scn, struct s3d_shape* shape) res_T s3d_scene_detach_shape(struct s3d_scene* scn, struct s3d_shape* shape) { + size_t n; + unsigned shape_id; res_T res = RES_OK; - char is_attached; if(!scn || !shape) return RES_BAD_ARG; - if(!(S3D(shape_is_attached(shape, &is_attached)), is_attached)) { + + S3D(shape_get_id(shape, &shape_id)); + if(htable_shape_find(&scn->shapes, &shape_id) == NULL) { log_error(scn->dev, - "%s: the shape is not attached to a scene.\n", FUNC_NAME); + "%s: the shape is not attached to the 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); + + res = scene_clear_cached_geometry(scn, shape, FUNC_NAME); if(res != RES_OK) return res; + + n = htable_shape_erase(&scn->shapes, &shape_id); + ASSERT(n == 1); (void)n; + + S3D(shape_ref_put(shape)); return RES_OK; } res_T s3d_scene_clear(struct s3d_scene* scn) { - struct list_node* node, *tmp; + struct htable_shape_iterator it, end; + if(!scn) return RES_BAD_ARG; 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, FUNC_NAME); + htable_shape_begin(&scn->shapes, &it); + htable_shape_end(&scn->shapes, &end); + while(!htable_shape_iterator_eq(&it, &end)) { + struct s3d_shape** pshape = htable_shape_iterator_data_get(&it); + struct s3d_shape* shape = *pshape; + const res_T res = scene_clear_cached_geometry(scn, shape, FUNC_NAME); ASSERT(res == RES_OK); (void)res; + S3D(shape_ref_put(shape)); + htable_shape_iterator_next(&it); } + htable_shape_clear(&scn->shapes); + return RES_OK; } @@ -1268,17 +1295,19 @@ s3d_scene_primitives_count(struct s3d_scene* scn, size_t* prims_count) *prims_count = darray_nprims_cdf_cdata_get(&scn->nprims_cdf)[len - 1].nprims; } } else { - struct list_node* node; - struct s3d_shape* shape; + struct htable_shape_iterator it, end; struct geometry** pgeom; struct geometry* geom; size_t inst_count; + + htable_shape_begin(&scn->shapes, &it); + htable_shape_end(&scn->shapes, &end); *prims_count = 0; - LIST_FOR_EACH(node, &scn->shapes) { - unsigned shape_id; - shape = CONTAINER_OF(node, struct s3d_shape, scene_attachment); - S3D(shape_get_id(shape, &shape_id)); - pgeom = htable_geom_find(&scn->cached_geoms, &shape_id); + while(!htable_shape_iterator_eq(&it, &end)) { + const unsigned* shape_id = htable_shape_iterator_key_get(&it); + htable_shape_iterator_next(&it); + + pgeom = htable_geom_find(&scn->cached_geoms, shape_id); ASSERT(pgeom != NULL); geom = *pgeom; @@ -1330,18 +1359,20 @@ s3d_scene_compute_area(struct s3d_scene* scn, float* out_area) area = darray_fltui_cdata_get(&scn->cdf)[len - 1].flt * 0.5f; } } else { - struct list_node* node; - struct s3d_shape* shape; + struct htable_shape_iterator it, end; struct geometry** pgeom; struct geometry* geom; float inst_area; + htable_shape_begin(&scn->shapes, &it); + htable_shape_end(&scn->shapes, &end); + area = 0.f; - LIST_FOR_EACH(node, &scn->shapes) { - unsigned shape_id; - shape = CONTAINER_OF(node, struct s3d_shape, scene_attachment); - S3D(shape_get_id(shape, &shape_id)); - pgeom = htable_geom_find(&scn->cached_geoms, &shape_id); + while(!htable_shape_iterator_eq(&it, &end)) { + const unsigned* shape_id = htable_shape_iterator_key_get(&it); + htable_shape_iterator_next(&it); + + pgeom = htable_geom_find(&scn->cached_geoms, shape_id); ASSERT(pgeom != NULL); geom = *pgeom; @@ -1372,8 +1403,7 @@ error: res_T s3d_scene_compute_volume(struct s3d_scene* scn, float* out_volume) { - struct list_node* node; - struct s3d_shape* shape; + struct htable_shape_iterator it, end; struct geometry** pgeom; struct geometry* geom; float volume; @@ -1390,12 +1420,15 @@ s3d_scene_compute_volume(struct s3d_scene* scn, float* out_volume) goto error; } + htable_shape_begin(&scn->shapes, &it); + htable_shape_end(&scn->shapes, &end); + volume = 0.f; - LIST_FOR_EACH(node, &scn->shapes) { - unsigned shape_id; - shape = CONTAINER_OF(node, struct s3d_shape, scene_attachment); - S3D(shape_get_id(shape, &shape_id)); - pgeom = htable_geom_find(&scn->cached_geoms, &shape_id); + while(!htable_shape_iterator_eq(&it, &end)) { + const unsigned* shape_id = htable_shape_iterator_key_get(&it); + htable_shape_iterator_next(&it); + + pgeom = htable_geom_find(&scn->cached_geoms, shape_id); ASSERT(pgeom != NULL); geom = *pgeom; diff --git a/src/s3d_scene_c.h b/src/s3d_scene_c.h @@ -62,6 +62,12 @@ geom_ptr_init__(struct mem_allocator* alloc, struct geometry** geom) #define HTABLE_KEY unsigned /* Id of the shape */ #include <rsys/hash_table.h> +/* Generate the htable_shape hash table */ +#define HTABLE_NAME shape +#define HTABLE_DATA struct s3d_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 @@ -75,7 +81,7 @@ struct nprims_cdf { unsigned nprims, irtc; }; #include <rsys/dynamic_array.h> struct s3d_scene { - struct list_node shapes; /* List of attached shapes */ + struct htable_shape shapes; /* List of attached shapes */ struct htable_geom cached_geoms; /* Cached shape geometries */ struct darray_geom embree2geoms; /* Shape geometries index by embree id */ struct darray_fltui cdf; /* Unormalized CDF */ diff --git a/src/s3d_shape.c b/src/s3d_shape.c @@ -52,7 +52,6 @@ shape_release(ref_T* ref) dev = shape->dev; /* The shape should not be attached */ - ASSERT(is_list_empty(&shape->scene_attachment)); if(shape->type != GEOM_NONE) { switch(shape->type) { case GEOM_MESH: @@ -87,7 +86,6 @@ shape_create(struct s3d_device* dev, struct s3d_shape** out_shape) res = RES_MEM_ERR; goto error; } - list_init(&shape->scene_attachment); S3D(device_ref_get(dev)); shape->dev = dev; ref_init(&shape->ref); @@ -184,14 +182,6 @@ s3d_shape_is_enabled(struct s3d_shape* shape, char* is_enabled) } res_T -s3d_shape_is_attached(struct s3d_shape* shape, char* is_attached) -{ - if(!shape || !is_attached) return RES_BAD_ARG; - *is_attached = !is_list_empty(&shape->scene_attachment); - return RES_OK; -} - -res_T s3d_shape_flip_surface(struct s3d_shape* shape) { if(!shape) return RES_BAD_ARG; @@ -388,4 +378,3 @@ s3d_mesh_get_hit_filter_data(struct s3d_shape* shape, void** data) return RES_OK; } - diff --git a/src/s3d_shape_c.h b/src/s3d_shape_c.h @@ -45,7 +45,6 @@ #include <limits.h> struct s3d_shape { - struct list_node scene_attachment; struct fid id; char flip_surface; diff --git a/src/test_s3d_scene.c b/src/test_s3d_scene.c @@ -120,7 +120,7 @@ main(int argc, char** argv) CHECK(s3d_scene_attach_shape(scn, NULL), RES_BAD_ARG); CHECK(s3d_scene_attach_shape(NULL, shapes[0]), RES_BAD_ARG); CHECK(s3d_scene_attach_shape(scn, shapes[0]), RES_OK); - CHECK(s3d_scene_attach_shape(scn, shapes[0]), RES_BAD_ARG); + CHECK(s3d_scene_attach_shape(scn, shapes[0]), RES_OK); CHECK(s3d_scene_detach_shape(NULL, NULL), RES_BAD_ARG); CHECK(s3d_scene_detach_shape(scn, NULL), RES_BAD_ARG); diff --git a/src/test_s3d_shape.c b/src/test_s3d_shape.c @@ -87,25 +87,15 @@ main(int argc, char** argv) CHECK(s3d_shape_get_id(shape, &id), RES_OK); NCHECK(id, S3D_INVALID_ID); - CHECK(s3d_shape_is_attached(NULL, NULL), RES_BAD_ARG); - CHECK(s3d_shape_is_attached(shape, NULL), RES_BAD_ARG); - CHECK(s3d_shape_is_attached(NULL, &c), RES_BAD_ARG); - CHECK(s3d_shape_is_attached(shape, &c), RES_OK); - CHECK(c, 0); - CHECK(s3d_scene_attach_shape(NULL, NULL), RES_BAD_ARG); CHECK(s3d_scene_attach_shape(scn, NULL), RES_BAD_ARG); CHECK(s3d_scene_attach_shape(NULL, shape), RES_BAD_ARG); CHECK(s3d_scene_attach_shape(scn, shape), RES_OK); - CHECK(s3d_shape_is_attached(shape, &c), RES_OK); - NCHECK(c, 0); CHECK(s3d_scene_detach_shape(NULL, NULL), RES_BAD_ARG); CHECK(s3d_scene_detach_shape(scn, NULL), RES_BAD_ARG); CHECK(s3d_scene_detach_shape(NULL, shape), RES_BAD_ARG); CHECK(s3d_scene_detach_shape(scn, shape), RES_OK); - CHECK(s3d_shape_is_attached(shape, &c), RES_OK); - CHECK(c, 0); attribs[0].type = S3D_FLOAT3; attribs[0].usage = S3D_POSITION;