star-3d

Surface structuring for efficient 3D geometric queries
git clone git://git.meso-star.fr/star-3d.git
Log | Files | Refs | README | LICENSE

commit 1014b516425347daf33c0e11aecc262336e076e6
parent 19795ca5e55ceeb47974b199c54e851943844713
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed,  9 Sep 2015 10:27:10 +0200

First functionnal version of s3d_<shape|scene> refactoring

The sampler API is not implemented yet

Diffstat:
Mcmake/CMakeLists.txt | 5+++--
Msrc/s3d_geometry.c | 15++++++++++++---
Msrc/s3d_geometry.h | 7++++---
Msrc/s3d_instance.c | 27++++++++++-----------------
Msrc/s3d_instance.h | 9++-------
Msrc/s3d_mesh.c | 12+++---------
Msrc/s3d_primitive.c | 37++++++++++++++++++-------------------
Msrc/s3d_sampler.c | 3++-
Msrc/s3d_scene.c | 273+++++++++++++++++++++++++++++--------------------------------------------------
Msrc/s3d_scene_c.h | 21++++++++++-----------
Msrc/s3d_shape.c | 13+++++++++----
11 files changed, 173 insertions(+), 249 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -63,6 +63,7 @@ set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) set(S3D_FILES_SRC s3d_device.c + s3d_geometry.c s3d_instance.c s3d_mesh.c s3d_primitive.c @@ -75,8 +76,8 @@ set(S3D_FILES_INC s3d_backend.h s3d_buffer.h s3d_device_c.h - s3d_instance.h s3d_geometry.h + s3d_instance.h s3d_mesh.h s3d_shape_c.h) set(S3D_FILES_DOC COPYING.fr COPYING.en README.md) @@ -128,7 +129,7 @@ if(NOT NO_TEST) endfunction(new_test) new_test(test_s3d_device) - new_test(test_s3d_sampler) + # new_test(test_s3d_sampler) new_test(test_s3d_scene) new_test(test_s3d_shape) new_test(test_s3d_trace_ray) diff --git a/src/s3d_geometry.c b/src/s3d_geometry.c @@ -30,7 +30,12 @@ * 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_device_c.h" #include "s3d_geometry.h" +#include "s3d_instance.h" +#include "s3d_mesh.h" + +#include <rsys/mem_allocator.h> /******************************************************************************* * Helper functions @@ -65,14 +70,18 @@ geometry_create struct geometry** out_geom) { struct geometry* geom = NULL; + res_T res = RES_OK; ASSERT(dev && out_geom); - geom = MEM_CALLOC(dev->allocator, 1, sizeof(struct geometry)); + geom = (struct geometry*)MEM_CALLOC + (dev->allocator, 1, sizeof(struct geometry)); if(!geom) { res = RES_MEM_ERR; goto error; } - + ref_init(&geom->ref); + S3D(device_ref_get(dev)); + geom->dev = dev; geom->name = S3D_INVALID_ID; geom->irtc = RTC_INVALID_GEOMETRY_ID; geom->flip_surface = 0; @@ -102,7 +111,7 @@ void geometry_ref_put(struct geometry* geom) { ASSERT(geom); - ref_put(&geom->ref, release); + ref_put(&geom->ref, geometry_release); } diff --git a/src/s3d_geometry.h b/src/s3d_geometry.h @@ -34,12 +34,13 @@ #define S3D_GEOMETRY_H #include "s3d_backend.h" +#include <rsys/ref_count.h> enum geometry_type { GEOM_MESH, GEOM_INSTANCE, GEOM_TYPES_COUNT__, - GEOM_NONE = SHAPE_TYPES_COUNT__ + GEOM_NONE = GEOM_TYPES_COUNT__ }; /* Backend geometry */ @@ -64,11 +65,11 @@ geometry_create (struct s3d_device* dev, struct geometry** geom); -extern LOCAL_SYM res_T +extern LOCAL_SYM void geometry_ref_get (struct geometry* geometry); -extern LOCAL_SYM res_T +extern LOCAL_SYM void geometry_ref_put (struct geometry* geometry); diff --git a/src/s3d_instance.c b/src/s3d_instance.c @@ -50,7 +50,6 @@ instance_release(ref_T* ref) ASSERT(ref); inst = CONTAINER_OF(ref, struct instance, ref); scn = inst->scene; - ASSERT(inst->geom.irtc == RTC_INVALID_GEOMETRY_ID); MEM_RM(scn->dev->allocator, inst); S3D(scene_ref_put(scn)); } @@ -76,7 +75,6 @@ instance_create f33_set_identity(inst->transform); /* rotation */ f3_splat(inst->transform + 9, 0.f); /* Translation */ inst->update_transform = 0; - geometry_init(&inst->geom); ref_init(&inst->ref); S3D(scene_ref_get(scn)); inst->scene = scn; @@ -114,10 +112,10 @@ instance_get_ntris(struct instance* inst) struct s3d_shape* shape = CONTAINER_OF (node, struct s3d_shape, scene_attachment); switch(shape->type) { - case SHAPE_INSTANCE: + case GEOM_INSTANCE: ntris += instance_get_ntris(shape->data.instance); break; - case SHAPE_MESH: + case GEOM_MESH: ntris += mesh_get_ntris(shape->data.mesh); break; default: FATAL("Unreachable code\n"); break; @@ -133,18 +131,15 @@ instance_compute_area(struct instance* inst) float area = 0.f; ASSERT(inst); - if(!inst->geom.is_enabled) - return 0.f; - /* 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); switch(shape->type) { - case SHAPE_INSTANCE: + case GEOM_INSTANCE: area += instance_compute_area(shape->data.instance); break; - case SHAPE_MESH: + case GEOM_MESH: area += mesh_compute_area(shape->data.mesh); break; default: FATAL("Unreachable code\n"); break; @@ -154,25 +149,23 @@ instance_compute_area(struct instance* inst) } float -instance_compute_volume(struct instance* inst) +instance_compute_volume(struct instance* inst, const char flip_surface) { struct list_node* node; float volume = 0.f; ASSERT(inst); - - if(!inst->geom.is_enabled) - return 0.f; /* 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); + const char flip = flip_surface ^ shape->flip_surface; switch(shape->type) { - case SHAPE_INSTANCE: - volume += instance_compute_volume(shape->data.instance); + case GEOM_INSTANCE: + volume += instance_compute_volume(shape->data.instance, flip); break; - case SHAPE_MESH: - volume += mesh_compute_volume(shape->data.mesh, inst->flip_surface); + case GEOM_MESH: + volume += mesh_compute_volume(shape->data.mesh, flip); break; default: FATAL("Unreachable code\n"); break; } diff --git a/src/s3d_instance.h b/src/s3d_instance.h @@ -39,12 +39,6 @@ struct instance { float transform[12]; /* local to world 3x4 column major matrix */ char update_transform; - char flip_surface; - - struct geometry geom; - - unsigned id; /* Unique identifier of an instance */ - struct s3d_scene* scene; ref_T ref; }; @@ -72,7 +66,8 @@ instance_compute_area extern LOCAL_SYM float instance_compute_volume - (struct instance* inst); + (struct instance* inst, + const char flip_surface); /* Flip the instance surfaces or not */ #endif /* S3D_INSTANCE_H */ diff --git a/src/s3d_mesh.c b/src/s3d_mesh.c @@ -217,7 +217,6 @@ mesh_release(ref_T* ref) mesh = CONTAINER_OF(ref, struct mesh, ref); mesh_clear(mesh); dev = mesh->dev; - ASSERT(mesh->geom.irtc == RTC_INVALID_GEOMETRY_ID); MEM_RM(dev->allocator, mesh); S3D(device_ref_put(dev)); } @@ -237,7 +236,6 @@ mesh_create(struct s3d_device* dev, struct mesh** out_mesh) res = RES_MEM_ERR; goto error; } - geometry_init(&mesh->geom); ref_init(&mesh->ref); S3D(device_ref_get(dev)); mesh->dev = dev; @@ -342,8 +340,7 @@ mesh_compute_area(struct mesh* mesh) ASSERT(mesh); ntris = mesh_get_ntris(mesh); - if(!ntris || !mesh->geom.is_enabled) - return 0.f; + if(!ntris) return 0.f; ids = mesh_get_ids(mesh); pos = mesh_get_pos(mesh); @@ -368,16 +365,13 @@ mesh_compute_volume(struct mesh* mesh, const char flip_surface) const float* pos; size_t itri, ntris; double volume = 0.0; - char flip; ASSERT(mesh); ntris = mesh_get_ntris(mesh); - if(!ntris || !mesh->geom.is_enabled) - return 0.f; + if(!ntris) return 0.f; ids = mesh_get_ids(mesh); pos = mesh_get_pos(mesh); - flip = mesh->flip_surface ^ flip_surface; /* Build a tetrahedron whose face is the mesh triangle and its appex is the * origin. Then compute the volume of the tetrahedron and add or sub it from @@ -392,7 +386,7 @@ mesh_compute_volume(struct mesh* mesh, const char flip_surface) /* Front face is CW by default */ f3_sub(E0, v2, v0); f3_sub(E1, v1, v0); - if(flip) { + if(flip_surface) { f3_cross(N, E1, E0); } else { f3_cross(N, E0, E1); diff --git a/src/s3d_primitive.c b/src/s3d_primitive.c @@ -48,7 +48,7 @@ s3d_primitive_get_attrib struct s3d_attrib* attrib) { const uint32_t* ids; - struct mesh* mesh = NULL; + struct geometry* geom_mesh = NULL; const float* transform = NULL; char flip_surface = 0; float w; @@ -63,33 +63,32 @@ s3d_primitive_get_attrib return RES_BAD_ARG; if(prim->inst__ == NULL) { - mesh = (struct mesh*)prim->mesh__; - flip_surface = mesh->flip_surface; + geom_mesh = (struct geometry*)prim->mesh__; + flip_surface = geom_mesh->flip_surface; } else { - const struct instance* inst = (const struct instance*)prim->inst__; - ASSERT(prim->inst_id == inst->id); - mesh = (struct mesh*)prim->mesh__; - transform = inst->transform; - if(!mesh) { - res = RES_BAD_ARG; - goto error; - } - flip_surface = inst->flip_surface ^ mesh->flip_surface; + const struct geometry* geom_inst = (const struct geometry*)prim->inst__; + ASSERT(geom_inst->type == GEOM_INSTANCE); + ASSERT(prim->inst_id == geom_inst->name); + geom_mesh = (struct geometry*)prim->mesh__; + transform = geom_inst->data.instance->transform; + ASSERT(geom_mesh); + flip_surface = geom_inst->flip_surface ^ geom_mesh->flip_surface; } - ASSERT(prim->geom_id == mesh->id); + ASSERT(prim->geom_id == geom_mesh->name); + ASSERT(geom_mesh->type == GEOM_MESH); /* The mesh haven't the required mesh attrib */ - if(usage != S3D_GEOMETRY_NORMAL && !mesh->attribs[usage]) { + if(usage != S3D_GEOMETRY_NORMAL && !geom_mesh->data.mesh->attribs[usage]) { res = RES_BAD_ARG; goto error; } /* Out of bound primitive index */ - if(prim->prim_id >= mesh_get_ntris(mesh)) { + if(prim->prim_id >= mesh_get_ntris(geom_mesh->data.mesh)) { res = RES_BAD_ARG; goto error; } - ids = mesh_get_ids(mesh) + prim->prim_id * 3/*#ids per triangle*/; + ids = mesh_get_ids(geom_mesh->data.mesh) + prim->prim_id * 3/*#triangle ids*/; attrib->usage = usage; if(usage == S3D_POSITION || usage == S3D_GEOMETRY_NORMAL) { @@ -97,7 +96,7 @@ s3d_primitive_get_attrib const float* pos; attrib->type = S3D_FLOAT3; /* Fetch data */ - pos = mesh_get_pos(mesh); + pos = mesh_get_pos(geom_mesh->data.mesh); v0 = pos + ids[0] * 3; v1 = pos + ids[1] * 3; v2 = pos + ids[2] * 3; @@ -131,10 +130,10 @@ s3d_primitive_get_attrib const float* attr; const float* v0, *v1, *v2; unsigned i, dim; - attrib->type = mesh->attribs_type[usage]; + attrib->type = geom_mesh->data.mesh->attribs_type[usage]; /* Fetch attrib data */ dim = s3d_type_get_dimension(attrib->type); - attr = mesh_get_attr(mesh, usage); + attr = mesh_get_attr(geom_mesh->data.mesh, usage); v0 = attr + ids[0] * dim; v1 = attr + ids[1] * dim; v2 = attr + ids[2] * dim; diff --git a/src/s3d_sampler.c b/src/s3d_sampler.c @@ -42,6 +42,7 @@ #include <algorithm> /* The sampler is used to compute uniform random variates of a shape */ +#if 0 struct s3d_sampler { struct s3d_shape* shape; /* The shape to sample */ @@ -578,4 +579,4 @@ exit: error: goto exit; } - +#endif diff --git a/src/s3d_scene.c b/src/s3d_scene.c @@ -51,18 +51,18 @@ scene_build static INLINE void scene_geometry_flush_enable_state (struct s3d_scene* scn, - struct geometry* cache, /* Cached value */ - const struct geometry* curr) /* New value */ + struct geometry* geom, /* Cached geometry */ + const struct s3d_shape* shape) /* New shape */ { - ASSERT(scn && cache && curr); - if(cache->is_enabled == curr->is_enabled) + ASSERT(scn && geom && shape); + if(geom->is_enabled == shape->is_enabled) return; - cache->is_enabled = curr->is_enabled; - if(curr->is_enabled) { - rtcEnable(scn->rtc_scn, cache->irtc); + geom->is_enabled = shape->is_enabled; + if(geom->is_enabled) { + rtcEnable(scn->rtc_scn, geom->irtc); } else { - rtcDisable(scn->rtc_scn, cache->irtc); + rtcDisable(scn->rtc_scn, geom->irtc); } scn->is_rtc_scn_outdated = 1; } @@ -80,8 +80,8 @@ scene_build_register_mesh(struct s3d_scene* scn, struct geometry* geom) scn->is_rtc_scn_outdated = 1; } - if(geom->irtc >= darray_mesh_size_get(&scn->meshes)) { - res_T res = darray_mesh_resize(&scn->meshes, geom->irtc + 1); + if(geom->irtc >= darray_geom_size_get(&scn->embree2geoms)) { + res_T res = darray_geom_resize(&scn->embree2geoms, geom->irtc + 1); if(res != RES_OK) { rtcDeleteGeometry(scn->rtc_scn, geom->irtc); geom->irtc = RTC_INVALID_GEOMETRY_ID; @@ -89,61 +89,57 @@ scene_build_register_mesh(struct s3d_scene* scn, struct geometry* geom) } } geometry_ref_get(geom); - darray_mesh_data_get(&scn->meshes)[geom->irtc] = geom; + darray_geom_data_get(&scn->embree2geoms)[geom->irtc] = geom; return RES_OK; } static res_T scene_build_register_instance(struct s3d_scene* scn, struct geometry* geom) { - ASSERT(scn && geom && inst->scene); - /* The instance should not contain instances */ - ASSERT(!darray_inst_size_get(&inst->scene->instances)); + ASSERT(scn && geom && geom->data.instance->scene && geom->type==GEOM_INSTANCE); + /* The instance should not contain instances, i.e. one instancing level is + * supported */ + ASSERT(geom->data.instance->scene->instances_count == 0); if(geom->irtc == RTC_INVALID_GEOMETRY_ID) { geom->irtc = rtcNewInstance(scn->rtc_scn, geom->data.instance->scene->rtc_scn); - if(geom.irtc == RTC_INVALID_GEOMETRY_ID) + if(geom->irtc == RTC_INVALID_GEOMETRY_ID) return RES_UNKNOWN_ERR; scn->is_rtc_scn_outdated = 1; } - if(geom->irtc >= darray_inst_size_get(&scn->instances)) { - res_T res = darray_inst_resize(&scn->instances, geom->irtc + 1); + if(geom->irtc >= darray_geom_size_get(&scn->embree2geoms)) { + res_T res = darray_geom_resize(&scn->embree2geoms, geom->irtc + 1); if(res != RES_OK) { rtcDeleteGeometry(scn->rtc_scn, geom->irtc); geom->irtc = RTC_INVALID_GEOMETRY_ID; return res; } } - instance_ref_get(inst); - darray_inst_data_get(&scn->instances)[inst->geom.irtc] = inst; + geometry_ref_get(geom); + darray_geom_data_get(&scn->embree2geoms)[geom->irtc] = geom; return RES_OK; } static void scene_build_clear(struct s3d_scene* scn) { - struct mesh** meshes; - struct instance** instances; - size_t nmeshes; - size_t ninstances; + struct geometry** geoms; + size_t ngeoms; size_t i; ASSERT(scn); - nmeshes = darray_mesh_size_get(&scn->meshes); - meshes = darray_mesh_data_get(&scn->meshes); - FOR_EACH(i, 0, nmeshes) if(meshes[i]) mesh_ref_put(meshes[i]); - darray_mesh_clear(&scn->meshes); - - ninstances = darray_inst_size_get(&scn->instances); - instances = darray_inst_data_get(&scn->instances); - FOR_EACH(i, 0, ninstances) { - if(instances[i]) { - scene_build_clear(instances[i]->scene); - instance_ref_put(instances[i]); - } + ngeoms = darray_geom_size_get(&scn->embree2geoms); + geoms = darray_geom_data_get(&scn->embree2geoms); + FOR_EACH(i, 0, ngeoms) { + if(!geoms[i]) continue; + + if(geoms[i]->type == GEOM_INSTANCE) + scene_build_clear(geoms[i]->data.instance->scene); + + geometry_ref_put(geoms[i]); } - darray_inst_clear(&scn->instances); + darray_geom_clear(&scn->embree2geoms); scn->build_type = BUILD_NONE; } @@ -158,7 +154,7 @@ scene_setup_shape_mesh char upd_pos, upd_ids; res_T res = RES_OK; - ASSERT(shape && shape->type == SHAPE_MESH); + ASSERT(shape && shape->type == GEOM_MESH); /* Retrieve the cached geometry */ pgeom = htable_geom_find(&scn->cached_geoms, &shape); @@ -172,7 +168,7 @@ scene_setup_shape_mesh geom->type = GEOM_MESH; res = htable_geom_set(&scn->cached_geoms, &shape, &geom); if(res != RES_OK) goto error; - geom->name = shape->name.index; + geom->name = shape->id.index; } /* Discard the geometry that is not geometrically valid */ @@ -182,7 +178,7 @@ scene_setup_shape_mesh geom->irtc = RTC_INVALID_GEOMETRY_ID; scn->is_rtc_scn_outdated = 1; } - mesh_clear(geom->mesh); + mesh_clear(geom->data.mesh); goto exit; } @@ -221,14 +217,14 @@ scene_setup_shape_mesh } /* The shape mesh was resize => the Embree geometry is no more valid */ - if(shape->data.mesh->resize_mask && mesh->geom.irtc != RTC_INVALID_GEOMETRY_ID) { - rtcDeleteGeometry(scn->rtc_scn, geom->data.mesh->geom.irtc); - geom->data.mesh->geom.irtc = RTC_INVALID_GEOMETRY_ID; + if(shape->data.mesh->resize_mask && geom->irtc != RTC_INVALID_GEOMETRY_ID) { + rtcDeleteGeometry(scn->rtc_scn, geom->irtc); + geom->irtc = RTC_INVALID_GEOMETRY_ID; scn->is_rtc_scn_outdated = 1; } /* Update the cached mesh states */ - geom->data.mesh->flip_surface = shape->data.mesh->flip_surface; + geom->flip_surface = shape->flip_surface; res = scene_build_register_mesh(scn, geom); if(res != RES_OK) goto error; @@ -240,13 +236,13 @@ scene_setup_shape_mesh scn->is_rtc_scn_outdated = 1; } if(upd_ids) { /* Update the Embree index buffer if necessary */ - rtcSetBuffer(scn->rtc_scn, mesh->geom.irtc, RTC_INDEX_BUFFER, - mesh_get_ids(mesh), 0, sizeof(uint32_t[3])); - rtcUpdateBuffer(scn->rtc_scn, mesh->geom.irtc, RTC_INDEX_BUFFER); + rtcSetBuffer(scn->rtc_scn, geom->irtc, RTC_INDEX_BUFFER, + mesh_get_ids(geom->data.mesh), 0, sizeof(uint32_t[3])); + rtcUpdateBuffer(scn->rtc_scn, geom->irtc, RTC_INDEX_BUFFER); scn->is_rtc_scn_outdated = 1; } - scene_geometry_flush_enable_state(scn, &mesh->geom, &shape->data.mesh->geom); + scene_geometry_flush_enable_state(scn, geom, shape); /* Flush the shape mesh states */ shape->data.mesh->resize_mask = 0; @@ -270,7 +266,7 @@ scene_setup_shape_instance(struct s3d_scene* scn, struct s3d_shape* shape) res = scene_build(shape->data.instance->scene, BUILD_INDIRECT); if(res != RES_OK) goto error; - pgeom = htable_inst_find(&scn->cached_geoms, &shape); + pgeom = htable_geom_find(&scn->cached_geoms, &shape); /* Create the scene instance of the geometry if necessary */ if(pgeom) { geom = *pgeom; @@ -280,38 +276,38 @@ scene_setup_shape_instance(struct s3d_scene* scn, struct s3d_shape* shape) geom->type = GEOM_INSTANCE; res = instance_create(shape->data.instance->scene, &geom->data.instance); if(res != RES_OK) goto error; - res = htable_inst_set(&scn->cached_geoms, &shape, &geom); + res = htable_geom_set(&scn->cached_geoms, &shape, &geom); if(res != RES_OK) goto error; - geom->id = shape->name.index; + geom->name = shape->id.index; } /* Update the cached instance states */ - ASSERT(geom->data.inst->scene == shape->data.instance->scene); - f33_set(geom->data.inst->transform, shape->data.instance->transform); + ASSERT(geom->data.instance->scene == shape->data.instance->scene); + f33_set(geom->data.instance->transform, shape->data.instance->transform); f3_set(geom->data.instance->transform + 9, shape->data.instance->transform + 9); - geom->data.instance->flip_surface = shape->flip_surface; + geom->flip_surface = shape->flip_surface; - /* TODO The instance cannot contain instances */ - if(darray_inst_size_get(&inst->scene->instances)) { + /* The instance cannot contain instances, i.e. one instancing level is + * supported */ + if(geom->data.instance->scene->instances_count != 0) { res = RES_BAD_ARG; goto error; } /* Create the Embree instance */ - res = scene_build_register_instance(scn, inst); + res = scene_build_register_instance(scn, geom); if(res != RES_OK) goto error; /* Update the Embree instance transformation */ - if(geom->data.instance->update_transform) { + if(shape->data.instance->update_transform) { rtcSetTransform (scn->rtc_scn, - inst->geom.irtc, + geom->irtc, RTC_MATRIX_COLUMN_MAJOR, - inst->transform); + geom->data.instance->transform); scn->is_rtc_scn_outdated = 1; } - scene_geometry_flush_enable_state - (scn, geom, &shape->data.instance->geom); + scene_geometry_flush_enable_state(scn, geom, shape); shape->data.instance->update_transform = 0; /* Flush instance state */ exit: @@ -321,100 +317,29 @@ error: } static void -scene_detach_shape_mesh(struct s3d_scene* scn, struct s3d_shape* shape) +scene_detach_shape(struct s3d_scene* scn, struct s3d_shape* shape) { - struct mesh** pmesh; + struct geometry** pgeom; ASSERT(scn && shape && !is_list_empty(&shape->scene_attachment)); - ASSERT(shape->type == SHAPE_MESH); - - pmesh = htable_mesh_find(&scn->cached_meshes, &shape); - if(pmesh) { /* Remove the cached shape mesh */ - struct mesh* mesh = *pmesh; - if(mesh->geom.irtc != RTC_INVALID_GEOMETRY_ID) { - rtcDeleteGeometry(scn->rtc_scn, mesh->geom.irtc); - mesh->geom.irtc = RTC_INVALID_GEOMETRY_ID; - scn->is_rtc_scn_outdated = 1; - } - mesh_ref_put(mesh); - htable_mesh_erase(&scn->cached_meshes, &shape); - } - list_del(&shape->scene_attachment); - S3D(shape_ref_put(shape)); -} + ASSERT(shape->type == GEOM_MESH || shape->type == GEOM_INSTANCE); -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->cached_instances, &shape); - if(pinst) { /* Remove the cached shape instance */ - struct instance* inst = *pinst; - if(inst->geom.irtc != RTC_INVALID_GEOMETRY_ID) { - rtcDeleteGeometry(scn->rtc_scn, inst->geom.irtc); - inst->geom.irtc = RTC_INVALID_GEOMETRY_ID; + pgeom = htable_geom_find(&scn->cached_geoms, &shape); + if(pgeom) { /* Remove the cached shape mesh */ + struct geometry* geom = *pgeom; + if(geom->irtc != RTC_INVALID_GEOMETRY_ID) { + rtcDeleteGeometry(scn->rtc_scn, geom->irtc); + geom->irtc = RTC_INVALID_GEOMETRY_ID; + scn->is_rtc_scn_outdated = 1; } - instance_ref_put(inst); - htable_inst_erase(&scn->cached_instances, &shape); + geometry_ref_put(geom); + htable_geom_erase(&scn->cached_geoms, &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 res_T -scene_compute_shape_cdf(struct s3d_scene* scn) -{ - struct list_node* node; - ASSERT(scn); - - LIST_FOR_EACH(node, &scn->shapes) { - - const size_t ntris = mesh_get_ntris(mesh); - const uint32_t* ids = mesh_get_ids(mesh); - const float* verts = mesh_get_pos(mesh); - size_t itri; - float area; - - ASSERT(shape->type == SHAPE_MESH); - - area = 0.f; - FOR_EACH(itri, 0, ntris) { - int i; - const float* positions[3]; - float edges[2][3], normal[3]; - float triangle_area; - - FOR_EACH(i, 0, 3) { /* Fetch vertex positions */ - const uint32_t id = ids[itri * 3 + i]; - ASSERT(id < mesh_get_nverts(shape->data.mesh)); - positions[i] = verts + id * 3/*#coords*/; - } - - /* Compute triangle area. Note that actually, we compute the double of - * the triangle area since it saves computation times whithout affecting - * the sampling result */ - f3_sub(edges[0], positions[1], positions[0]); - f3_sub(edges[1], positions[2], positions[0]); - f3_cross(normal, edges[0], edges[1]); - triangle_area = f3_len(normal); - - /* Store the CDF value of the triangle `itri' */ - area += triangle_area; - darray_float_push_back(&triangles_cdf, &area); - } + if(shape->type == GEOM_INSTANCE) { + ASSERT(scn->instances_count != 0); + --scn->instances_count; } } @@ -433,9 +358,9 @@ scene_build(struct s3d_scene* scn, const enum build_type type) LIST_FOR_EACH(node, &scn->shapes) { struct s3d_shape* shape = CONTAINER_OF (node, struct s3d_shape, scene_attachment); - switch(shape->geom.type) { - case SHAPE_INSTANCE: res = scene_setup_instance(scn, &shape->geom); break; - case SHAPE_MESH: res = scene_setup_mesh(scn, &shape->geom); break; + switch(shape->type) { + case GEOM_INSTANCE: res = scene_setup_shape_instance(scn, shape); break; + case GEOM_MESH: res = scene_setup_shape_mesh(scn, shape); break; default: FATAL("Unreachable code\n"); break; } if(res != RES_OK) @@ -465,10 +390,8 @@ scene_release(ref_T* ref) dev = scn->dev; scene_build_clear(scn); if(scn->rtc_scn) rtcDeleteScene(scn->rtc_scn); - htable_mesh_release(&scn->cached_meshes); - htable_inst_release(&scn->cached_instances); - darray_mesh_release(&scn->meshes); - darray_inst_release(&scn->instances); + htable_geom_release(&scn->cached_geoms); + darray_geom_release(&scn->embree2geoms); MEM_RM(dev->allocator, scn); S3D(device_ref_put(dev)); } @@ -494,8 +417,7 @@ s3d_scene_create(struct s3d_device* dev, struct s3d_scene** out_scn) } list_init(&scn->shapes); htable_geom_init(dev->allocator, &scn->cached_geoms); - darray_mesh_init(dev->allocator, &scn->meshes); - darray_inst_init(dev->allocator, &scn->instances); + darray_geom_init(dev->allocator, &scn->embree2geoms); ref_init(&scn->ref); S3D(device_ref_get(dev)); scn->dev = dev; @@ -552,8 +474,8 @@ s3d_scene_instantiate(struct s3d_scene* scn, struct s3d_shape** out_shape) if(res != RES_OK) goto error; - shape->geom.type = GEOM_MESH_INSTANCE; - res = instance_create(scn, &shape->geom.data.instance); + shape->type = GEOM_INSTANCE; + res = instance_create(scn, &shape->data.instance); if(res != RES_OK) goto error; @@ -579,6 +501,7 @@ s3d_scene_attach_shape(struct s3d_scene* scn, struct s3d_shape* shape) list_add_tail(&scn->shapes, &shape->scene_attachment); S3D(shape_ref_get(shape)); + scn->instances_count += shape->type == GEOM_INSTANCE; return RES_OK; } @@ -591,7 +514,7 @@ s3d_scene_detach_shape(struct s3d_scene* scn, struct s3d_shape* shape) if(!(S3D(shape_is_attached(shape, &is_attached)), is_attached)) return RES_BAD_ARG; #ifndef NDEBUG - { + { /* Check the the shape is attached to `scn' */ struct list_node* node; char is_found = 0; LIST_FOR_EACH(node, &scn->shapes) { @@ -703,29 +626,33 @@ s3d_scene_trace_ray hit->uv[0] = w; if((unsigned)ray.instID == RTC_INVALID_GEOMETRY_ID) { - ASSERT((unsigned)ray.geomID < darray_mesh_size_get(&scn->meshes)); - hit->prim.mesh__ = darray_mesh_data_get(&scn->meshes)[ray.geomID]; + ASSERT((unsigned)ray.geomID < darray_geom_size_get(&scn->embree2geoms)); + hit->prim.mesh__ = darray_geom_data_get(&scn->embree2geoms)[ray.geomID]; hit->prim.inst__ = NULL; hit->prim.prim_id = ray.primID; - hit->prim.geom_id = ((struct mesh*)hit->prim.mesh__)->id; + hit->prim.geom_id = ((struct geometry*)hit->prim.mesh__)->name; hit->prim.inst_id = S3D_INVALID_ID; } else { /* The hit shape is instantiated */ /* Retrieve the hit instance */ - struct instance* instance; - ASSERT((unsigned)ray.instID < darray_inst_size_get(&scn->instances)); - instance = darray_inst_data_get(&scn->instances)[ray.instID]; - hit->prim.mesh__ = scene_get_mesh(instance->scene, ray.geomID); - hit->prim.inst__ = instance; + struct geometry* geom_inst; + ASSERT((unsigned)ray.instID < darray_geom_size_get(&scn->embree2geoms)); + geom_inst = darray_geom_data_get(&scn->embree2geoms)[ray.instID]; + hit->prim.mesh__ = scene_get_mesh(geom_inst->data.instance->scene, ray.geomID); + hit->prim.inst__ = geom_inst; hit->prim.prim_id = ray.primID; - hit->prim.geom_id = ((struct mesh*)hit->prim.mesh__)->id; - hit->prim.inst_id = instance->id; - flip_surface = instance->flip_surface; + hit->prim.geom_id = ((struct geometry*)hit->prim.mesh__)->name; + hit->prim.inst_id = geom_inst->name; + flip_surface = geom_inst->flip_surface; + ASSERT(hit->prim.inst__); + ASSERT(((struct geometry*)hit->prim.inst__)->type == GEOM_INSTANCE); } ASSERT(hit->prim.mesh__); - flip_surface ^= ((struct mesh*)hit->prim.mesh__)->flip_surface; - if(flip_surface) - f3_minus(hit->normal, hit->normal); + ASSERT(((struct geometry*)hit->prim.mesh__)->type == GEOM_MESH); + + /* Flip geometric normal with respect to the flip surface flag */ + flip_surface ^= ((struct geometry*)hit->prim.mesh__)->flip_surface; + if(flip_surface) f3_minus(hit->normal, hit->normal); } return RES_OK; } diff --git a/src/s3d_scene_c.h b/src/s3d_scene_c.h @@ -62,7 +62,7 @@ geom_ptr_init__(struct mem_allocator* alloc, struct geometry** geom) #define HTABLE_KEY struct s3d_shape* #include <rsys/hash_table.h> -enum sync_type { +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 */ @@ -70,11 +70,10 @@ enum sync_type { struct s3d_scene { struct list_node shapes; /* List of attached shapes */ - struct htable_mesh cached_geoms; /* Cached shape geometries */ + struct htable_geom cached_geoms; /* Cached shape geometries */ + struct darray_geom embree2geoms; /* Shape geometries index by embree id */ - /* Active geometry. Indexed by the Embree identifier */ - struct darray_geom meshes; - struct darray_geom instances; + size_t instances_count; /* # instances int the scene */ RTCScene rtc_scn; char is_rtc_scn_outdated; @@ -85,15 +84,15 @@ struct s3d_scene { ref_T ref; }; -static FINLINE struct mesh* +static FINLINE struct geometry* scene_get_mesh(struct s3d_scene* scn, const unsigned igeom) { - struct mesh* mesh; + struct geometry* geom; ASSERT(scn && igeom != RTC_INVALID_GEOMETRY_ID); - ASSERT(igeom < darray_mesh_size_get(&scn->meshes)); - mesh = darray_mesh_data_get(&scn->meshes)[igeom]; - ASSERT(mesh); - return mesh; + ASSERT(igeom < darray_geom_size_get(&scn->embree2geoms)); + geom = darray_geom_data_get(&scn->embree2geoms)[igeom]; + ASSERT(geom); + return geom; } #endif /* S3D_SCENE_C_H */ diff --git a/src/s3d_shape.c b/src/s3d_shape.c @@ -60,6 +60,7 @@ shape_release(ref_T* ref) case GEOM_INSTANCE: if(shape->data.instance) instance_ref_put(shape->data.instance); break; + default: FATAL("Unreachable code \n"); break; } } MEM_RM(dev->allocator, shape); @@ -89,8 +90,10 @@ shape_create(struct s3d_device* dev, struct s3d_shape** out_shape) S3D(device_ref_get(dev)); shape->dev = dev; ref_init(&shape->ref); - shape->fid = flist_name_add(&dev->names); + shape->id = flist_name_add(&dev->names); shape->type = GEOM_NONE; + shape->is_enabled = 1; + shape->flip_surface = 0; exit: if(out_shape) *out_shape = shape; @@ -160,7 +163,7 @@ res_T s3d_shape_get_id(struct s3d_shape* shape, unsigned* id) { if(!shape || !id) return RES_BAD_ARG; - *id = shape->name.index; + *id = shape->id.index; return RES_OK; } @@ -236,10 +239,12 @@ s3d_shape_compute_volume(struct s3d_shape* shape, float* volume) return RES_BAD_ARG; switch(shape->type) { case GEOM_MESH: - *volume = mesh_compute_volume(shape->data.mesh, 0); + *volume = mesh_compute_volume + (shape->data.mesh, shape->flip_surface); break; case GEOM_INSTANCE: - *volume = instance_compute_volume(shape->data.instance); + *volume = instance_compute_volume + (shape->data.instance, shape->flip_surface); break; default: FATAL("Unreachable code \n"); break; }