commit f3314a3c58b2c85403b549e2dfc10631cb68d9af
parent 35b39239804a82cf3d209c75c339a35930666b88
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Wed, 25 Mar 2015 12:10:01 +0100
Major refactoring of the instance data management
Diffstat:
8 files changed, 274 insertions(+), 43 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -59,8 +59,20 @@ set(VERSION_MINOR 0)
set(VERSION_PATCH 0)
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
-set(S3D_FILES_SRC s3d_device.c s3d_mesh.c s3d_scene.c s3d_shape.c)
-set(S3D_FILES_INC s3d.h s3d_buffer.h s3d_device_c.h s3d_mesh.h s3d_shape_c.h)
+set(S3D_FILES_SRC
+ s3d_device.c
+ s3d_instance.c
+ s3d_mesh.c
+ s3d_scene.c
+ s3d_shape.c)
+set(S3D_FILES_INC
+ s3d.h
+ s3d_backend.h
+ s3d_buffer.h
+ s3d_device_c.h
+ s3d_instance.h
+ s3d_mesh.h
+ s3d_shape_c.h)
# Prepend each file in the `S3D_FILES_<SRC|INC>' list by `S3D_SOURCE_DIR'
rcmake_prepend_path(S3D_FILES_SRC ${S3D_SOURCE_DIR})
diff --git a/src/s3d_instance.c b/src/s3d_instance.c
@@ -0,0 +1,60 @@
+/* Copyright (C) |Meso|Star> 2015 (contact@meso-star.com)
+ *
+ * This software is a computer program whose purpose is to describe a
+ * virtual 3D environment that can be ray-traced and sampled both robustly
+ * and efficiently.
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms. */
+
+#include "s3d.h"
+#include "s3d_backend.h"
+#include "s3d_instance.h"
+
+#include <rsys/float33.h>
+
+void
+instance_init(struct instance* inst)
+{
+ ASSERT(inst);
+ inst->scene = NULL;
+ f33_set_identity(inst->transform); /* rotation */
+ f3_splat(inst->transform + 9, 0.f); /* Translation */
+ inst->update_transform = 0;
+ inst->rtc_geom = RTC_INVALID_GEOMETRY_ID;
+}
+
+void
+instance_clear(struct instance* inst)
+{
+ ASSERT(inst);
+ if(inst->scene) {
+ S3D(scene_ref_put(inst->scene));
+ inst->scene = NULL;
+ }
+}
+
+
diff --git a/src/s3d_instance.h b/src/s3d_instance.h
@@ -0,0 +1,52 @@
+/* Copyright (C) |Meso|Star> 2015 (contact@meso-star.com)
+ *
+ * This software is a computer program whose purpose is to describe a
+ * virtual 3D environment that can be ray-traced and sampled both robustly
+ * and efficiently.
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms. */
+
+#ifndef S3D_INSTANCE_H
+#define S3D_INSTANCE_H
+
+struct instance {
+ struct s3d_scene* scene;
+ float transform[12]; /* local to world 3x4 column major matrix */
+ char update_transform;
+ unsigned rtc_geom;
+};
+
+extern LOCAL_SYM void
+instance_init
+ (struct instance* inst);
+
+extern LOCAL_SYM void
+instance_clear
+ (struct instance* inst);
+
+#endif /* S3D_INSTANCE_H */
+
diff --git a/src/s3d_scene.c b/src/s3d_scene.c
@@ -79,6 +79,41 @@ scene_delete_mesh_rtc_geometry(struct s3d_scene* scn, struct mesh* mesh)
}
static res_T
+scene_create_instance_rtc_geometry(struct s3d_scene* scn, struct instance* inst)
+{
+ ASSERT(scn && inst && inst->scene && inst->rtc_geom == RTC_INVALID_GEOMETRY_ID);
+ /* The instance should not contain instances */
+ ASSERT(!darray_geom2inst_size_get(&inst->scene->geom2inst));
+
+ inst->rtc_geom = rtcNewInstance(scn->rtc_scn, inst->scene->rtc_scn);
+ if(inst->rtc_geom >= darray_geom2inst_size_get(&scn->geom2inst)) {
+ res_T res = darray_geom2inst_resize(&scn->geom2inst, inst->rtc_geom + 1);
+ if(res != RES_OK) {
+ rtcDeleteGeometry(scn->rtc_scn, inst->rtc_geom);
+ inst->rtc_geom = RTC_INVALID_GEOMETRY_ID;
+ return res;
+ } else {
+ /* Check that no other scene is mapped to this Embree geometry */
+ ASSERT(!darray_geom2inst_data_get(&scn->geom2inst)[inst->rtc_geom]);
+ }
+ darray_geom2inst_data_get(&scn->geom2inst)[inst->rtc_geom] = inst;
+ scn->is_rtc_scn_outdated = 1;
+ }
+ return RES_OK;
+}
+
+static void
+scene_delete_instance_rtc_geometry(struct s3d_scene* scn, struct instance* inst)
+{
+ ASSERT(scn && inst && inst->rtc_geom != RTC_INVALID_GEOMETRY_ID);
+ ASSERT(darray_geom2inst_size_get(&scn->geom2inst) > inst->rtc_geom);
+ darray_geom2inst_data_get(&scn->geom2inst)[inst->rtc_geom] = NULL;
+ rtcDeleteGeometry(scn->rtc_scn, inst->rtc_geom);
+ inst->rtc_geom = RTC_INVALID_GEOMETRY_ID;
+ scn->is_rtc_scn_outdated = 1;
+}
+
+static res_T
scene_setup_shape_mesh
(struct s3d_scene* scn,
struct s3d_shape* shape)
@@ -182,41 +217,76 @@ error:
goto exit;
}
-#if 0
static res_T
-shape_instance_setup(struct s3d_scene* scn, struct s3d_shape* shape)
+scene_setup_shape_instance(struct s3d_scene* scn, struct s3d_shape* shape)
{
- res_T res;
+ struct instance** pinst = NULL;
+ struct instance* inst = NULL;
+ res_T res = RES_OK;
ASSERT(scn && shape && shape->type == SHAPE_INSTANCE);
- /* Recursuvely update the scene */
- S3D(scene_build(shape->data.instance.scene));
- if(shape->rtc_geom == RTC_INVALID_GEOMETRY_ID) {
- shape->rtc_geom = rtcNewInstance
- (scn->rtc_scn, shape->data.instance.scene->rtc_scn);
+ /* Recursuvely update the scene */
+ res = s3d_scene_build(shape->data.instance.scene);
+ if(res != RES_OK) goto error;
- res = shape_register_rtc_geom(scn, shape);
- if(res != RES_OK) {
- return res;
+ pinst = htable_inst_find(&scn->instances, &shape);
+ /* Create the scene instance of the shape if necessary */
+ if(pinst) {
+ inst = *pinst;
+ } else {
+ inst = (struct instance*)
+ MEM_ALLOC(scn->dev->allocator, sizeof(struct instance));
+ if(!inst) {
+ res = RES_MEM_ERR;
+ goto error;
}
+ instance_init(inst);
+ res = htable_inst_set(&scn->instances, &shape, &inst);
+ if(res != RES_OK) goto error;
+
+ S3D(scene_ref_get(shape->data.instance.scene)); /* Not necessary but ... */
+ inst->scene = shape->data.instance.scene;
+ }
+ ASSERT(inst->scene == shape->data.instance.scene);
+ f33_set(inst->transform, shape->data.instance.transform);
+ f3_set(inst->transform + 9, shape->data.instance.transform + 9);
+
+ /* The instance cannot contain instances */
+ if(darray_geom2inst_size_get(&inst->scene->geom2inst)) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ /* Create the Embree instance */
+ if(inst->rtc_geom == RTC_INVALID_GEOMETRY_ID) {
+ res = scene_create_instance_rtc_geometry(scn, inst);
+ if(res != RES_OK) goto error;
}
+
+ /* Update the Embree instance transformation */
if(shape->data.instance.update_transform) {
rtcSetTransform
(scn->rtc_scn,
- shape->rtc_geom,
+ inst->rtc_geom,
RTC_MATRIX_COLUMN_MAJOR,
- shape->data.instance.transform);
- shape->data.instance.update_transform = 1;
+ inst->transform);
+ scn->is_rtc_scn_outdated = 1;
}
- return RES_OK;
+
+ shape->data.instance.update_transform = 0; /* Flush instance state */
+
+exit:
+ return res;
+error:
+ goto exit;
}
-#endif
-static INLINE void
-scene_remove_shape(struct s3d_scene* scn, struct s3d_shape* shape)
+static void
+scene_detach_shape_mesh(struct s3d_scene* scn, struct s3d_shape* shape)
{
struct mesh** pmesh;
ASSERT(scn && shape && !is_list_empty(&shape->scene_attachment));
+ ASSERT(shape->type == SHAPE_MESH);
pmesh = htable_mesh_find(&scn->meshes, &shape);
if(pmesh) { /* The shape mesh is registered into the scene */
@@ -232,6 +302,37 @@ scene_remove_shape(struct s3d_scene* scn, struct s3d_shape* shape)
}
static void
+scene_detach_shape_instance(struct s3d_scene* scn, struct s3d_shape* shape)
+{
+ struct instance** pinst;
+ ASSERT(scn && shape && !is_list_empty(&shape->scene_attachment));
+ ASSERT(shape->type == SHAPE_INSTANCE);
+
+ pinst = htable_inst_find(&scn->instances, &shape);
+ if(pinst) { /* The shape instance is registered into the scene */
+ struct instance* inst = *pinst;
+ if(inst->rtc_geom != RTC_INVALID_GEOMETRY_ID)
+ scene_delete_instance_rtc_geometry(scn, inst);
+ instance_clear(inst);
+ MEM_FREE(scn->dev->allocator, inst);
+ htable_inst_erase(&scn->instances, &shape);
+ }
+ list_del(&shape->scene_attachment);
+ S3D(shape_ref_put(shape));
+}
+
+static void
+scene_detach_shape(struct s3d_scene* scn, struct s3d_shape* shape)
+{
+ ASSERT(scn && shape);
+ switch(shape->type) {
+ case SHAPE_INSTANCE: scene_detach_shape_instance(scn, shape); break;
+ case SHAPE_MESH: scene_detach_shape_mesh(scn, shape); break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+}
+
+static void
scene_release(ref_T* ref)
{
struct s3d_scene* scn;
@@ -242,7 +343,9 @@ scene_release(ref_T* ref)
dev = scn->dev;
if(scn->rtc_scn) rtcDeleteScene(scn->rtc_scn);
htable_mesh_release(&scn->meshes);
+ htable_inst_release(&scn->instances);
darray_geom2mesh_release(&scn->geom2mesh);
+ darray_geom2inst_release(&scn->geom2inst);
MEM_FREE(dev->allocator, scn);
S3D(device_ref_put(dev));
}
@@ -268,7 +371,9 @@ s3d_scene_create(struct s3d_device* dev, struct s3d_scene** out_scn)
}
list_init(&scn->shapes);
htable_mesh_init(dev->allocator, &scn->meshes);
+ htable_inst_init(dev->allocator, &scn->instances);
darray_geom2mesh_init(dev->allocator, &scn->geom2mesh);
+ darray_geom2inst_init(dev->allocator, &scn->geom2inst);
ref_init(&scn->ref);
S3D(device_ref_get(dev));
scn->dev = dev;
@@ -323,11 +428,9 @@ s3d_scene_instantiate(struct s3d_scene* scn, struct s3d_shape** out_shape)
return res;
shape->type = SHAPE_INSTANCE;
+ instance_init(&shape->data.instance);
S3D(scene_ref_get(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;
}
@@ -363,7 +466,7 @@ s3d_scene_detach_shape(struct s3d_scene* scn, struct s3d_shape* shape)
ASSERT(is_found);
}
#endif
- scene_remove_shape(scn, shape);
+ scene_detach_shape(scn, shape);
return RES_OK;
}
@@ -374,11 +477,10 @@ s3d_scene_clear(struct s3d_scene* scn)
if(!scn)
return RES_BAD_ARG;
- /* Prevent the scene_<attach_shape|remove_shape|build> operations */
LIST_FOR_EACH_SAFE(node, tmp, &scn->shapes) {
struct s3d_shape* shape = CONTAINER_OF
(node, struct s3d_shape, scene_attachment);
- scene_remove_shape(scn, shape);
+ scene_detach_shape(scn, shape);
}
return RES_OK;
}
@@ -398,7 +500,7 @@ s3d_scene_build(struct s3d_scene* scn)
struct s3d_shape* shape = CONTAINER_OF
(node, struct s3d_shape, scene_attachment);
switch(shape->type) {
- case SHAPE_INSTANCE: /*res = shape_instance_setup(scn, shape);*/ break;
+ 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;
}
@@ -461,8 +563,8 @@ s3d_scene_trace_ray
hit->prim.igeom = RTC_INVALID_GEOMETRY_ID;
} else { /* The hit shape is instantiated */
/* Retrieve the hit instance */
- ASSERT((unsigned)ray.instID < darray_geom2mesh_size_get(&scn->geom2mesh));
- /*hit->prim.ptr = TODO */
+ ASSERT((unsigned)ray.instID < darray_geom2inst_size_get(&scn->geom2inst));
+ hit->prim.ptr = darray_geom2inst_data_get(&scn->geom2inst);
hit->prim.igeom = ray.geomID;
hit->prim.iprim = ray.primID;
}
diff --git a/src/s3d_scene_c.h b/src/s3d_scene_c.h
@@ -44,15 +44,26 @@
#define DARRAY_DATA struct mesh*
#include <rsys/dynamic_array.h>
+#define DARRAY_NAME geom2inst
+#define DARRAY_DATA struct instance*
+#include <rsys/dynamic_array.h>
+
#define HTABLE_NAME mesh
#define HTABLE_DATA struct mesh*
#define HTABLE_KEY struct s3d_shape*
#include <rsys/hash_table.h>
+#define HTABLE_NAME inst
+#define HTABLE_DATA struct instance*
+#define HTABLE_KEY struct s3d_shape*
+#include <rsys/hash_table.h>
+
struct s3d_scene {
struct list_node shapes; /* List of attached shapes */
struct htable_mesh meshes; /* List of meshes associated to a shape */
- struct darray_geom2mesh geom2mesh;
+ struct htable_inst instances; /* List of instances associated to a shape */
+ struct darray_geom2mesh geom2mesh; /* Map an Embree geometry to a mesh */
+ struct darray_geom2inst geom2inst; /* Map an Embree geometry to an instance */
RTCScene rtc_scn;
char is_rtc_scn_outdated;
diff --git a/src/s3d_shape.c b/src/s3d_shape.c
@@ -48,7 +48,7 @@ shape_release_data(struct s3d_shape* shape)
switch(shape->type) {
case SHAPE_MESH: mesh_clear(&shape->data.mesh); break;
case SHAPE_NONE: /* Do nothing */ break;
- case SHAPE_INSTANCE: S3D(scene_ref_put(shape->data.instance.scene)); break;
+ case SHAPE_INSTANCE: instance_clear(&shape->data.instance); break;
default: FATAL("Unreachable code\n"); break;
}
shape->type = SHAPE_NONE;
diff --git a/src/s3d_shape_c.h b/src/s3d_shape_c.h
@@ -34,6 +34,7 @@
#define S3D_SHAPE_C_H
#include "s3d_mesh.h"
+#include "s3d_instance.h"
#include <rsys/dynamic_array_u32.h>
#include <rsys/dynamic_array_float.h>
@@ -50,12 +51,6 @@ enum shape_type {
SHAPE_NONE = SHAPE_TYPES_COUNT__
};
-struct instance {
- struct s3d_scene* scene;
- float transform[12]; /* local to world 3x4 column major matrix */
- char update_transform;
-};
-
struct s3d_shape {
struct list_node scene_attachment;
enum shape_type type;
diff --git a/src/test_s3d_trace_ray.c b/src/test_s3d_trace_ray.c
@@ -48,8 +48,8 @@ struct camera {
static void
camera_init(struct camera* cam)
{
- const float pos[3] = { 178.f, -1000.f, 273.f };
- const float tgt[3] = { 178.f, 0.f, 273.f };
+ const float pos[3] = { 0.f, -1500.f, 0.f };
+ const float tgt[3] = { 0.f, 0.f, 0.f };
const float up[3] = { 0.f, 0.f, 1.f };
const float proj_ratio = (float)IMG_WIDTH/(float)IMG_HEIGHT;
const float fov_x = (float)PI * 0.25f;
@@ -157,7 +157,6 @@ main(int argc, char** argv)
CHECK(s3d_scene_trace_ray(scn, org, dir, range, &hit), RES_BAD_ARG);
- /*
CHECK(s3d_scene_create(dev, &scn2), RES_OK);
f3(org, -555.f, 0.f, -551.f);
@@ -184,7 +183,7 @@ main(int argc, char** argv)
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_build(scn2), RES_OK);
camera_init(&cam);
FOR_EACH(iy, 0, IMG_HEIGHT) {
@@ -196,7 +195,7 @@ main(int argc, char** argv)
pixel[0] = (float)ix/(float)IMG_WIDTH;
camera_ray(&cam, pixel, org, dir);
- CHECK(s3d_scene_trace_ray(scn, org, dir, range, &hit), RES_OK);
+ CHECK(s3d_scene_trace_ray(scn2, org, dir, range, &hit), RES_OK);
if(!img)
continue;
@@ -225,7 +224,7 @@ main(int argc, char** argv)
CHECK(s3d_device_ref_put(dev), RES_OK);
CHECK(s3d_shape_ref_put(shape), RES_OK);
CHECK(s3d_scene_ref_put(scn), RES_OK);
- /*CHECK(s3d_scene_ref_put(scn2), RES_OK);*/
+ CHECK(s3d_scene_ref_put(scn2), RES_OK);
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);