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:
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);