commit 25dc3f8917156a7ce84106c89d5b410cac3f5005
parent 1219563e93d695ab07744ae34880dba33bef8999
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Fri, 20 Mar 2015 10:15:48 +0100
Add the support of instantiated scenes into another scene
Diffstat:
4 files changed, 133 insertions(+), 62 deletions(-)
diff --git a/src/s3d_scene.c b/src/s3d_scene.c
@@ -36,6 +36,7 @@
#include "s3d_shape_c.h"
#include <rsys/float3.h>
+#include <rsys/float33.h>
#include <rsys/mem_allocator.h>
#include <rsys/mutex.h>
@@ -54,6 +55,90 @@ delete_rtc_geometry(struct s3d_scene* scn, struct s3d_shape* shape)
}
static res_T
+shape_mesh_setup(struct s3d_scene* scn, struct s3d_shape* shape)
+{
+ uint32_t* ids;
+ float* pos;
+ size_t ntris, nverts;
+ res_T res;
+ ASSERT(scn && shape && shape->type == SHAPE_MESH);
+
+ ids = darray_u32_data_get(&shape->data.mesh.indices);
+ pos = darray_float_data_get(&shape->data.mesh.attribs[S3D_POSITION]);
+ ntris = darray_u32_size_get(&shape->data.mesh.indices)/3;
+ nverts = darray_float_size_get(&shape->data.mesh.attribs[S3D_POSITION])/3;
+
+ mutex_rw_rlock(shape->lock); /* Prevent concurrent shape update */
+
+ /* The Embree geometry is no more valid */
+ if(shape->data.mesh.resize_mask
+ && shape->rtc_geom != RTC_INVALID_GEOMETRY_ID) {
+ rtcDeleteGeometry(scn->rtc_scn, shape->rtc_geom);
+ shape->rtc_geom = RTC_INVALID_GEOMETRY_ID;
+ shape->data.mesh.resize_mask = 0;
+ }
+ if(shape->rtc_geom != RTC_INVALID_GEOMETRY_ID) {
+ /* Update the Embree geometry if required */
+ if(shape->data.mesh.update_mask & MESH_INDEX_BUFFER)
+ rtcUpdateBuffer(scn->rtc_scn, shape->rtc_geom, RTC_INDEX_BUFFER);
+ if(shape->data.mesh.update_mask & MESH_VERTEX_BUFFER)
+ rtcUpdateBuffer(scn->rtc_scn, shape->rtc_geom, RTC_VERTEX_BUFFER);
+ shape->data.mesh.update_mask = 0;
+ } else {
+ /* Setup a new Embree geometry */
+ shape->rtc_geom = rtcNewTriangleMesh
+ (scn->rtc_scn, RTC_GEOMETRY_STATIC, ntris, nverts);
+ rtcSetBuffer(scn->rtc_scn, shape->rtc_geom, RTC_INDEX_BUFFER, ids, 0,
+ sizeof(uint32_t[3]));
+ rtcSetBuffer(scn->rtc_scn, shape->rtc_geom, RTC_VERTEX_BUFFER, pos, 0,
+ sizeof(float[3]));
+
+ /* Map the Embree geometry to its shape */
+ if(shape->rtc_geom >= darray_geom2shape_size_get(&scn->geom2shape)) {
+ res = darray_geom2shape_resize(&scn->geom2shape, shape->rtc_geom+1);
+ if(res != RES_OK) {
+ mutex_rw_unlock(shape->lock);
+ return res;
+ }
+ }
+ darray_geom2shape_data_get(&scn->geom2shape)[shape->rtc_geom] = shape;
+ }
+ mutex_rw_unlock(shape->lock);
+
+ return RES_OK;
+}
+
+static res_T
+scene_setup(struct s3d_scene* scn);
+
+static res_T
+shape_instance_setup(struct s3d_scene* scn, struct s3d_shape* shape)
+{
+ res_T res;
+ ASSERT(scn && shape && shape->type == SHAPE_INSTANCE);
+
+ /* Recursuvely update the scene */
+ res = scene_setup(shape->data.instance.scene);
+ if(res != RES_OK) return res;
+
+ mutex_rw_rlock(shape->lock);
+
+ if(shape->rtc_geom == RTC_INVALID_GEOMETRY_ID) {
+ shape->rtc_geom = rtcNewInstance
+ (scn->rtc_scn, shape->data.instance.scene->rtc_scn);
+ }
+ if(shape->data.instance.update_transform) {
+ rtcSetTransform
+ (scn->rtc_scn,
+ shape->rtc_geom,
+ RTC_MATRIX_COLUMN_MAJOR,
+ shape->data.instance.transform);
+ }
+
+ mutex_rw_unlock(shape->lock);
+}
+
+res_T
scene_setup(struct s3d_scene* scn)
{
struct list_node* node;
@@ -63,51 +148,17 @@ scene_setup(struct s3d_scene* scn)
LIST_FOR_EACH(node, &scn->shapes) {
struct s3d_shape* shape = CONTAINER_OF
(node, struct s3d_shape, scene_attachment);
- uint32_t* ids = darray_u32_data_get(&shape->data.mesh.indices);
- float* pos = darray_float_data_get(&shape->data.mesh.attribs[S3D_POSITION]);
- const size_t ntris = darray_u32_size_get(&shape->data.mesh.indices)/3;
- const size_t nverts = darray_float_size_get
- (&shape->data.mesh.attribs[S3D_POSITION])/3;
-
- mutex_rw_rlock(shape->lock); /* Prevent concurrent shape update */
-
- if(shape->type != SHAPE_MESH)
- FATAL("Unsupported shape type\n");
-
- /* The Embree geometry is no more valid */
- if(shape->data.mesh.resize_mask
- && shape->rtc_geom != RTC_INVALID_GEOMETRY_ID) {
- rtcDeleteGeometry(scn->rtc_scn, shape->rtc_geom);
- shape->rtc_geom = RTC_INVALID_GEOMETRY_ID;
- shape->data.mesh.resize_mask = 0;
+ switch(shape->type) {
+ case SHAPE_INSTANCE:
+ FATAL("Unsupported shape type\n");
+ break;
+ case SHAPE_MESH:
+ res = shape_mesh_setup(scn, shape);
+ break;
+ default: FATAL("Unreachable code\n"); break;
}
-
- if(shape->rtc_geom != RTC_INVALID_GEOMETRY_ID) {
- /* Update the Embree geometry if required */
- if(shape->data.mesh.update_mask & MESH_INDEX_BUFFER)
- rtcUpdateBuffer(scn->rtc_scn, shape->rtc_geom, RTC_INDEX_BUFFER);
- if(shape->data.mesh.update_mask & MESH_VERTEX_BUFFER)
- rtcUpdateBuffer(scn->rtc_scn, shape->rtc_geom, RTC_VERTEX_BUFFER);
- shape->data.mesh.update_mask = 0;
- } else {
- /* Setup a new Embree geometry */
- shape->rtc_geom = rtcNewTriangleMesh
- (scn->rtc_scn, RTC_GEOMETRY_STATIC, ntris, nverts);
- rtcSetBuffer(scn->rtc_scn, shape->rtc_geom, RTC_INDEX_BUFFER, ids, 0,
- sizeof(uint32_t[3]));
- rtcSetBuffer(scn->rtc_scn, shape->rtc_geom, RTC_VERTEX_BUFFER, pos, 0,
- sizeof(float[3]));
-
- if(shape->rtc_geom >= darray_geom2shape_size_get(&scn->geom2shape)) {
- res = darray_geom2shape_resize(&scn->geom2shape, shape->rtc_geom+1);
- if(res != RES_OK) {
- mutex_rw_unlock(shape->lock);
- goto error;
- }
- }
- darray_geom2shape_data_get(&scn->geom2shape)[shape->rtc_geom] = shape;
- }
- mutex_rw_unlock(shape->lock);
+ if(res != RES_OK)
+ goto error;
}
exit:
@@ -241,7 +292,10 @@ s3d_scene_instantiate(struct s3d_scene* scn, struct s3d_shape** out_shape)
shape->type = SHAPE_INSTANCE;
S3D(scene_ref_get(scn));
- shape->data.scene = scn;
+ f33_set_identity(shape->data.instance.transform); /* Rotation */
+ f3_splat(shape->data.instance.transform + 9, 0); /* Translation */
+ shape->data.instance.scene = scn;
+ shape->data.instance.update_transform = 0;
*out_shape = shape;
return RES_OK;
}
@@ -309,7 +363,7 @@ s3d_scene_build(struct s3d_scene* scn)
/* Prevent concurrent ray tracing */
mutex_rw_wlock(scn->lock_rtc);
- if(scn->is_outdated) {
+ if(ATOMIC_GET(&scn->is_outdated)) {
res = scene_setup(scn);
rtcCommit(scn->rtc_scn);
scn->is_outdated = res != RES_OK;
diff --git a/src/s3d_scene_c.h b/src/s3d_scene_c.h
@@ -47,7 +47,7 @@ struct s3d_scene {
struct list_node shapes; /* List of attached shapes */
struct darray_geom2shape geom2shape;
RTCScene rtc_scn;
- char is_outdated; /* Flag defining if the scene description was updated */
+ int is_outdated; /* Flag defining if the scene description was updated */
struct mutex* lock;
struct mutex_rw* lock_rtc;
diff --git a/src/s3d_shape.c b/src/s3d_shape.c
@@ -238,7 +238,7 @@ shape_release_data(struct s3d_shape* shape)
switch(shape->type) {
case SHAPE_MESH: mesh_release(&shape->data.mesh); break;
case SHAPE_NONE: /* Do nothing */ break;
- case SHAPE_INSTANCE: S3D(scene_ref_put(shape->data.scene)); break;
+ case SHAPE_INSTANCE: S3D(scene_ref_put(shape->data.instance.scene)); break;
default: FATAL("Unreachable code\n"); break;
}
shape->type = SHAPE_NONE;
@@ -295,7 +295,6 @@ shape_create(struct s3d_device* dev, struct s3d_shape** out_shape)
S3D(device_ref_get(dev));
shape->dev = dev;
ref_init(&shape->ref);
- f33_set_identity(shape->transform);
shape->lock = mutex_rw_create();
if(!shape->lock) {
res = RES_MEM_ERR;
@@ -386,9 +385,15 @@ s3d_shape_instance_set_position
if(!shape || shape->type != SHAPE_INSTANCE || !position)
return RES_BAD_ARG;
mutex_rw_wlock(shape->lock);
- shape->transform[9] = -f3_dot(f33_row(axis, shape->transform, 0), position);
- shape->transform[10] = -f3_dot(f33_row(axis, shape->transform, 1), position);
- shape->transform[11] = -f3_dot(f33_row(axis, shape->transform, 2), position);
+ shape->data.instance.transform[9] =
+ -f3_dot(f33_row(axis, shape->data.instance.transform, 0), position);
+ shape->data.instance.transform[10] =
+ -f3_dot(f33_row(axis, shape->data.instance.transform, 1), position);
+ shape->data.instance.transform[11] =
+ -f3_dot(f33_row(axis, shape->data.instance.transform, 2), position);
+ shape->data.instance.update_transform = 1;
+ if(shape->scn)
+ ATOMIC_SET(&shape->scn->is_outdated, 1);
mutex_rw_unlock(shape->lock);
return RES_OK;
}
@@ -404,12 +409,22 @@ s3d_shape_instance_translate
if(space == S3D_LOCAL_TRANSFORM) {
float vec[3];
mutex_rw_wlock(shape->lock);
- f33_mulf3(vec, shape->transform, translation); /* Trans in local space */
- f3_add(shape->transform + 9, shape->transform + 9, vec);
+ f33_mulf3(vec, shape->data.instance.transform, translation);
+ f3_add
+ (shape->data.instance.transform + 9,
+ shape->data.instance.transform + 9,
+ vec);
+ shape->data.instance.update_transform = 1;
+ if(shape->scn) ATOMIC_SET(&shape->scn->is_outdated, 1);
mutex_rw_unlock(shape->lock);
} else if(space == S3D_WORLD_TRANSFORM) {
mutex_rw_wlock(shape->lock);
- f3_add(shape->transform + 9, shape->transform + 9, translation);
+ f3_add
+ (shape->data.instance.transform + 9,
+ shape->data.instance.transform + 9,
+ translation);
+ shape->data.instance.update_transform = 1;
+ if(shape->scn) ATOMIC_SET(&shape->scn->is_outdated, 1);
mutex_rw_unlock(shape->lock);
} else {
return RES_BAD_ARG;
@@ -489,11 +504,8 @@ s3d_shape_mesh_setup_indexed_vertices
}
}
- if(shape->scn) {/* Notify the shape update */
- mutex_lock(shape->scn->lock);
- shape->scn->is_outdated = 1;
- mutex_unlock(shape->scn->lock);
- }
+ if(shape->scn) /* Notify the shape update */
+ ATOMIC_SET(&shape->scn->is_outdated, 1);
exit:
mutex_rw_unlock(shape->lock);
diff --git a/src/s3d_shape_c.h b/src/s3d_shape_c.h
@@ -65,16 +65,21 @@ struct mesh { /* Triangular mesh */
int resize_mask; /* Define which shape buffers were [re]allocateod */
};
+struct instance {
+ struct s3d_scene* scene;
+ float transform[12]; /* local to world 3x4 column major matrix */
+ int update_transform; /* Define if the transform matrix was updated or not */
+};
+
struct s3d_shape {
struct list_node scene_attachment;
enum shape_type type;
unsigned rtc_geom; /* Embree geometry id */
struct s3d_scene* scn; /* The scene on which the shape is attached */
struct mutex_rw* lock;
- float transform[12]; /* 3x4 column major transformation */
union {
- struct s3d_scene* scene;
+ struct instance instance;
struct mesh mesh;
} data;