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 150fd2b313a60479d8357d69f77fcccdbd41aea9
parent 455c86e80a55f0f8d852639c8917e74456752ae0
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed, 27 Jul 2016 09:53:10 +0200

Fix compilation errors and warnings of the library

The tests still do not compile.

Diffstat:
Mcmake/CMakeLists.txt | 2++
Msrc/s3d.h | 12+++---------
Msrc/s3d_instance.c | 22----------------------
Msrc/s3d_instance.h | 8++------
Msrc/s3d_scene.c | 16++++++----------
Msrc/s3d_scene_c.h | 11-----------
Msrc/s3d_session.c | 205++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/s3d_session_c.h | 15++++++++++++++-
Msrc/s3d_shape.c | 2+-
9 files changed, 132 insertions(+), 161 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -68,6 +68,7 @@ set(S3D_FILES_SRC s3d_mesh.c s3d_primitive.c s3d_scene.c + s3d_session.c s3d_shape.c) set(S3D_FILES_INC_API s3d.h) set(S3D_FILES_INC @@ -78,6 +79,7 @@ set(S3D_FILES_INC s3d_geometry.h s3d_instance.h s3d_mesh.h + s3d_session_c.h s3d_shape_c.h) set(S3D_FILES_DOC COPYING.fr COPYING.en README.md) diff --git a/src/s3d.h b/src/s3d.h @@ -270,7 +270,7 @@ s3d_scene_clear S3D_API res_T s3d_session_create (struct s3d_scene* scn, - const int session_mask /* Combination of s3d_session_flag */ + const int session_mask, /* Combination of s3d_session_flag */ struct s3d_session** session); S3D_API res_T @@ -378,7 +378,7 @@ s3d_shape_ref_put * representation of the caller with a simple dynamic array */ S3D_API res_T s3d_shape_get_id - (struct s3d_shape* shape, + (const struct s3d_shape* shape, unsigned* id); /* Enable/disable the shape, i.e. it cannot be hit when its associated scene is @@ -391,15 +391,9 @@ s3d_shape_enable /* Return whether or not the shape is enabled, i.e. ray-traced. Default is 1 */ S3D_API res_T s3d_shape_is_enabled - (struct s3d_shape* shape, + (const struct s3d_shape* shape, char* is_enabled); -/* Define whether the shape is attached or not */ -S3D_API res_T -s3d_shape_is_attached - (struct s3d_shape* shape, - char* is_attached); - /* Flip the surface orientation, i.e. flip the geometric normal of the surface */ S3D_API res_T s3d_shape_flip_surface diff --git a/src/s3d_instance.c b/src/s3d_instance.c @@ -102,25 +102,3 @@ instance_ref_put(struct instance* inst) ref_put(&inst->ref, instance_release); } -float -instance_compute_volume(struct instance* inst, const char flip_surface) -{ - struct htable_shape_iterator it, end; - float volume = 0.f; - ASSERT(inst); - - htable_shape_begin(&inst->scene->shapes, &it); - htable_shape_end(&inst->scene->shapes, &end); - - /* TODO take into account the scale factor of the instance */ - while(!htable_shape_iterator_eq(&it, &end)) { - struct s3d_shape** pshape = htable_shape_iterator_data_get(&it); - struct s3d_shape* shape = *pshape; - const char flip = flip_surface ^ shape->flip_surface; - ASSERT(shape->type == GEOM_MESH); /* One instancing level is supported */ - volume += mesh_compute_volume(shape->data.mesh, flip); - htable_shape_iterator_next(&it); - } - return volume; -} - diff --git a/src/s3d_instance.h b/src/s3d_instance.h @@ -39,7 +39,8 @@ struct instance { float transform[12]; /* local to world 3x4 column major matrix */ - struct s3d_scene* scene; + struct s3d_scene* scene; /* Instantiated scene */ + struct s3d_session* session; /* Current session of the instance */ ref_T ref; }; @@ -56,10 +57,5 @@ extern LOCAL_SYM void instance_ref_put (struct instance* inst); -extern LOCAL_SYM float -instance_compute_volume - (struct instance* inst, - const char flip_surface); - #endif /* S3D_INSTANCE_H */ diff --git a/src/s3d_scene.c b/src/s3d_scene.c @@ -34,6 +34,7 @@ #include "s3d_device_c.h" #include "s3d_scene_c.h" #include "s3d_session_c.h" +#include "s3d_shape_c.h" #include <rsys/list.h> #include <rsys/mem_allocator.h> @@ -46,12 +47,13 @@ scene_release(ref_T* ref) { struct s3d_scene* scn; struct s3d_device* dev; - struct list_node node, tmp; + struct list_node* node; + struct list_node* tmp; ASSERT(ref); scn = CONTAINER_OF(ref, struct s3d_scene, ref); dev = scn->dev; - LIST_FOR_EACH_SAFE(node, scn->sessions) { + LIST_FOR_EACH_SAFE(node, tmp, &scn->sessions) { session_destroy(CONTAINER_OF(node, struct s3d_session, node)); } htable_shape_release(&scn->shapes); @@ -181,7 +183,6 @@ s3d_scene_detach_shape(struct s3d_scene* scn, struct s3d_shape* shape) { size_t n; unsigned shape_id; - res_T res = RES_OK; if(!scn || !shape) return RES_BAD_ARG; @@ -207,18 +208,13 @@ s3d_scene_clear(struct s3d_scene* scn) struct htable_shape_iterator it, end; if(!scn) return RES_BAD_ARG; - if(scn->session_mask != 0) { - log_error(scn->dev, - "%s: cannot clear a scene with an active session.\n", FUNC_NAME); - return RES_BAD_OP; - } + htable_shape_begin(&scn->shapes, &it); htable_shape_end(&scn->shapes, &end); while(!htable_shape_iterator_eq(&it, &end)) { struct s3d_shape** pshape = htable_shape_iterator_data_get(&it); struct s3d_shape* shape = *pshape; - const res_T res = scene_clear_cached_geometry(scn, shape, FUNC_NAME); - ASSERT(res == RES_OK); (void)res; + SIG_BROADCAST(&scn->sig_shape_detach, scene_shape_cb_T, ARG2(scn, shape)); S3D(shape_ref_put(shape)); htable_shape_iterator_next(&it); } diff --git a/src/s3d_scene_c.h b/src/s3d_scene_c.h @@ -60,16 +60,5 @@ struct s3d_scene { ref_T ref; }; -static FINLINE struct geometry* -scene_get_mesh(struct s3d_scene* scn, const unsigned igeom) -{ - struct geometry* geom; - ASSERT(scn && igeom != RTC_INVALID_GEOMETRY_ID); - 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_session.c b/src/s3d_session.c @@ -90,12 +90,12 @@ on_shape_detach { struct geometry** pgeom; struct geometry* geom; - struct s3d_session* session = data; + struct s3d_session* session = (struct s3d_session*)data; unsigned shape_id; ASSERT(scn && shape && data); S3D(shape_get_id(shape, &shape_id)); - pgeom = htable_geom_find(session->cached_geoms, &shape_id); + pgeom = htable_geom_find(&session->cached_geoms, &shape_id); /* The session did not register a geometry for this shape. Ignore the signal */ if(!pgeom) return; @@ -147,7 +147,7 @@ hit_setup(struct s3d_session* session, const RTCRay* ray, struct s3d_hit* hit) if((unsigned)ray->instID == RTC_INVALID_GEOMETRY_ID) { struct geometry* geom_mesh; ASSERT((unsigned)ray->geomID < darray_geom_size_get(&session->embree2geoms)); - geom_mesh = darray_geom_data_get(&session->embree2geoms)[ray->geomID]; + geom_mesh = session_geometry_from_embree_id(session, ray->geomID); hit->prim.mesh__ = geom_mesh; hit->prim.inst__ = NULL; hit->prim.prim_id = ray->primID; @@ -162,8 +162,9 @@ hit_setup(struct s3d_session* session, const RTCRay* ray, struct s3d_hit* hit) struct geometry* geom_inst; struct geometry* geom_mesh; ASSERT((unsigned)ray->instID < darray_geom_size_get(&session->embree2geoms)); - geom_inst = darray_geom_data_get(&session->embree2geoms)[ray->instID]; - geom_mesh = scene_get_mesh(geom_inst->data.instance->scene, ray->geomID); + geom_inst = session_geometry_from_embree_id(session, ray->instID); + geom_mesh = session_geometry_from_embree_id + (geom_inst->data.instance->session, ray->geomID); hit->prim.mesh__ = geom_mesh; hit->prim.inst__ = geom_inst; hit->prim.prim_id = ray->primID; @@ -261,8 +262,8 @@ embree_geometry_setup_indices } static INLINE void -mebree_geometry_setup_enable_state - (struct s3d_scene* session, struct geometry* geom) +embree_geometry_setup_enable_state + (struct s3d_session* session, struct geometry* geom) { ASSERT(session && geom); if(geom->is_enabled) { @@ -309,8 +310,8 @@ session_setup_embree(struct s3d_session* session) res_T res = RES_OK; ASSERT(session); - htable_shape_begin(&session->cached_geoms, &it); - htable_shape_end(&session->cached_geoms, &end); + htable_geom_begin(&session->cached_geoms, &it); + htable_geom_end(&session->cached_geoms, &end); while(!htable_geom_iterator_eq(&it, &end)) { struct geometry** pgeom = htable_geom_iterator_data_get(&it); @@ -335,14 +336,14 @@ session_setup_embree(struct s3d_session* session) if((geom->embree_outdated_mask & EMBREE_FILTER_FUNCTION) != 0) embree_geometry_setup_filter_function(session, geom); if((geom->embree_outdated_mask & EMBREE_TRANSFORM) != 0) - embree_embree_geometry_setup_transform(session, geom); + embree_geometry_setup_transform(session, geom); geom->embree_outdated_mask = 0; } /* Commit the embree changes */ if(rtc_outdated) { - rtcCommit(session->rtc_session); + rtcCommit(session->rtc_scn); session->rtc_delete_geometry = 0; } @@ -481,7 +482,7 @@ session_register_instance } /* Recursively create a session on the scene to instantiate */ - res = s3d_scene_create_session + res = s3d_session_create (shape->data.instance->scene, session_mask, &instance_session); if(res != RES_OK) goto error; @@ -528,7 +529,7 @@ error: static res_T session_compute_cdf(struct s3d_session* session) { - struct htable_shape_iterator it, end; + struct htable_geom_iterator it, end; size_t len; float area = 0.f; res_T res = RES_OK; @@ -558,12 +559,12 @@ session_compute_cdf(struct s3d_session* session) } break; case GEOM_INSTANCE: - res = scene_compute_cdf(geom->data.instance->scene); + res = session_compute_cdf(geom->data.instance->session); if(res != RES_OK) goto error; - len = darray_fltui_size_get(&geom->data.instance->scene->cdf); + len = darray_fltui_size_get(&geom->data.instance->session->cdf); if(len) { area += darray_fltui_cdata_get - (&geom->data.instance->scene->cdf)[len - 1].flt; + (&geom->data.instance->session->cdf)[len - 1].flt; } break; default: FATAL("Unreachable code\n"); break; @@ -587,7 +588,7 @@ session_compute_nprims_cdf (struct s3d_session* session, const char store_cdf) { - struct htable_shape_iterator it, end; + struct htable_geom_iterator it, end; size_t len; unsigned nprims; res_T res = RES_OK; @@ -596,13 +597,14 @@ session_compute_nprims_cdf darray_nprims_cdf_clear(&session->nprims_cdf); htable_geom_begin(&session->cached_geoms, &it); - htable_geom_end(&session->shapes, &end); + htable_geom_end(&session->cached_geoms, &end); nprims = 0; while(!htable_geom_iterator_eq(&it, &end)) { const unsigned* shape_id = htable_geom_iterator_key_get(&it); struct geometry** pgeom = htable_geom_iterator_data_get(&it); struct geometry* geom = *pgeom; + struct nprims_cdf cdf; htable_geom_iterator_next(&it); @@ -615,12 +617,14 @@ session_compute_nprims_cdf nprims += (unsigned)len; break; case GEOM_INSTANCE: - res = scene_compute_nprims_cdf(geom->data.instance->scene, store_cdf); + res = session_compute_nprims_cdf + (geom->data.instance->session, store_cdf); if(res != RES_OK) goto error; - len = darray_nprims_cdf_size_get(&geom->data.instance->scene->nprims_cdf); + len = darray_nprims_cdf_size_get + (&geom->data.instance->session->nprims_cdf); if(len) { nprims += darray_nprims_cdf_cdata_get - (&geom->data.instance->scene->nprims_cdf)[len - 1].nprims; + (&geom->data.instance->session->nprims_cdf)[len - 1].nprims; } break; default: FATAL("Unreachable code\n"); break; @@ -629,31 +633,31 @@ session_compute_nprims_cdf cdf.nprims = nprims; cdf.ishape = *shape_id; if(store_cdf && len) { - res = darray_nprims_cdf_push_back(&scn->nprims_cdf, &cdf); + res = darray_nprims_cdf_push_back(&session->nprims_cdf, &cdf); if(res != RES_OK) goto error; } } exit: return res; error: - darray_nprims_cdf_clear(&scn->nprims_cdf); + darray_nprims_cdf_clear(&session->nprims_cdf); goto exit; } static void session_compute_scene_aabb(struct s3d_session* session) { - struct htable_shape_iterator it, end; + struct htable_geom_iterator it, end; float lower[3], upper[3]; - ASSERT(session->lower[0] == FLT_MAX && session->upper[0] = -FLT_MAX); - ASSERT(session->lower[1] == FLT_MAX && session->upper[1] = -FLT_MAX); - ASSERT(session->lower[2] == FLT_MAX && session->upper[2] = -FLT_MAX); + ASSERT(session->lower[0] == FLT_MAX && session->upper[0] == -FLT_MAX); + ASSERT(session->lower[1] == FLT_MAX && session->upper[1] == -FLT_MAX); + ASSERT(session->lower[2] == FLT_MAX && session->upper[2] == -FLT_MAX); - htable_shape_begin(&session->cached_geoms, &it); - htable_shape_end(&session->cached_geoms, &end); + htable_geom_begin(&session->cached_geoms, &it); + htable_geom_end(&session->cached_geoms, &end); - while(!htable_shape_iterator_eq(&it, &end)) { + while(!htable_geom_iterator_eq(&it, &end)) { struct instance* inst; struct geometry** pgeom = htable_geom_iterator_data_get(&it); struct geometry* geom = *pgeom; @@ -666,10 +670,10 @@ session_compute_scene_aabb(struct s3d_session* session) case GEOM_MESH: mesh_compute_aabb(geom->data.mesh, lower, upper); break; case GEOM_INSTANCE: inst = geom->data.instance; - scene_compute_aabb(inst->scene); + session_compute_scene_aabb(inst->session); /* Transform local scene AABB in world space */ - f33_mulf3(lower, inst->transform, inst->scene->lower); - f33_mulf3(upper, inst->transform, inst->scene->upper); + f33_mulf3(lower, inst->transform, inst->session->lower); + f33_mulf3(upper, inst->transform, inst->session->upper); f3_add(lower, inst->transform + 9, lower); f3_add(upper, inst->transform + 9, upper); break; @@ -680,7 +684,52 @@ session_compute_scene_aabb(struct s3d_session* session) } } -static void +float +session_compute_volume + (struct s3d_session* session, + const char flip_surface) +{ + struct htable_geom_iterator it, end; + float volume; + + ASSERT(!session); + htable_geom_begin(&session->cached_geoms, &it); + htable_geom_end(&session->cached_geoms, &end); + + volume = 0.f; + while(!htable_geom_iterator_eq(&it, &end)) { + struct geometry** pgeom = htable_geom_iterator_data_get(&it); + struct geometry* geom = *pgeom; + const char flip = geom->flip_surface ^ flip_surface; + + htable_geom_iterator_next(&it); + + if(!geom->is_enabled) continue; + + switch(geom->type) { + case GEOM_MESH: + volume += mesh_compute_volume(geom->data.mesh, flip); + break; + case GEOM_INSTANCE: + volume += session_compute_volume(geom->data.instance->session, flip); + break; + default: FATAL("Unreachable code\n"); break; + } + } + + if(volume < 0.f) { + log_warning(session->scn->dev, +"%s:\n" +"\tthe volume is negative. The scene shapes might not represent closed 2D\n" +"\tmanifold volumes, or their surface normal might not point inward the volume.\n", + FUNC_NAME); + } + + return volume; +} + + +static res_T session_sync (struct s3d_session* session, const int mask) @@ -723,7 +772,7 @@ session_sync if(res != RES_OK) goto error; } /* Setup the scene for the scene_primitive_id/S3D_GET_PRIMITIVE session */ - res = scene_compute_nprims_cdf(scn, (mask & S3D_GET_PRIMITIVE)!=0); + res = session_compute_nprims_cdf(session, (mask & S3D_GET_PRIMITIVE)!=0); if(res != RES_OK) goto error; session->mask = mask; @@ -747,11 +796,13 @@ session_create(struct s3d_scene* scn, struct s3d_session** out_session) list_del(&session->node); ref_get(&session->ref); } else { - const int rtc_mask = + const RTCSceneFlags rtc_scene_mask = RTC_SCENE_DYNAMIC | RTC_SCENE_INCOHERENT - | RTC_SCENE_ROBUST - | RTC_INTERSECT1; + | RTC_SCENE_ROBUST; + const RTCAlgorithmFlags rtc_algorithm_mask = + RTC_INTERSECT1 + | RTC_INTERSECT4; session = (struct s3d_session*)MEM_CALLOC (scn->dev->allocator, 1, sizeof(struct s3d_session)); @@ -768,7 +819,8 @@ session_create(struct s3d_scene* scn, struct s3d_session** out_session) f3_splat(session->upper,-FLT_MAX); ref_init(&session->ref); - session->rtc_scn = rtcDeviceNewScene(scn->dev->rtc, rtc_mask); + session->rtc_scn = rtcDeviceNewScene + (scn->dev->rtc, rtc_scene_mask, rtc_algorithm_mask); if(!session->rtc_scn) { res = RES_MEM_ERR; goto error; @@ -795,12 +847,9 @@ session_release(ref_T* ref) { struct htable_geom_iterator it, end; struct s3d_session* session = CONTAINER_OF(ref, struct s3d_session, ref); - struct s3d_scene* scn; size_t i, n; ASSERT(ref); - scn = session->scn; - /* Release the session of the instances */ htable_geom_begin(&session->cached_geoms, &it); htable_geom_end(&session->cached_geoms, &end); @@ -820,9 +869,9 @@ session_release(ref_T* ref) /* Remove the geometry of the shapes detached while the session was active */ n = darray_uint_size_get(&session->detached_shapes); FOR_EACH(i, 0, n) { - const unsigned spape_id = darray_uint_cdata_get(&session->detached_shapes); - struct geomtry** pgeom = htable_geom_find(&session->cached_geoms, &shape_id); - struct geomtry* geom = *pgeom; + const unsigned shape_id = darray_uint_cdata_get(&session->detached_shapes)[i]; + struct geometry** pgeom = htable_geom_find(&session->cached_geoms, &shape_id); + struct geometry* geom = *pgeom; session_destroy_geometry(session, geom); } darray_uint_clear(&session->detached_shapes); @@ -832,15 +881,14 @@ session_release(ref_T* ref) darray_geom_clear(&session->embree2geoms); darray_fltui_clear(&session->cdf); darray_nprims_cdf_clear(&session->nprims_cdf); - darray_session_clear(&session->instances); f3_splat(session->lower, FLT_MAX); f3_splat(session->upper,-FLT_MAX); - session->mask = NULL; + session->mask = 0; /* Do not physically release the memory space of the session. Add it to the * available sessions pool of the scene */ - list_add(scn->sessions, &session->node); - S3D(scene_ref_put(scn)); + list_add(&session->scn->sessions, &session->node); + S3D(scene_ref_put(session->scn)); } /******************************************************************************* @@ -922,7 +970,7 @@ s3d_session_trace_ray if(!session || !org || !dir || !range || !hit) return RES_BAD_ARG; if(!f3_is_normalized(dir)) { - log_error(session->dev, + log_error(session->scn->dev, "%s: unnormalized ray direction {%g, %g, %g}.\n", FUNC_NAME, SPLIT3(dir)); return RES_BAD_ARG; @@ -1223,8 +1271,7 @@ s3d_session_primitives_count(struct s3d_session* session, size_t* prims_count) htable_geom_begin(&session->cached_geoms, &it); htable_geom_end(&session->cached_geoms, &end); *prims_count = 0; - while(!htable_shape_iterator_eq(&it, &end)) { - const unsigned* shape_id = htable_geom_iterator_key_get(&it); + while(!htable_geom_iterator_eq(&it, &end)) { struct geometry** pgeom = htable_geom_iterator_data_get(&it); struct geometry* geom = *pgeom; htable_geom_iterator_next(&it); @@ -1277,8 +1324,7 @@ s3d_session_compute_area(struct s3d_session* session, float* out_area) htable_geom_end(&session->cached_geoms, &end); area = 0.f; - while(!htable_shape_iterator_eq(&it, &end)) { - const unsigned* shape_id = htable_geom_iterator_key_get(&it); + while(!htable_geom_iterator_eq(&it, &end)) { struct geometry** pgeom = htable_geom_iterator_data_get(&it); struct geometry* geom = *pgeom; @@ -1311,52 +1357,9 @@ error: res_T s3d_session_compute_volume(struct s3d_session* session, float* out_volume) { - struct htable_geom_iterator it, end; - float volume; - res_T res = RES_OK; - - if(!session || !out_volume) { - res = RES_BAD_ARG; - goto error; - } - htable_geom_begin(&session->shapes, &it); - htable_geom_end(&session->shapes, &end); - - volume = 0.f; - while(!htable_shape_iterator_eq(&it, &end)) { - const unsigned* shape_id = htable_geom_iterator_key_get(&it); - struct geometry** pgeom = htable_geom_iterator_data_get(&it); - struct geometry* geom = *pgeom; - - htable_geom_iterator_next(&it); - - if(!geom->is_enabled) continue; - - switch(geom->type) { - case GEOM_MESH: - volume += mesh_compute_volume(geom->data.mesh, geom->flip_surface); - break; - case GEOM_INSTANCE: - volume += instance_compute_volume(geom->data.instance, geom->flip_surface); - break; - default: FATAL("Unreachable code\n"); break; - } - } - - if(volume < 0.f) { - log_warning(session->scn->dev, -"%s:\n" -"\tthe volume is negative. The scene shapes might not represent closed 2D\n" -"\tmanifold volumes, or their surface normal might not point inward the volume.\n", - FUNC_NAME); - } - -exit: - if(out_volume) *out_volume = volume; - return res; -error: - volume = -1.f; - goto exit; + if(!session || !out_volume) return RES_BAD_ARG; + *out_volume = session_compute_volume(session, 0/*No initial flip_surface*/); + return RES_OK; } res_T @@ -1403,6 +1406,6 @@ session_destroy(struct s3d_session* session) CLBK_DISCONNECT(&session->on_shape_detach_cb); /* Free the session memory space */ - MEM_RM(session->scn->allocator, session); + MEM_RM(session->scn->dev->allocator, session); } diff --git a/src/s3d_session_c.h b/src/s3d_session_c.h @@ -99,7 +99,7 @@ struct s3d_session { int rtc_delete_geometry; /* Define if Embree geometries were deleted */ RTCScene rtc_scn; /* Embree scene */ - struct ref_T ref; + ref_T ref; struct s3d_scene* scn; }; @@ -107,5 +107,18 @@ extern LOCAL_SYM void session_destroy (struct s3d_session* session); +static FINLINE struct geometry* +session_geometry_from_embree_id + (struct s3d_session* session, + const unsigned irtc) +{ + struct geometry* geom; + ASSERT(session && irtc != RTC_INVALID_GEOMETRY_ID); + ASSERT(irtc < darray_geom_size_get(&session->embree2geoms)); + geom = darray_geom_data_get(&session->embree2geoms)[irtc]; + ASSERT(geom); + return geom; +} + #endif /* S3D_SESSION_C_H */ diff --git a/src/s3d_shape.c b/src/s3d_shape.c @@ -158,7 +158,7 @@ s3d_shape_ref_put(struct s3d_shape* shape) } res_T -s3d_shape_get_id(struct s3d_shape* shape, unsigned* id) +s3d_shape_get_id(const struct s3d_shape* shape, unsigned* id) { if(!shape || !id) return RES_BAD_ARG; *id = shape->id.index;