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 19795ca5e55ceeb47974b199c54e851943844713
parent a61ec8fbab4c568c4345370a6e53a2eda1c79c4b
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed,  9 Sep 2015 09:17:41 +0200

Begin the refactoring of the shape and scene build

Diffstat:
Asrc/s3d_geometry.c | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/s3d_geometry.h | 41++++++++++++++++++++++++++++++++---------
Msrc/s3d_mesh.h | 7-------
Msrc/s3d_scene.c | 208+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Msrc/s3d_scene_c.h | 45+++++++++++++--------------------------------
Msrc/s3d_shape.c | 86+++++++++++++++++++++++++++----------------------------------------------------
Msrc/s3d_shape_c.h | 16++++++----------
7 files changed, 317 insertions(+), 194 deletions(-)

diff --git a/src/s3d_geometry.c b/src/s3d_geometry.c @@ -0,0 +1,108 @@ +/* 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_geometry.h" + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static void +geometry_release(ref_T* ref) +{ + struct geometry* geom; + struct s3d_device* dev; + + geom = CONTAINER_OF(ref, struct geometry, ref); + dev = geom->dev; + switch(geom->type) { + case GEOM_MESH: + if(geom->data.mesh) mesh_ref_put(geom->data.mesh); + break; + case GEOM_INSTANCE: + if(geom->data.instance) instance_ref_put(geom->data.instance); + break; + default: FATAL("Unreachable code\n"); break; + } + MEM_RM(dev->allocator, geom); + S3D(device_ref_put(dev)); +} + +/******************************************************************************* + * Local functions + ******************************************************************************/ +res_T +geometry_create + (struct s3d_device* dev, + struct geometry** out_geom) +{ + struct geometry* geom = NULL; + ASSERT(dev && out_geom); + + geom = MEM_CALLOC(dev->allocator, 1, sizeof(struct geometry)); + if(!geom) { + res = RES_MEM_ERR; + goto error; + } + + geom->name = S3D_INVALID_ID; + geom->irtc = RTC_INVALID_GEOMETRY_ID; + geom->flip_surface = 0; + geom->is_enabled = 1; + geom->type = GEOM_NONE; + geom->data.mesh = NULL; + +exit: + *out_geom = geom; + return res; +error: + if(geom) { + geometry_ref_put(geom); + geom = NULL; + } + goto exit; +} + +void +geometry_ref_get(struct geometry* geom) +{ + ASSERT(geom); + ref_get(&geom->ref); +} + +void +geometry_ref_put(struct geometry* geom) +{ + ASSERT(geom); + ref_put(&geom->ref, release); +} + + diff --git a/src/s3d_geometry.h b/src/s3d_geometry.h @@ -35,19 +35,42 @@ #include "s3d_backend.h" +enum geometry_type { + GEOM_MESH, + GEOM_INSTANCE, + GEOM_TYPES_COUNT__, + GEOM_NONE = SHAPE_TYPES_COUNT__ +}; + /* Backend geometry */ struct geometry { - unsigned irtc; /* Embree geometry identifier */ - char is_enabled; + unsigned name; /* Client side identifier */ + unsigned irtc; /* Embree identifier */ + char flip_surface; /* Is the geometry surface flipped? */ + char is_enabled; /* Is the geometry enabled? */ + + enum geometry_type type; + union { + struct instance* instance; + struct mesh* mesh; + } data; + + struct s3d_device* dev; + ref_T ref; }; -static FINLINE void -geometry_init(struct geometry* geom) -{ - ASSERT(geom); - geom->irtc = RTC_INVALID_GEOMETRY_ID; - geom->is_enabled = 1; -} +extern LOCAL_SYM res_T +geometry_create + (struct s3d_device* dev, + struct geometry** geom); + +extern LOCAL_SYM res_T +geometry_ref_get + (struct geometry* geometry); + +extern LOCAL_SYM res_T +geometry_ref_put + (struct geometry* geometry); #endif /* S3D_GEOMETRY_H */ diff --git a/src/s3d_mesh.h b/src/s3d_mesh.h @@ -61,15 +61,8 @@ struct mesh { /* Triangular mesh */ struct index_buffer* indices; struct vertex_buffer* attribs[S3D_ATTRIBS_COUNT__]; enum s3d_type attribs_type[S3D_ATTRIBS_COUNT__]; - int resize_mask; /* Combination of buffer_type */ int update_mask; /* Combination of buffer_type */ - - struct geometry geom; - char flip_surface; - - unsigned id; /* Unique identifier of a mesh */ - struct s3d_device* dev; ref_T ref; }; diff --git a/src/s3d_scene.c b/src/s3d_scene.c @@ -68,50 +68,50 @@ scene_geometry_flush_enable_state } static res_T -scene_build_register_mesh(struct s3d_scene* scn, struct mesh* mesh) +scene_build_register_mesh(struct s3d_scene* scn, struct geometry* geom) { - ASSERT(scn && mesh); + ASSERT(scn && geom && geom->type == GEOM_MESH); /* Create the Embree geometry if it is not valid */ - if(mesh->geom.irtc == RTC_INVALID_GEOMETRY_ID) { - mesh->geom.irtc = rtcNewTriangleMesh(scn->rtc_scn, RTC_GEOMETRY_DYNAMIC, - mesh_get_ntris(mesh), mesh_get_nverts(mesh)); - if(mesh->geom.irtc == RTC_INVALID_GEOMETRY_ID) + if(geom->irtc == RTC_INVALID_GEOMETRY_ID) { + geom->irtc = rtcNewTriangleMesh(scn->rtc_scn, RTC_GEOMETRY_DYNAMIC, + mesh_get_ntris(geom->data.mesh), mesh_get_nverts(geom->data.mesh)); + if(geom->irtc == RTC_INVALID_GEOMETRY_ID) return RES_UNKNOWN_ERR; scn->is_rtc_scn_outdated = 1; } - if(mesh->geom.irtc >= darray_mesh_size_get(&scn->meshes)) { - res_T res = darray_mesh_resize(&scn->meshes, mesh->geom.irtc + 1); + if(geom->irtc >= darray_mesh_size_get(&scn->meshes)) { + res_T res = darray_mesh_resize(&scn->meshes, geom->irtc + 1); if(res != RES_OK) { - rtcDeleteGeometry(scn->rtc_scn, mesh->geom.irtc); - mesh->geom.irtc = RTC_INVALID_GEOMETRY_ID; + rtcDeleteGeometry(scn->rtc_scn, geom->irtc); + geom->irtc = RTC_INVALID_GEOMETRY_ID; return res; } } - mesh_ref_get(mesh); - darray_mesh_data_get(&scn->meshes)[mesh->geom.irtc] = mesh; + geometry_ref_get(geom); + darray_mesh_data_get(&scn->meshes)[geom->irtc] = geom; return RES_OK; } static res_T -scene_build_register_instance(struct s3d_scene* scn, struct instance* inst) +scene_build_register_instance(struct s3d_scene* scn, struct geometry* geom) { - ASSERT(scn && inst && inst->scene); + ASSERT(scn && geom && inst->scene); /* The instance should not contain instances */ ASSERT(!darray_inst_size_get(&inst->scene->instances)); - if(inst->geom.irtc == RTC_INVALID_GEOMETRY_ID) { - inst->geom.irtc = rtcNewInstance(scn->rtc_scn, inst->scene->rtc_scn); - if(inst->geom.irtc == RTC_INVALID_GEOMETRY_ID) + 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) return RES_UNKNOWN_ERR; scn->is_rtc_scn_outdated = 1; } - if(inst->geom.irtc >= darray_inst_size_get(&scn->instances)) { - res_T res = darray_inst_resize(&scn->instances, inst->geom.irtc + 1); + if(geom->irtc >= darray_inst_size_get(&scn->instances)) { + res_T res = darray_inst_resize(&scn->instances, geom->irtc + 1); if(res != RES_OK) { - rtcDeleteGeometry(scn->rtc_scn, inst->geom.irtc); - inst->geom.irtc = RTC_INVALID_GEOMETRY_ID; + rtcDeleteGeometry(scn->rtc_scn, geom->irtc); + geom->irtc = RTC_INVALID_GEOMETRY_ID; return res; } } @@ -152,88 +152,91 @@ scene_setup_shape_mesh (struct s3d_scene* scn, struct s3d_shape* shape) { - struct mesh** pmesh = NULL; - struct mesh* mesh = NULL; + struct geometry** pgeom = NULL; + struct geometry* geom = NULL; size_t iattr; char upd_pos, upd_ids; res_T res = RES_OK; ASSERT(shape && shape->type == SHAPE_MESH); - /* Retrieve the cached shape mesh */ - pmesh = htable_mesh_find(&scn->cached_meshes, &shape); - if(pmesh) { - mesh = *pmesh; + /* Retrieve the cached geometry */ + pgeom = htable_geom_find(&scn->cached_geoms, &shape); + if(pgeom) { + geom = *pgeom; } else { - res = mesh_create(scn->dev, &mesh); + res = geometry_create(scn->dev, &geom); + if(res != RES_OK) goto error; + res = mesh_create(scn->dev, &geom->data.mesh); if(res != RES_OK) goto error; - res = htable_mesh_set(&scn->cached_meshes, &shape, &mesh); + geom->type = GEOM_MESH; + res = htable_geom_set(&scn->cached_geoms, &shape, &geom); if(res != RES_OK) goto error; - mesh->id = shape->name.index; + geom->name = shape->name.index; } - /* Discard the shape mesh that is not geometrically valid */ + /* Discard the geometry that is not geometrically valid */ if(!shape->data.mesh->indices || !shape->data.mesh->attribs[S3D_POSITION]) { - if(mesh->geom.irtc != RTC_INVALID_GEOMETRY_ID) { - rtcDeleteGeometry(scn->rtc_scn, mesh->geom.irtc); - mesh->geom.irtc = RTC_INVALID_GEOMETRY_ID; + 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; } - mesh_clear(mesh); + mesh_clear(geom->mesh); goto exit; } /* Define which Embree geometry buffer must be updated */ - upd_ids = mesh->indices != shape->data.mesh->indices + upd_ids = geom->data.mesh->indices != shape->data.mesh->indices || ((shape->data.mesh->update_mask & INDEX_BUFFER) != 0); - upd_pos = mesh->attribs[S3D_POSITION] != shape->data.mesh->attribs[S3D_POSITION] + upd_pos = geom->data.mesh->attribs[S3D_POSITION] != shape->data.mesh->attribs[S3D_POSITION] || ((shape->data.mesh->update_mask == VERTEX_BUFFER) != 0); /* Get a reference onto the shape mesh indices */ - if(mesh->indices != shape->data.mesh->indices) { - if(mesh->indices) { - index_buffer_ref_put(mesh->indices); - mesh->indices = NULL; + if(geom->data.mesh->indices != shape->data.mesh->indices) { + if(geom->data.mesh->indices) { + index_buffer_ref_put(geom->data.mesh->indices); + geom->data.mesh->indices = NULL; } ASSERT(shape->data.mesh->indices); index_buffer_ref_get(shape->data.mesh->indices); - mesh->indices = shape->data.mesh->indices; + geom->data.mesh->indices = shape->data.mesh->indices; } /* Get the reference onto the shape mesh attribs */ FOR_EACH(iattr, 0, S3D_ATTRIBS_COUNT__) { - if(mesh->attribs[iattr] == shape->data.mesh->attribs[iattr]) + if(geom->data.mesh->attribs[iattr] == shape->data.mesh->attribs[iattr]) continue; - if(mesh->attribs[iattr]) { - vertex_buffer_ref_put(mesh->attribs[iattr]); - mesh->attribs[iattr] = NULL; + if(geom->data.mesh->attribs[iattr]) { + vertex_buffer_ref_put(geom->data.mesh->attribs[iattr]); + geom->data.mesh->attribs[iattr] = NULL; } if(!shape->data.mesh->attribs[iattr]) continue; vertex_buffer_ref_get(shape->data.mesh->attribs[iattr]); - mesh->attribs[iattr] = shape->data.mesh->attribs[iattr]; - mesh->attribs_type[iattr] = shape->data.mesh->attribs_type[iattr]; + geom->data.mesh->attribs[iattr] = shape->data.mesh->attribs[iattr]; + geom->data.mesh->attribs_type[iattr] = shape->data.mesh->attribs_type[iattr]; } /* 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, mesh->geom.irtc); - 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; scn->is_rtc_scn_outdated = 1; } /* Update the cached mesh states */ - mesh->flip_surface = shape->data.mesh->flip_surface; + geom->data.mesh->flip_surface = shape->data.mesh->flip_surface; - res = scene_build_register_mesh(scn, mesh); + res = scene_build_register_mesh(scn, geom); if(res != RES_OK) goto error; if(upd_pos) { /* Update the Embree vertex buffer if necessary */ - rtcSetBuffer(scn->rtc_scn, mesh->geom.irtc, RTC_VERTEX_BUFFER, - mesh_get_pos(mesh), 0, sizeof(float[3])); - rtcUpdateBuffer(scn->rtc_scn, mesh->geom.irtc, RTC_VERTEX_BUFFER); + rtcSetBuffer(scn->rtc_scn, geom->irtc, RTC_VERTEX_BUFFER, + mesh_get_pos(geom->data.mesh), 0, sizeof(float[3])); + rtcUpdateBuffer(scn->rtc_scn, geom->irtc, RTC_VERTEX_BUFFER); scn->is_rtc_scn_outdated = 1; } if(upd_ids) { /* Update the Embree index buffer if necessary */ @@ -258,33 +261,36 @@ error: static res_T scene_setup_shape_instance(struct s3d_scene* scn, struct s3d_shape* shape) { - struct instance** pinst = NULL; - struct instance* inst = NULL; + struct geometry** pgeom = NULL; + struct geometry* geom = NULL; res_T res = RES_OK; - ASSERT(scn && shape && shape->type == SHAPE_INSTANCE); + ASSERT(scn && shape && shape->type == GEOM_INSTANCE); /* Recursuvely update the scene */ res = scene_build(shape->data.instance->scene, BUILD_INDIRECT); if(res != RES_OK) goto error; - pinst = htable_inst_find(&scn->cached_instances, &shape); - /* Create the scene instance of the shape if necessary */ - if(pinst) { - inst = *pinst; + pgeom = htable_inst_find(&scn->cached_geoms, &shape); + /* Create the scene instance of the geometry if necessary */ + if(pgeom) { + geom = *pgeom; } else { - res = instance_create(shape->data.instance->scene, &inst); + res = geometry_create(scn->dev, &geom); + if(res != RES_OK) goto error; + 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_instances, &shape, &inst); + res = htable_inst_set(&scn->cached_geoms, &shape, &geom); if(res != RES_OK) goto error; - inst->id = shape->name.index; + geom->id = shape->name.index; } /* Update the cached instance states */ - 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); - inst->flip_surface = shape->data.instance->flip_surface; + ASSERT(geom->data.inst->scene == shape->data.instance->scene); + f33_set(geom->data.inst->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; - /* The instance cannot contain instances */ + /* TODO The instance cannot contain instances */ if(darray_inst_size_get(&inst->scene->instances)) { res = RES_BAD_ARG; goto error; @@ -295,7 +301,7 @@ scene_setup_shape_instance(struct s3d_scene* scn, struct s3d_shape* shape) if(res != RES_OK) goto error; /* Update the Embree instance transformation */ - if(shape->data.instance->update_transform) { + if(geom->data.instance->update_transform) { rtcSetTransform (scn->rtc_scn, inst->geom.irtc, @@ -305,7 +311,7 @@ scene_setup_shape_instance(struct s3d_scene* scn, struct s3d_shape* shape) } scene_geometry_flush_enable_state - (scn, &inst->geom, &shape->data.instance->geom); + (scn, geom, &shape->data.instance->geom); shape->data.instance->update_transform = 0; /* Flush instance state */ exit: @@ -369,6 +375,50 @@ scene_detach_shape(struct s3d_scene* scn, struct s3d_shape* shape) } 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); + } + } +} + +static res_T scene_build(struct s3d_scene* scn, const enum build_type type) { struct list_node* node; @@ -383,9 +433,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->type) { - case SHAPE_INSTANCE: res = scene_setup_shape_instance(scn, shape); break; - case SHAPE_MESH: res = scene_setup_shape_mesh(scn, shape); break; + 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; default: FATAL("Unreachable code\n"); break; } if(res != RES_OK) @@ -443,8 +493,7 @@ s3d_scene_create(struct s3d_device* dev, struct s3d_scene** out_scn) goto error; } list_init(&scn->shapes); - htable_mesh_init(dev->allocator, &scn->cached_meshes); - htable_inst_init(dev->allocator, &scn->cached_instances); + htable_geom_init(dev->allocator, &scn->cached_geoms); darray_mesh_init(dev->allocator, &scn->meshes); darray_inst_init(dev->allocator, &scn->instances); ref_init(&scn->ref); @@ -498,12 +547,13 @@ s3d_scene_instantiate(struct s3d_scene* scn, struct s3d_shape** out_shape) res = RES_BAD_ARG; goto error; } + res = shape_create(scn->dev, &shape); if(res != RES_OK) goto error; - shape->type = SHAPE_INSTANCE; - res = instance_create(scn, &shape->data.instance); + shape->geom.type = GEOM_MESH_INSTANCE; + res = instance_create(scn, &shape->geom.data.instance); if(res != RES_OK) goto error; diff --git a/src/s3d_scene_c.h b/src/s3d_scene_c.h @@ -41,46 +41,28 @@ #include <rsys/ref_count.h> /* - * The mesh/instance pointers must be initialized to NULL in order to define + * The geometry pointers must be initialized to NULL in order to define * which pointers are valid or not */ static FINLINE void -mesh_ptr_init__(struct mem_allocator* alloc, struct mesh** mesh) +geom_ptr_init__(struct mem_allocator* alloc, struct geometry** geom) { - (void)alloc; *mesh = NULL; + (void)alloc; *geom = NULL; } -static FINLINE void -instance_ptr_init__(struct mem_allocator* alloc, struct instance** inst) -{ - (void)alloc; *inst = NULL; -} - -/* Generate the darray_mesh dynamic array */ -#define DARRAY_NAME mesh -#define DARRAY_DATA struct mesh* -#define DARRAY_FUNCTOR_INIT mesh_ptr_init__ -#include <rsys/dynamic_array.h> - -/* Generate the darray_inst dynamic array */ -#define DARRAY_NAME inst -#define DARRAY_DATA struct instance* -#define DARRAY_FUNCTOR_INIT instance_ptr_init__ +/* Generate the darray_geom dynamic array */ +#define DARRAY_NAME geom +#define DARRAY_DATA struct geometry* +#define DARRAY_FUNCTOR_INIT geom_ptr_init__ #include <rsys/dynamic_array.h> /* Generate the htable_mesh hash table */ -#define HTABLE_NAME mesh -#define HTABLE_DATA struct mesh* -#define HTABLE_KEY struct s3d_shape* -#include <rsys/hash_table.h> - -/* Generate the htable_instance hash table */ -#define HTABLE_NAME inst -#define HTABLE_DATA struct instance* +#define HTABLE_NAME geom +#define HTABLE_DATA struct geometry* #define HTABLE_KEY struct s3d_shape* #include <rsys/hash_table.h> -enum build_type { +enum sync_type { BUILD_NONE, /* The scene is not built */ BUILD_DIRECT, /* The scene is directly build */ BUILD_INDIRECT /* The scene is build as an instance */ @@ -88,12 +70,11 @@ enum build_type { struct s3d_scene { struct list_node shapes; /* List of attached shapes */ - struct htable_mesh cached_meshes; /* Cached shape meshes */ - struct htable_inst cached_instances; /* Cached shape instances */ + struct htable_mesh cached_geoms; /* Cached shape geometries */ /* Active geometry. Indexed by the Embree identifier */ - struct darray_mesh meshes; - struct darray_inst instances; + struct darray_geom meshes; + struct darray_geom instances; RTCScene rtc_scn; char is_rtc_scn_outdated; diff --git a/src/s3d_shape.c b/src/s3d_shape.c @@ -42,25 +42,6 @@ * Helper functions ******************************************************************************/ static void -shape_release_data(struct s3d_shape* shape) -{ - ASSERT(shape); - switch(shape->type) { - case SHAPE_MESH: - if(shape->data.mesh) - mesh_ref_put(shape->data.mesh); - break; - case SHAPE_NONE: /* Do nothing */ break; - case SHAPE_INSTANCE: - if(shape->data.instance) - instance_ref_put(shape->data.instance); - break; - default: FATAL("Unreachable code\n"); break; - } - shape->type = SHAPE_NONE; -} - -static void shape_release(ref_T* ref) { struct s3d_shape* shape; @@ -71,8 +52,16 @@ shape_release(ref_T* ref) /* The shape should not be attached */ ASSERT(is_list_empty(&shape->scene_attachment)); - flist_name_del(&dev->names, shape->name); - shape_release_data(shape); + if(shape->type != GEOM_NONE) { + switch(shape->type) { + case GEOM_MESH: + if(shape->data.mesh) mesh_ref_put(shape->data.mesh); + break; + case GEOM_INSTANCE: + if(shape->data.instance) instance_ref_put(shape->data.instance); + break; + } + } MEM_RM(dev->allocator, shape); S3D(device_ref_put(dev)); } @@ -100,7 +89,8 @@ shape_create(struct s3d_device* dev, struct s3d_shape** out_shape) S3D(device_ref_get(dev)); shape->dev = dev; ref_init(&shape->ref); - shape->name = flist_name_add(&dev->names); + shape->fid = flist_name_add(&dev->names); + shape->type = GEOM_NONE; exit: if(out_shape) *out_shape = shape; @@ -133,11 +123,11 @@ s3d_shape_create_mesh if(res != RES_OK) goto error; + shape->type = GEOM_MESH; res = mesh_create(dev, &shape->data.mesh); if(res != RES_OK) goto error; - shape->type = SHAPE_MESH; exit: if(out_shape) *out_shape = shape; @@ -178,11 +168,7 @@ res_T s3d_shape_enable(struct s3d_shape* shape, const char enable) { if(!shape) return RES_BAD_ARG; - switch(shape->type) { - case SHAPE_MESH: shape->data.mesh->geom.is_enabled = enable; break; - case SHAPE_INSTANCE: shape->data.instance->geom.is_enabled = enable; break; - default: FATAL("Unreachable code\n"); break; - } + shape->is_enabled = enable; return RES_OK; } @@ -190,23 +176,14 @@ res_T s3d_shape_is_enabled(struct s3d_shape* shape, char* is_enabled) { if(!shape || !is_enabled) return RES_BAD_ARG; - switch(shape->type) { - case SHAPE_MESH: - *is_enabled = shape->data.mesh->geom.is_enabled; - break; - case SHAPE_INSTANCE: - *is_enabled = shape->data.instance->geom.is_enabled; - break; - default: FATAL("Unreachable code\n"); break; - } + *is_enabled = shape->is_enabled; return RES_OK; } res_T s3d_shape_is_attached(struct s3d_shape* shape, char* is_attached) { - if(!shape || !is_attached) - return RES_BAD_ARG; + if(!shape || !is_attached) return RES_BAD_ARG; *is_attached = !is_list_empty(&shape->scene_attachment); return RES_OK; } @@ -214,26 +191,20 @@ s3d_shape_is_attached(struct s3d_shape* shape, char* is_attached) res_T s3d_shape_flip_surface(struct s3d_shape* shape) { - if(!shape) - return RES_BAD_ARG; - switch(shape->type) { - case SHAPE_MESH: shape->data.mesh->flip_surface ^= 1; break; - case SHAPE_INSTANCE: shape->data.instance->flip_surface ^= 1; break; - default: FATAL("Unreachable code\n"); break; - } + if(!shape) return RES_BAD_ARG; + shape->flip_surface ^= 1; return RES_OK; } res_T s3d_shape_primitives_count(struct s3d_shape* shape, size_t* nprims) { - if(!shape || !nprims) - return RES_BAD_ARG; + if(!shape || !nprims) return RES_BAD_ARG; switch(shape->type) { - case SHAPE_MESH: + case GEOM_MESH: *nprims = mesh_get_ntris(shape->data.mesh); break; - case SHAPE_INSTANCE: + case GEOM_INSTANCE: *nprims = instance_get_ntris(shape->data.instance); break; default: FATAL("Unreachable code\n"); break; @@ -247,10 +218,10 @@ s3d_shape_compute_area(struct s3d_shape* shape, float* area) if(!shape || !area) return RES_BAD_ARG; switch(shape->type) { - case SHAPE_MESH: + case GEOM_MESH: *area = mesh_compute_area(shape->data.mesh); break; - case SHAPE_INSTANCE: + case GEOM_INSTANCE: *area = instance_compute_area(shape->data.instance); break; default: FATAL("Unreachable code\n"); break; @@ -264,10 +235,10 @@ s3d_shape_compute_volume(struct s3d_shape* shape, float* volume) if(!shape || !volume) return RES_BAD_ARG; switch(shape->type) { - case SHAPE_MESH: + case GEOM_MESH: *volume = mesh_compute_volume(shape->data.mesh, 0); break; - case SHAPE_INSTANCE: + case GEOM_INSTANCE: *volume = instance_compute_volume(shape->data.instance); break; default: FATAL("Unreachable code \n"); break; @@ -280,7 +251,7 @@ s3d_instance_set_position (struct s3d_shape* shape, const float position[3]) { float axis[3]; - if(!shape || shape->type != SHAPE_INSTANCE || !position) + if(!shape || shape->type != GEOM_INSTANCE || !position) return RES_BAD_ARG; shape->data.instance->transform[9] = f3_dot(f33_row(axis, shape->data.instance->transform, 0), position); @@ -298,7 +269,7 @@ s3d_instance_translate const enum s3d_transform_space space, const float translation[3]) { - if(!shape || shape->type != SHAPE_INSTANCE || !translation) + if(!shape || shape->type != GEOM_INSTANCE || !translation) return RES_BAD_ARG; if(space == S3D_LOCAL_TRANSFORM) { float vec[3]; @@ -329,8 +300,9 @@ s3d_mesh_setup_indexed_vertices struct s3d_vertex_data attribs[], void* data) { - if(!shape || shape->type != SHAPE_MESH) + if(!shape || shape->type != GEOM_MESH) return RES_BAD_ARG; return mesh_setup_indexed_vertices (shape->data.mesh, ntris, get_indices, nverts, attribs, data); } + diff --git a/src/s3d_shape_c.h b/src/s3d_shape_c.h @@ -44,20 +44,16 @@ #include <limits.h> -enum shape_type { - SHAPE_MESH, - SHAPE_INSTANCE, - SHAPE_TYPES_COUNT__, - SHAPE_NONE = SHAPE_TYPES_COUNT__ -}; - struct s3d_shape { struct list_node scene_attachment; - enum shape_type type; - struct fid name; + struct fid id; + + char flip_surface; + char is_enabled; + enum geometry_type type; union { - struct instance* instance; + struct instance* instance; struct mesh* mesh; } data;