commit 969bbf55d3833753fbdd4d9dc62641d66015b3eb
parent 3446ed1eb3fd3f8ce1966c0f169847416afd5843
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Fri, 27 Mar 2015 12:21:15 +0100
Add and test the s3d_scene_<begin|end>_trace functions
Diffstat:
5 files changed, 103 insertions(+), 36 deletions(-)
diff --git a/src/s3d.h b/src/s3d.h
@@ -212,10 +212,18 @@ s3d_scene_clear
(struct s3d_scene* scn);
/* Synchronize the scene geometry with the geometry of its attached shapes. If
- * one is tracing rays into the scene, it waits for the end of the ray-tracing
- * to effectively update the scene representation */
+ * a s3d_scene_begin_trace call is currently active on an attached instance a
+ * RES_BAD_OP error is returned. On success no other begin trace can be invoked
+ * on `scn' and its instances until s3d_scene_end_trace is called. A
+ * s3d_scene_trace_ray operation can be invoked on scn only between a
+ * s3d_scene_begin_trace and s3d_scene_end_trace call. */
S3D_API res_T
-s3d_scene_build
+s3d_scene_begin_trace
+ (struct s3d_scene* scn);
+
+/* End the trace operation on the scene */
+S3D_API res_T
+s3d_scene_end_trace
(struct s3d_scene* scn);
/* Trace a ray into the scene and return the closest intersection. The ray is
diff --git a/src/s3d_scene.c b/src/s3d_scene.c
@@ -44,6 +44,11 @@
* Helper functions
******************************************************************************/
static res_T
+scene_build
+ (struct s3d_scene* scn,
+ const enum build_type type);
+
+static res_T
scene_build_register_mesh(struct s3d_scene* scn, struct mesh* mesh)
{
ASSERT(scn && mesh);
@@ -113,9 +118,15 @@ scene_build_clear(struct s3d_scene* scn)
ninstances = darray_geom2inst_size_get(&scn->geom2inst);
instances = darray_geom2inst_data_get(&scn->geom2inst);
- FOR_EACH(i, 0, ninstances) if(instances[i]) instance_ref_put(instances[i]);
+ FOR_EACH(i, 0, ninstances) {
+ if(instances[i]) {
+ scene_build_clear(instances[i]->scene);
+ instance_ref_put(instances[i]);
+ }
+ }
darray_geom2inst_clear(&scn->geom2inst);
scn->is_rtc_scn_outdated = 0;
+ scn->build_type = BUILD_NONE;
}
static res_T
@@ -229,7 +240,7 @@ scene_setup_shape_instance(struct s3d_scene* scn, struct s3d_shape* shape)
ASSERT(scn && shape && shape->type == SHAPE_INSTANCE);
/* Recursuvely update the scene */
- res = s3d_scene_build(shape->data.instance->scene);
+ res = scene_build(shape->data.instance->scene, BUILD_INDIRECT);
if(res != RES_OK) goto error;
pinst = htable_inst_find(&scn->instances, &shape);
@@ -328,6 +339,40 @@ scene_detach_shape(struct s3d_scene* scn, struct s3d_shape* shape)
}
}
+static res_T
+scene_build(struct s3d_scene* scn, const enum build_type type)
+{
+ struct list_node* node;
+ res_T res = RES_OK;
+ ASSERT(scn && (type == BUILD_DIRECT || type == BUILD_INDIRECT));
+
+ if(scn->build_type != BUILD_NONE) {
+ res = RES_BAD_OP;
+ goto error;
+ }
+
+ LIST_FOR_EACH(node, &scn->shapes) {
+ struct s3d_shape* shape = CONTAINER_OF
+ (node, struct s3d_shape, scene_attachment);
+ switch(shape->type) {
+ case SHAPE_INSTANCE: res = scene_setup_shape_instance(scn, shape); break;
+ case SHAPE_MESH: res = scene_setup_shape_mesh(scn, shape); break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+ if(res != RES_OK)
+ goto error;
+ }
+ if(scn->is_rtc_scn_outdated)
+ rtcCommit(scn->rtc_scn);
+
+ scn->build_type = type;
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
static void
scene_release(ref_T* ref)
{
@@ -374,6 +419,7 @@ s3d_scene_create(struct s3d_device* dev, struct s3d_scene** out_scn)
ref_init(&scn->ref);
S3D(device_ref_get(dev));
scn->dev = dev;
+ scn->build_type = BUILD_NONE;
scn->rtc_scn = rtcNewScene
(RTC_SCENE_DYNAMIC | RTC_SCENE_INCOHERENT | RTC_SCENE_ROBUST,
RTC_INTERSECT1 | RTC_INTERSECT4);
@@ -493,35 +539,21 @@ s3d_scene_clear(struct s3d_scene* scn)
}
res_T
-s3d_scene_build(struct s3d_scene* scn)
+s3d_scene_begin_trace(struct s3d_scene* scn)
{
- struct list_node* node;
- res_T res = RES_OK;
-
- if(!scn) {
- res = RES_BAD_ARG;
- goto error;
- }
+ if(!scn) return RES_BAD_ARG;
+ return scene_build(scn, BUILD_DIRECT);
+}
+res_T
+s3d_scene_end_trace(struct s3d_scene* scn)
+{
+ if(!scn)
+ return RES_BAD_ARG;
+ if(scn->build_type != BUILD_DIRECT)
+ return RES_BAD_OP;
scene_build_clear(scn);
- LIST_FOR_EACH(node, &scn->shapes) {
- struct s3d_shape* shape = CONTAINER_OF
- (node, struct s3d_shape, scene_attachment);
- switch(shape->type) {
- case SHAPE_INSTANCE: res = scene_setup_shape_instance(scn, shape); break;
- case SHAPE_MESH: res = scene_setup_shape_mesh(scn, shape); break;
- default: FATAL("Unreachable code\n"); break;
- }
- if(res != RES_OK)
- goto error;
- }
- if(scn->is_rtc_scn_outdated)
- rtcCommit(scn->rtc_scn);
-
-exit:
- return res;
-error:
- goto exit;
+ return RES_OK;
}
res_T
@@ -537,6 +569,8 @@ s3d_scene_trace_ray
return RES_BAD_ARG;
if(!f3_is_normalized(dir))
return RES_BAD_ARG;
+ if(scn->build_type == BUILD_NONE)
+ return RES_BAD_OP;
if(range[0] > range[1]) {
*hit = S3D_HIT_NULL;
return RES_OK;
diff --git a/src/s3d_scene_c.h b/src/s3d_scene_c.h
@@ -58,6 +58,12 @@
#define HTABLE_KEY struct s3d_shape*
#include <rsys/hash_table.h>
+enum build_type {
+ BUILD_NONE, /* The scene is not built */
+ BUILD_DIRECT, /* The scene is directly build */
+ BUILD_INDIRECT /* The scene is build as an instance */
+};
+
struct s3d_scene {
struct list_node shapes; /* List of attached shapes */
struct htable_mesh meshes; /* List of meshes associated to a shape */
@@ -67,6 +73,8 @@ struct s3d_scene {
RTCScene rtc_scn;
char is_rtc_scn_outdated;
+ enum build_type build_type;
+
struct s3d_device* dev;
ref_T ref;
};
diff --git a/src/test_s3d_scene.c b/src/test_s3d_scene.c
@@ -82,8 +82,13 @@ main(int argc, char** argv)
CHECK(s3d_scene_clear(scn), RES_OK);
CHECK(s3d_scene_instantiate(scn, shapes + 2), RES_OK);
- CHECK(s3d_scene_build(NULL), RES_BAD_ARG);
- CHECK(s3d_scene_build(scn), RES_OK);
+ CHECK(s3d_scene_begin_trace(NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_begin_trace(scn), RES_OK);
+ CHECK(s3d_scene_begin_trace(scn), RES_BAD_OP);
+
+ CHECK(s3d_scene_end_trace(NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_end_trace(scn), RES_OK);
+ CHECK(s3d_scene_end_trace(scn), RES_BAD_OP);
CHECK(s3d_shape_ref_put(shapes[0]), RES_OK);
CHECK(s3d_shape_ref_put(shapes[1]), RES_OK);
diff --git a/src/test_s3d_trace_ray.c b/src/test_s3d_trace_ray.c
@@ -125,6 +125,7 @@ main(int argc, char** argv)
(shape, ntris, cbox_get_ids, nverts, attribs, &desc), RES_OK);
CHECK(s3d_scene_attach_shape(scn, shape), RES_OK);
+ CHECK(s3d_scene_begin_trace(scn), RES_OK);
CHECK(s3d_scene_trace_ray(NULL, NULL, NULL, NULL, NULL), RES_BAD_ARG);
CHECK(s3d_scene_trace_ray(scn, NULL, NULL, NULL, NULL), RES_BAD_ARG);
CHECK(s3d_scene_trace_ray(NULL, org, NULL, NULL, NULL), RES_BAD_ARG);
@@ -157,10 +158,13 @@ main(int argc, char** argv)
CHECK(s3d_scene_trace_ray(scn, NULL, dir, range, &hit), RES_BAD_ARG);
CHECK(s3d_scene_trace_ray(NULL, org, dir, range, &hit), RES_BAD_ARG);
CHECK(s3d_scene_trace_ray(scn, org, dir, range, &hit), RES_OK);
- CHECK(s3d_scene_build(scn), RES_OK);
CHECK(s3d_scene_trace_ray(scn, org, dir, range, &hit), RES_OK);
f3(dir, 1.f, 1.f, 1.f);
CHECK(s3d_scene_trace_ray(scn, org, dir, range, &hit), RES_BAD_ARG);
+ CHECK(s3d_scene_end_trace(scn), RES_OK);
+
+ f3(dir, 0.f, 1.f, 0.f);
+ CHECK(s3d_scene_trace_ray(scn, org, dir, range, &hit), RES_BAD_OP);
/* Update the shape with the CBox tall block mesh */
ntris = sizeof(cbox_block_ids)/sizeof(unsigned[3]);
@@ -169,7 +173,8 @@ main(int argc, char** argv)
desc.indices = cbox_block_ids;
CHECK(s3d_mesh_setup_indexed_vertices
(shape, ntris, cbox_get_ids, nverts, attribs, &desc), RES_OK);
- CHECK(s3d_scene_build(scn), RES_OK);
+ CHECK(s3d_scene_begin_trace(scn), RES_OK);
+ CHECK(s3d_scene_end_trace(scn), RES_OK);
/* Update the shape vertices */
desc.vertices = cbox_tall_block;
@@ -202,7 +207,12 @@ main(int argc, char** argv)
CHECK(s3d_scene_instantiate(scn, &shape), RES_OK);
CHECK(s3d_scene_attach_shape(scn2, shape), RES_OK);
CHECK(s3d_instance_set_position(shape, org), RES_OK);
- CHECK(s3d_scene_build(scn2), RES_OK);
+
+ CHECK(s3d_scene_begin_trace(scn), RES_OK);
+ CHECK(s3d_scene_begin_trace(scn2), RES_BAD_OP);
+ CHECK(s3d_scene_end_trace(scn), RES_OK);
+ CHECK(s3d_scene_begin_trace(scn2), RES_OK);
+ CHECK(s3d_scene_begin_trace(scn), RES_BAD_OP);
camera_init(&cam);
FOR_EACH(iy, 0, IMG_HEIGHT) {
@@ -253,6 +263,8 @@ main(int argc, char** argv)
}
}
}
+ CHECK(s3d_scene_end_trace(scn2), RES_OK);
+
if(argc > 1) {
CHECK(image_ppm_write(argv[1], IMG_WIDTH, IMG_HEIGHT, 3, img), RES_OK);
}