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 6665dab14dfa1598f8f748125814092c6c6333cc
parent 839506a11d53a28b0c86af1c2af2a00473b5fe3e
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Tue, 28 Jun 2016 09:54:49 +0200

Implement and test the s2d_scene_<get_primitive|primitives_count> funcs

Diffstat:
Msrc/s2d_scene.c | 168++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/s2d_scene_c.h | 7+++++++
Msrc/test_s2d_primitive.c | 11+++++++++++
Msrc/test_s2d_scene.c | 49++++++++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 229 insertions(+), 6 deletions(-)

diff --git a/src/s2d_scene.c b/src/s2d_scene.c @@ -67,7 +67,7 @@ hit_setup(struct s2d_scene* scn, const RTCRay* ray, struct s2d_hit* hit) hit->prim.mesh__ = geom; hit->prim.prim_id = ray->primID; hit->prim.geom_id = geom->name; - hit->prim.scene_prim_id = 0/* TODO */; + 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; @@ -425,6 +425,60 @@ operator < (const struct fltui& it, const float val) 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) { @@ -478,9 +532,10 @@ scene_sync res = scene_compute_cdf(scn); if(res != RES_OK) goto error; } - if((session_mask & S2D_GET_PRIMITIVE) != 0) { - FATAL("The S2D_GET_PRIMITIVE session is not implemented yet!\n"); - } + + 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; @@ -508,6 +563,7 @@ scene_release(ref_T* ref) htable_geom_release(&scn->cached_geoms); darray_geom_release(&scn->embree2geoms); darray_fltui_release(&scn->cdf); + darray_nprims_cdf_release(&scn->nprims_cdf); MEM_RM(dev->allocator, scn); S2D(device_ref_put(dev)); } @@ -543,6 +599,7 @@ s2d_scene_create(struct s2d_device* dev, struct s2d_scene** out_scn) 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); ref_init(&scn->ref); S2D(device_ref_get(dev)); scn->dev = dev; @@ -802,7 +859,7 @@ s2d_scene_sample primitive->mesh__ = geom; primitive->geom_id = geom->name; primitive->prim_id = (unsigned)(flt_found - flt_begin); - primitive->scene_prim_id = 0/*TODO*/; + primitive->scene_prim_id = primitive->prim_id + geom->scene_prim_id_offset; S2D(primitive_sample(primitive, v, s)); exit: @@ -811,3 +868,104 @@ 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", + __FUNCTION__); + res = RES_BAD_OP; + goto error; + } + S2D(scene_primitives_count(scn, &nprims)); + if(iprim >= 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", __FUNCTION__); + 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) continue; + nprims += line_segments_get_nsegments(geom->lines); + } + } +exit: + if(prims_count) *prims_count = nprims; + return res; +error: + goto exit; +} diff --git a/src/s2d_scene_c.h b/src/s2d_scene_c.h @@ -65,11 +65,18 @@ struct fltui { float flt; unsigned ui; }; #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> + 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 */ diff --git a/src/test_s2d_primitive.c b/src/test_s2d_primitive.c @@ -51,6 +51,7 @@ main(int argc, char** argv) struct s2d_device* dev; struct s2d_scene* scn; struct s2d_shape* shape; + size_t nprims; unsigned box_id; float tmp[2]; float length; @@ -111,6 +112,16 @@ main(int argc, char** argv) 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); diff --git a/src/test_s2d_scene.c b/src/test_s2d_scene.c @@ -29,6 +29,8 @@ #include "s2d.h" #include "test_s2d_utils.h" +#include <rsys/float2.h> + int main(int argc, char** argv) { @@ -37,6 +39,9 @@ main(int argc, char** argv) struct s2d_device* dev; struct s2d_scene* scn; struct s2d_shape* shape; + struct s2d_primitive prim; + size_t nprims; + size_t i; int mask; (void)argc, (void)argv; @@ -87,6 +92,12 @@ main(int argc, char** argv) 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); @@ -101,7 +112,7 @@ main(int argc, char** argv) attrib.usage = S2D_POSITION; attrib.get = box_get_position; CHECK(s2d_line_segments_setup_indexed_vertices - (shape, box_nsegs, box_get_ids, box_nverts, &attrib, 1, (void*)&box_desc), + (shape, box_nsegs, box_get_ids, box_nverts, &attrib, 1, (void*)&box_desc), RES_OK); CHECK(s2d_scene_attach_shape(scn, shape), RES_OK); @@ -109,6 +120,42 @@ main(int argc, char** argv) CHECK(s2d_scene_detach_shape(scn, shape), RES_BAD_OP); CHECK(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); + + 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); + + CHECK(s2d_scene_end_session(scn), RES_OK); + + CHECK(s2d_scene_get_primitive(scn, 0, &prim), RES_BAD_OP); + + CHECK(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); + 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; + case 1: f2_eq_eps(attr.value, f2(tmp, 1.f, 0.f), 1.e-6f); break; + case 2: f2_eq_eps(attr.value, f2(tmp, 0.f,-1.f), 1.e-6f); break; + case 3: f2_eq_eps(attr.value, f2(tmp,-1.f, 0.f), 1.e-6f); break; + default: FATAL("Unreachable code.\n"); + } + } + CHECK(s2d_scene_end_session(scn), RES_OK); + CHECK(s2d_shape_ref_put(shape), RES_OK); CHECK(s2d_scene_ref_put(scn), RES_OK); CHECK(s2d_device_ref_put(dev), RES_OK);