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