commit 9a3eeb57fdb532847e1a6fab02fa76d3c26baed7
parent b6d9b307a4c735229076f321d9c8fdd9ad484dbe
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Thu, 10 Sep 2015 16:27:30 +0200
Add and test the s3d_scene_get_primitive function
Add the S3D_GET_PRIMITIVE session flag that allows to get a given
primitive onto the scene.
Diffstat:
7 files changed, 249 insertions(+), 49 deletions(-)
diff --git a/src/s3d.h b/src/s3d.h
@@ -95,7 +95,7 @@ enum s3d_transform_space {
* value. They can be used in conjunction with a dynamic array to map from s3d
* geometry to application geometry */
struct s3d_primitive {
- unsigned prim_id; /* Primitive identifer */
+ unsigned prim_id; /* Primitive identifier */
unsigned geom_id; /* Geometry identifier */
unsigned inst_id; /* Instance identifier */
/* Internal data. Should not be accessed */
@@ -157,7 +157,8 @@ static const struct s3d_hit S3D_HIT_NULL =
enum s3d_session_flag {
S3D_TRACE = BIT(0),
- S3D_SAMPLE = BIT(1)
+ S3D_SAMPLE = BIT(1),
+ S3D_GET_PRIMITIVE = BIT(2)
};
/* Helper macro that defines whether or not the hit is valid, i.e. the ray
@@ -300,10 +301,18 @@ s3d_scene_trace_rays
S3D_API res_T
s3d_scene_sample
(struct s3d_scene* scn,
- const float u, const float v, const float w,
+ const float u, const float v, const float w, /* in [0, 1) */
struct s3d_primitive* primitive, /* sampled primitive */
float uv[2]);
+/* Retrieve a primitive from the scene. Can be called only if an S3D_SAMPLE
+ * session is active on `scn'*/
+S3D_API res_T
+s3d_scene_get_primitive
+ (struct s3d_scene* scn,
+ const unsigned iprim, /* in [0, #prims) */
+ struct s3d_primitive* prim);
+
/* Retrieve the number of scene primitives */
S3D_API res_T
s3d_scene_primitives_count
diff --git a/src/s3d_mesh.c b/src/s3d_mesh.c
@@ -439,7 +439,6 @@ mesh_compute_volume(struct mesh* mesh, const char flip_surface)
if(volume < 0.0 && volume > 3.e-6)
volume = 0;
- ASSERT(volume >= 0.0);
return (float)(volume / 3.0);
}
diff --git a/src/s3d_scene.c b/src/s3d_scene.c
@@ -366,8 +366,6 @@ scene_compute_cdf(struct s3d_scene* scn)
len = darray_float_size_get(&geom->data.mesh->cdf);
if(len) {
area += darray_float_cdata_get(&geom->data.mesh->cdf)[len - 1];
- fltui.ui = geom->irtc;
- fltui.flt = area;
}
break;
case GEOM_INSTANCE:
@@ -377,12 +375,12 @@ scene_compute_cdf(struct s3d_scene* scn)
if(len) {
area += darray_fltui_cdata_get
(&geom->data.instance->scene->cdf)[len - 1].flt;
- fltui.ui = geom->irtc;
- fltui.flt = area;
}
break;
default: FATAL("Unreachable code\n"); break;
}
+ fltui.ui = geom->irtc;
+ fltui.flt = area;
if(len) {
res = darray_fltui_push_back(&scn->cdf, &fltui);
if(res != RES_OK) goto error;
@@ -391,13 +389,75 @@ scene_compute_cdf(struct s3d_scene* scn)
exit:
return res;
error:
+ darray_fltui_clear(&scn->cdf);
goto exit;
}
static FINLINE bool
operator < (const struct fltui& it, const float val)
{
- return it.flt < val;
+ return it.flt <= val; /* TODO commen the <= */
+}
+
+static res_T
+scene_compute_nprims_cdf(struct s3d_scene* scn)
+{
+ struct list_node* node;
+ struct s3d_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) {
+ shape = CONTAINER_OF(node, struct s3d_shape, scene_attachment);
+ pgeom = htable_geom_find(&scn->cached_geoms, &shape);
+ ASSERT(pgeom != NULL);
+ geom = *pgeom;
+ struct nprims_cdf cdf;
+
+ if(!geom->is_enabled) continue;
+
+ switch(geom->type) {
+ case GEOM_MESH:
+ len = mesh_get_ntris(geom->data.mesh);
+ nprims += (unsigned)len;
+ break;
+ case GEOM_INSTANCE:
+ res = scene_compute_nprims_cdf(geom->data.instance->scene);
+ if(res != RES_OK) goto error;
+ len = darray_nprims_cdf_size_get(&geom->data.instance->scene->nprims_cdf);
+ if(len) {
+ nprims += darray_nprims_cdf_cdata_get
+ (&geom->data.instance->scene->nprims_cdf)[len - 1].nprims;
+ }
+ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+
+ cdf.nprims = nprims;
+ cdf.irtc = geom->irtc;
+ if(len) {
+ 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 FINLINE bool
+operator < (const struct nprims_cdf& it, const unsigned iprim)
+{
+ return it.nprims <= iprim; /* TODO comment the <= */
}
static res_T
@@ -442,17 +502,18 @@ scene_sync(struct s3d_scene* scn, const int session_mask)
if(res != RES_OK)
goto error;
}
-
if((session_mask & S3D_SAMPLE) != 0) {
res = scene_compute_cdf(scn);
if(res != RES_OK) goto error;
}
-
+ if((session_mask & S3D_GET_PRIMITIVE) != 0) {
+ res = scene_compute_nprims_cdf(scn);
+ if(res != RES_OK) goto error;
+ }
if((session_mask & S3D_TRACE) != 0 && scn->is_rtc_scn_outdated) {
rtcCommit(scn->rtc_scn);
scn->is_rtc_scn_outdated = 0;
}
-
scn->session_mask = session_mask;
exit:
@@ -475,6 +536,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);
S3D(device_ref_put(dev));
}
@@ -502,6 +564,7 @@ s3d_scene_create(struct s3d_device* dev, struct s3d_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);
S3D(device_ref_get(dev));
scn->dev = dev;
@@ -633,7 +696,9 @@ s3d_scene_begin_session(struct s3d_scene* scn, const int session_mask)
{
if(!scn)
return RES_BAD_ARG;
- if(!(session_mask&S3D_TRACE) && !(session_mask&S3D_SAMPLE))
+ if(!(session_mask&S3D_TRACE)
+ && !(session_mask&S3D_SAMPLE)
+ && !(session_mask&S3D_GET_PRIMITIVE))
return RES_BAD_ARG;
return scene_sync(scn, session_mask);
}
@@ -834,11 +899,12 @@ s3d_scene_sample
geom = darray_geom_data_get(&scn->embree2geoms)[igeom];
ASSERT(geom);
- if(geom->type != GEOM_INSTANCE) {
+ if(geom->type == GEOM_MESH) {
primitive->inst__ = NULL;
primitive->inst_id = S3D_INVALID_ID;
} else {
/* Find the sampled instantiated geometry */
+ ASSERT(geom->type == GEOM_INSTANCE);
primitive->inst__ = geom;
primitive->inst_id = geom->name;
if(darray_fltui_size_get(&geom->data.instance->scene->cdf) == 1) {
@@ -882,13 +948,89 @@ error:
}
res_T
-s3d_scene_primitives_count(struct s3d_scene* scn, size_t* prims_count)
+s3d_scene_get_primitive
+ (struct s3d_scene* scn, const unsigned iprim, struct s3d_primitive* prim)
{
- struct list_node* node;
- struct s3d_shape* shape;
- struct geometry** pgeom;
struct geometry* geom;
- size_t inst_count;
+ const struct nprims_cdf* begin, *end, *found;
+ size_t nprims;
+ size_t igeom;
+ size_t i;
+ res_T res = RES_OK;
+
+ if(!scn || !prim) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if((scn->session_mask & S3D_GET_PRIMITIVE) == 0) {
+ res = RES_BAD_OP;
+ goto error;
+ }
+ S3D(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);
+
+ if(geom->type == GEOM_MESH) {
+ prim->inst__ = NULL;
+ prim->inst_id = S3D_INVALID_ID;
+ } else {
+ ASSERT(geom->type == GEOM_INSTANCE);
+ prim->inst__ = geom;
+ prim->inst_id = geom->name;
+ if(darray_nprims_cdf_size_get(&geom->data.instance->scene->nprims_cdf)==1) {
+ igeom = darray_nprims_cdf_cdata_get
+ (&geom->data.instance->scene->nprims_cdf)[0].irtc;
+ } else {
+ begin = darray_nprims_cdf_cdata_get
+ (&geom->data.instance->scene->nprims_cdf);
+ end = begin + darray_nprims_cdf_size_get
+ (&geom->data.instance->scene->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
+ (&geom->data.instance->scene->embree2geoms)[igeom];
+ ASSERT(geom);
+ }
+ ASSERT(geom->type == GEOM_MESH);
+ ASSERT(i < mesh_get_ntris(geom->data.mesh));
+ prim->mesh__ = geom;
+ prim->geom_id = geom->name;
+ prim->prim_id = (unsigned)i;
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+s3d_scene_primitives_count(struct s3d_scene* scn, size_t* prims_count)
+{
res_T res = RES_OK;
if(!scn || !prims_count) {
@@ -899,28 +1041,40 @@ s3d_scene_primitives_count(struct s3d_scene* scn, size_t* prims_count)
res = RES_BAD_OP;
goto error;
}
+ if((scn->session_mask & S3D_GET_PRIMITIVE) != 0) {
+ const size_t len = darray_nprims_cdf_size_get(&scn->nprims_cdf);
+ if(!len) {
+ *prims_count = 0;
+ } else {
+ *prims_count = darray_nprims_cdf_cdata_get(&scn->nprims_cdf)[len - 1].nprims;
+ }
+ } else {
+ struct list_node* node;
+ struct s3d_shape* shape;
+ struct geometry** pgeom;
+ struct geometry* geom;
+ size_t inst_count;
+ *prims_count = 0;
+ LIST_FOR_EACH(node, &scn->shapes) {
+ shape = CONTAINER_OF(node, struct s3d_shape, scene_attachment);
+ pgeom = htable_geom_find(&scn->cached_geoms, &shape);
+ ASSERT(pgeom != NULL);
+ geom = *pgeom;
- *prims_count = 0;
- LIST_FOR_EACH(node, &scn->shapes) {
- shape = CONTAINER_OF(node, struct s3d_shape, scene_attachment);
- pgeom = htable_geom_find(&scn->cached_geoms, &shape);
- ASSERT(pgeom != NULL);
- geom = *pgeom;
-
- if(!geom->is_enabled) continue;
+ if(!geom->is_enabled) continue;
- switch(geom->type) {
- case GEOM_MESH:
- *prims_count += mesh_get_ntris(geom->data.mesh);
- break;
- case GEOM_INSTANCE:
- S3D(scene_primitives_count(geom->data.instance->scene, &inst_count));
- *prims_count += inst_count;
- break;
- default: FATAL("Unreachable code\n"); break;
+ switch(geom->type) {
+ case GEOM_MESH:
+ *prims_count += mesh_get_ntris(geom->data.mesh);
+ break;
+ case GEOM_INSTANCE:
+ S3D(scene_primitives_count(geom->data.instance->scene, &inst_count));
+ *prims_count += inst_count;
+ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
}
}
-
exit:
return res;
error:
diff --git a/src/s3d_scene_c.h b/src/s3d_scene_c.h
@@ -68,11 +68,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 s3d_scene {
struct list_node 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 */
+ struct darray_nprims_cdf nprims_cdf;
size_t instances_count; /* # instances in the scene */
diff --git a/src/test_s3d_cbox.h b/src/test_s3d_cbox.h
@@ -54,6 +54,7 @@ static const float cbox_walls[] = {
0.f, 559.f, 548.f,
552.f, 559.f, 548.f
};
+const unsigned cbox_walls_nverts = sizeof(cbox_walls) / sizeof(float[3]);
const unsigned cbox_walls_ids[] = {
0, 1, 2, 2, 3, 0, /* Bottom */
@@ -62,6 +63,7 @@ const unsigned cbox_walls_ids[] = {
0, 3, 7, 7, 4, 0, /* Right */
2, 3, 7, 7, 6, 2 /* Back */
};
+const unsigned cbox_walls_ntris = sizeof(cbox_walls_ids) / sizeof(unsigned[3]);
static const struct cbox_desc cbox_walls_desc = { cbox_walls, cbox_walls_ids };
@@ -98,6 +100,9 @@ static const unsigned cbox_block_ids[] = {
0, 1, 5, 5, 4, 0
};
+const unsigned cbox_block_nverts = sizeof(cbox_short_block) / sizeof(float[3]);
+const unsigned cbox_block_ntris = sizeof(cbox_block_ids) / sizeof(unsigned[3]);
+
/*******************************************************************************
* Callbacks
******************************************************************************/
diff --git a/src/test_s3d_scene.c b/src/test_s3d_scene.c
@@ -88,6 +88,7 @@ int
main(int argc, char** argv)
{
struct mem_allocator allocator;
+ struct s3d_primitive prims[10];
struct s3d_device* dev;
struct s3d_scene* scn;
struct s3d_scene* scn2;
@@ -96,8 +97,6 @@ main(int argc, char** argv)
struct s3d_shape* shapes[4];
const size_t nshapes = sizeof(shapes)/sizeof(struct s3d_shape*);
void* data = (void*)&cbox_walls_desc;
- const unsigned cbox_ntris = sizeof(cbox_walls_ids) / sizeof(unsigned[3]);
- const unsigned cbox_nverts = sizeof(cbox_walls) / sizeof(float[3]);
size_t i;
size_t nprims;
float area, volume;
@@ -226,8 +225,8 @@ main(int argc, char** argv)
attribs[0].get = cbox_get_position;
attribs[1] = S3D_VERTEX_DATA_NULL;
CHECK(s3d_shape_create_mesh(dev, shapes + 0), RES_OK);
- CHECK(s3d_mesh_setup_indexed_vertices
- (shapes[0], cbox_ntris, cbox_get_ids, cbox_nverts, attribs, data), RES_OK);
+ CHECK(s3d_mesh_setup_indexed_vertices(shapes[0], cbox_walls_ntris,
+ cbox_get_ids, cbox_walls_nverts, attribs, data), RES_OK);
CHECK(s3d_scene_attach_shape(scn, shapes[0]), RES_OK);
CHECK(s3d_scene_begin_session(scn, S3D_TRACE), RES_OK);
@@ -254,11 +253,27 @@ main(int argc, char** argv)
CHECK(nprims, 10);
CHECK(s3d_scene_end_session(scn2), RES_OK);
- CHECK(s3d_scene_begin_session(scn2, S3D_SAMPLE), RES_OK);
+ CHECK(s3d_scene_begin_session(scn2, S3D_GET_PRIMITIVE), RES_OK);
CHECK(s3d_scene_compute_area(scn2, &area), RES_OK);
CHECK(eq_epsf(area, 1532296.f, 1.e-6f), 1);
CHECK(s3d_scene_primitives_count(scn, &nprims), RES_OK);
CHECK(nprims, 10);
+
+ CHECK(s3d_scene_get_primitive(NULL, 11, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_get_primitive(scn2, 11, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_get_primitive(NULL, 0, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_get_primitive(scn2, 0, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_get_primitive(NULL, 11, prims + 0), RES_BAD_ARG);
+ CHECK(s3d_scene_get_primitive(scn2, 11, prims + 0), RES_BAD_ARG);
+ CHECK(s3d_scene_get_primitive(NULL, 0, prims + 0), RES_BAD_ARG);
+
+ FOR_EACH(i, 0, nprims) {
+ size_t j;
+ CHECK(s3d_scene_get_primitive(scn2, (unsigned)i, prims + i), RES_OK);
+ CHECK(S3D_PRIMITIVE_EQ(prims + i, &S3D_PRIMITIVE_NULL), 0);
+ FOR_EACH(j, 0, i)
+ CHECK(S3D_PRIMITIVE_EQ(prims + i, prims + j), 0);
+ }
CHECK(s3d_scene_end_session(scn2), RES_OK);
attribs[0].type = S3D_FLOAT3;
diff --git a/src/test_s3d_trace_ray.c b/src/test_s3d_trace_ray.c
@@ -94,6 +94,7 @@ main(int argc, char** argv)
struct s3d_shape* tall_block;
struct s3d_shape* short_block;
struct s3d_vertex_data attribs[4];
+ struct s3d_primitive prims[30];
struct camera cam;
struct cbox_desc desc;
unsigned char* img = NULL;
@@ -107,6 +108,7 @@ main(int argc, char** argv)
unsigned walls_id;
unsigned tall_block_id;
unsigned short_block_id;
+ size_t i;
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
@@ -123,8 +125,8 @@ main(int argc, char** argv)
attribs[0].get = cbox_get_position;
attribs[1] = S3D_VERTEX_DATA_NULL;
- ntris = sizeof(cbox_walls_ids)/sizeof(unsigned[3]);
- nverts = sizeof(cbox_walls)/sizeof(float[3]);
+ ntris = cbox_walls_ntris;
+ nverts = cbox_walls_nverts;
desc.vertices = cbox_walls;
desc.indices = cbox_walls_ids;
CHECK(s3d_shape_create_mesh(dev, &walls), RES_OK);
@@ -176,8 +178,8 @@ main(int argc, char** argv)
CHECK(s3d_scene_clear(scn), RES_OK);
/* Update the inst with the CBox tall block mesh */
- ntris = sizeof(cbox_block_ids)/sizeof(unsigned[3]);
- nverts = sizeof(cbox_short_block)/sizeof(float[3]);
+ ntris = cbox_block_ntris;
+ nverts = cbox_block_nverts;
desc.vertices = cbox_short_block;
desc.indices = cbox_block_ids;
CHECK(s3d_shape_create_mesh(dev, &tall_block), RES_OK);
@@ -210,8 +212,8 @@ main(int argc, char** argv)
/* Create the CBox walls */
desc.indices = cbox_walls_ids;
desc.vertices = cbox_walls;
- nverts = sizeof(cbox_walls)/sizeof(float[3]);
- ntris = sizeof(cbox_walls_ids)/sizeof(unsigned[3]);
+ nverts = cbox_walls_nverts;
+ ntris = cbox_walls_ntris;
CHECK(s3d_shape_create_mesh(dev, &walls), RES_OK);
CHECK(s3d_shape_get_id(walls, &walls_id), RES_OK);
CHECK(s3d_mesh_setup_indexed_vertices
@@ -251,10 +253,19 @@ main(int argc, char** argv)
CHECK(s3d_scene_attach_shape(scn, short_block), RES_OK);
CHECK(s3d_scene_attach_shape(scn, tall_block), RES_OK);
- CHECK(s3d_scene_begin_session(scn2, S3D_TRACE), RES_OK);
+ CHECK(s3d_scene_begin_session(scn2, S3D_TRACE|S3D_GET_PRIMITIVE), RES_OK);
CHECK(s3d_scene_primitives_count(scn2, &nprims), RES_OK);
CHECK(nprims, 30);
+ FOR_EACH(i, 0, nprims) {
+ size_t j;
+ CHECK(s3d_scene_get_primitive(scn2, (unsigned)i, prims + i), RES_OK);
+ CHECK(S3D_PRIMITIVE_EQ(prims + i, &S3D_PRIMITIVE_NULL), 0);
+ FOR_EACH(j, 0, i) {
+ CHECK(S3D_PRIMITIVE_EQ(prims + i, prims + j), 0);
+ }
+ }
+
camera_init(&cam);
FOR_EACH(iy, 0, IMG_HEIGHT) {
float pixel[2];