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 4fae190e507ceea73f6b0ce7b413dd0846f8d1ee
parent 789f7e128efcac1a7182cb99d60e413c346a4a46
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Mon, 16 Mar 2015 16:48:36 +0100

Refactoring of the description of a Mesh

Diffstat:
Msrc/s3d.h | 91+++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/s3d_scene.c | 5+++--
Msrc/s3d_shape.c | 347+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Msrc/s3d_shape_c.h | 5++---
Msrc/test_s3d_cbox.h | 15++++++++-------
Msrc/test_s3d_scene.c | 2+-
Msrc/test_s3d_shape.c | 165++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
7 files changed, 366 insertions(+), 264 deletions(-)

diff --git a/src/s3d.h b/src/s3d.h @@ -54,50 +54,43 @@ #define S3D(Func) s3d_ ## Func #endif +#define S3D_KEEP NULL + /* Attributes of a shape */ -enum s3d_shape_attrib { - S3D_SHAPE_POSITION, /* World space position */ - S3D_SHAPE_SHADING_NORMAL, /* World space interpolated vertex normal */ - S3D_SHAPE_GEOMETTRY_NORMAL, /* World space face normal */ - S3D_SHAPE_UV /* Parametric coordinates */ +enum s3d_attrib_usage { + S3D_POSITION, /* World space position */ + S3D_ATTRIB_0, /* Generic attrib 0 */ + S3D_ATTRIB_1, /* Generic attrib 1 */ + S3D_ATTRIB_2, /* Generic attrib 2 */ + S3D_ATTRIB_3, /* Generic attrib 3 */ + S3D_ATTRIBS_COUNT__, + S3D_GEOMETRY_NORMAL /* World space face normal */ }; enum s3d_type { S3D_FLOAT, S3D_FLOAT2, - S3D_FLOAT3 + S3D_FLOAT3, + S3D_FLOAT4 }; struct s3d_attrib { float value[4]; enum s3d_type type; + enum s3d_attrib_usage usage; }; -/* Descriptor of a triangular mesh */ -struct s3d_trimesh_desc { - /* # triangles. May be NULL if get_indices is NULL */ - unsigned (*get_tricount)(void*); - /* Get the 3 vertex indices of the triangle `itri'. May be NULL if the shape - * was already setuped as a triangular mesh <=> does not update the shape - * indices */ - void (*get_indices)(const unsigned itri, unsigned ids[3], void*); - /* Get the 3D position of the vertex `ivert'. May be NULL if the shape was - * already setuped as a triangular mesh <=> does not update the shape - * coordinates */ - void (*get_position)(const unsigned ivert, float position[3], void*); - /* Get the world space normal of `ivert'. May be NULL <=> does not setup - * normals data to the shape or does not update them */ - void (*get_normal)(const unsigned ivert, float normal[3], void*); - /* Get the parametric coordinates of `ivert'. May be NULL <=> does not setup - * uvs data to the shape or does not update them */ - void (*get_uv)(const unsigned ivert, float uv[2], void*); - /* Pointer to user data; last argument of the previous callbacks */ - void* data; +struct s3d_vertex_data { + enum s3d_attrib_usage usage; + enum s3d_type type; + void (*get) + (const unsigned ivert, /* Index of the vertex */ + float* value, /* Retrieved attrib value */ + void* ctx); /* Pointer to user data */ }; -static const struct s3d_trimesh_desc S3D_TRIMESH_DESC_NULL = { - NULL, NULL, NULL, NULL, NULL, NULL -}; +static const struct s3d_vertex_data S3D_VERTEX_DATA_NULL = +{ S3D_ATTRIBS_COUNT__, S3D_FLOAT, NULL }; /* Intersection point */ struct s3d_hit { @@ -201,11 +194,16 @@ s3d_scene_trace_ray * Shape API - A shape defines a geometry that can be attached to *one* scene. ******************************************************************************/ S3D_API res_T -s3d_shape_create +s3d_shape_create_mesh (struct s3d_device* dev, struct s3d_shape** shape); S3D_API res_T +s3d_shape_create_group + (struct s3d_device* dev, + struct s3d_shape **shape); + +S3D_API res_T s3d_shape_ref_get (struct s3d_shape* shape); @@ -220,21 +218,6 @@ s3d_shape_enable (struct s3d_shape* shape, const char enable); -/* Setup the shape from a triangular mesh descriptor. The data retrieved - * through the mesh descriptor must be valid until the end of the function - * call */ -S3D_API res_T -s3d_shape_setup_trimesh - (struct s3d_shape* shape, - const struct s3d_trimesh_desc* desc); - -/* Setup the shape from a scene. Actually the resulting shape is an instance of - * the scene */ -S3D_API res_T -s3d_shape_setup_scene - (struct s3d_shape* shape, - struct s3d_scene* scene); - /* Remove the shape from the scene on which it is attached. No error is * reported if the shape is not attached to a scene. After its detachment, the * scene release its reference on the shape */ @@ -252,7 +235,7 @@ s3d_shape_set_transform S3D_API res_T s3d_shape_get_attrib (struct s3d_shape* shape, - const enum s3d_shape_attrib attr, /* Attribute to retrieve */ + const enum s3d_attrib_usage attr, /* Attribute to retrieve */ const unsigned iprim, /* Id of the primitive on which `attr' is retrieved */ const float uv[2], /* Barycentric coordinates of `attr' on `iprim' */ struct s3d_attrib* attrib); /* Resulting attrib */ @@ -266,6 +249,22 @@ s3d_shape_sample unsigned* iprim, /* Sampled primitive */ float uv[2]); /* Sampled barycentric coordinate onto `iprim' */ +S3D_API res_T +s3d_shape_mesh_setup_indexed_vertices + (struct s3d_shape* shape, + const unsigned ntris, + void (*get_indices)(const unsigned itri, unsigned ids[3], void* ctx), + const unsigned nverts, + struct s3d_vertex_data attribs[], + void* data); + +/* Setup the shape from a scene. Actually the resulting shape is an instance of + * the scene */ +S3D_API res_T +s3d_shape_group_setup_scene + (struct s3d_shape* shape, + struct s3d_scene* scene); + END_DECLS #endif /* S3D_H */ diff --git a/src/s3d_scene.c b/src/s3d_scene.c @@ -56,9 +56,10 @@ scene_setup(struct s3d_scene* scn) struct s3d_shape* shape = CONTAINER_OF (node, struct s3d_shape, scene_attachment); uint32_t* ids = darray_u32_data_get(&shape->data.mesh.indices); - float* pos = darray_float_data_get(&shape->data.mesh.positions); + float* pos = darray_float_data_get(&shape->data.mesh.attribs[S3D_POSITION]); const size_t ntris = darray_u32_size_get(&shape->data.mesh.indices)/3; - const size_t nverts = darray_float_size_get(&shape->data.mesh.positions)/3; + const size_t nverts = darray_float_size_get + (&shape->data.mesh.attribs[S3D_POSITION])/3; ASSERT(IS_ALIGNED(ids, 16)); /* The Embree geometry is no more valid */ diff --git a/src/s3d_shape.c b/src/s3d_shape.c @@ -39,6 +39,19 @@ /******************************************************************************* * Helper functions ******************************************************************************/ +static INLINE size_t +get_s3d_type_dimension(const enum s3d_type type) +{ + switch(type) { + case S3D_FLOAT: return 1; + case S3D_FLOAT2: return 2; + case S3D_FLOAT3: return 3; + case S3D_FLOAT4: return 4; + default: FATAL("Unreachable code\n"); break; + } + return 0; +} + static FINLINE void shape_delete_rtc_geometry(struct s3d_shape* shape) { @@ -50,102 +63,97 @@ shape_delete_rtc_geometry(struct s3d_shape* shape) static void mesh_init(struct mem_allocator* allocator, struct mesh* mesh) { + int iattr; ASSERT(mesh); darray_u32_init(allocator, &mesh->indices); - darray_float_init(allocator, &mesh->positions); - darray_float_init(allocator, &mesh->normals); - darray_float_init(allocator, &mesh->uvs); + FOR_EACH(iattr, 0, S3D_ATTRIBS_COUNT__) { + darray_float_init(allocator, &mesh->attribs[iattr]); + mesh->attribs_type[iattr] = S3D_FLOAT; + } + /* The vertex positions are always float3 */ + mesh->attribs_type[S3D_POSITION] = S3D_FLOAT3; + mesh->update_mask = mesh->resize_mask = 0; } static void mesh_release(struct mesh* mesh) { + int iattr; ASSERT(mesh); darray_u32_release(&mesh->indices); - darray_float_release(&mesh->positions); - darray_float_release(&mesh->normals); - darray_float_release(&mesh->uvs); + FOR_EACH(iattr, 0, S3D_ATTRIBS_COUNT__) { + darray_float_release(&mesh->attribs[iattr]); + } } -static res_T +static void mesh_setup_indices (struct mesh* mesh, - const struct s3d_trimesh_desc* desc, - unsigned* nvertices) + const unsigned ntris, + void (*get_indices)(const unsigned itri, unsigned ids[3], void*), + const unsigned nverts, + void* data) { uint32_t* indices; - unsigned itri, ntris, nids, nids_prev, nverts; + unsigned itri; + unsigned nids, nids_prev; + unsigned nverts_new; res_T res; - ASSERT(mesh && desc && nvertices); + ASSERT(mesh && ntris && get_indices && nverts); + nids = ntris * 3; nids_prev = darray_u32_size_get(&mesh->indices); - if(!desc->get_indices) { - if(!nids_prev) { /* The indices were not previously setuped */ - return RES_BAD_ARG; - } else { /* Keep the previously setuped indices */ - nverts = darray_float_size_get(&mesh->positions); - ASSERT(nverts % 3 == 0); - *nvertices = nverts / 3; - return RES_OK; - } - } + ASSERT(get_indices != S3D_KEEP || nids == nids_prev); - if(!desc->get_tricount) - return RES_BAD_ARG; - - ntris = desc->get_tricount(desc->data); - if(!ntris) - return RES_BAD_ARG; + if(get_indices == S3D_KEEP) { + ASSERT(nids == nids_prev); + return; + } - nids = ntris * 3; if(nids == nids_prev) { mesh->update_mask |= (MESH_INDEX_BUFFER & !mesh->resize_mask); } else { mesh->resize_mask |= MESH_INDEX_BUFFER; mesh->update_mask &= !MESH_INDEX_BUFFER; res = darray_u32_resize(&mesh->indices, nids); - if(res != RES_OK) return res; + if(res != RES_OK) FATAL("Unsufficient memory\n"); } /* Setup the mesh indices */ indices = darray_u32_data_get(&mesh->indices); - nverts = 0; + nverts_new = 0; FOR_EACH(itri, 0, ntris) { uint32_t* ids = indices + itri*3; int i; STATIC_ASSERT(sizeof(unsigned) == sizeof(uint32_t), Unexpected_Type); - desc->get_indices(itri, ids, desc->data); - FOR_EACH(i, 0, 3) if(ids[i] >= nverts) nverts = ids[i]; + get_indices(itri, ids, data); + FOR_EACH(i, 0, 3) nverts_new = MMAX(nverts_new, ids[i]); } - /* Transform nverts from last vertex id to vertices count */ - *nvertices = nverts + 1; - return RES_OK; + /* Transform nverts from the last vertex id to vertices count */ + ++nverts_new; + if(nverts_new > nverts) + FATAL("Out of bound indexation\n"); } -static res_T +static void mesh_setup_positions (struct mesh* mesh, - const struct s3d_trimesh_desc* desc, - const unsigned nverts) + const unsigned nverts, + struct s3d_vertex_data* attr, + void* data) { float* positions; - unsigned i, nverts_prev; + unsigned ivert, nverts_prev; res_T res; - ASSERT(mesh && desc && nverts); + ASSERT(mesh && nverts && attr && attr->usage == S3D_POSITION); - nverts_prev = darray_float_size_get(&mesh->positions); + nverts_prev = darray_float_size_get(&mesh->attribs[S3D_POSITION]); ASSERT(nverts_prev % 3 == 0); nverts_prev /= 3; - - if(!desc->get_position) { - if(!nverts_prev) { /* The vertex positions were not already setuped */ - return RES_BAD_ARG; - } else if(nverts != nverts_prev) { /* Inconsistant descriptor */ - return RES_BAD_ARG; - } else { /* Keep the previous positions */ - return RES_OK; - } + if(attr->get == S3D_KEEP) { + ASSERT(nverts == nverts_prev); + return; } /* Allocate vertex positions */ @@ -154,122 +162,79 @@ mesh_setup_positions } else { mesh->resize_mask |= MESH_VERTEX_BUFFER; mesh->update_mask &= !MESH_VERTEX_BUFFER; /* The vertices are no more updated */ - res = darray_float_resize(&mesh->positions, nverts*3); - if(res != RES_OK) return res; + res = darray_float_resize(&mesh->attribs[S3D_POSITION], nverts*3); + if(res != RES_OK) FATAL("Unsufficient memory\n"); } /* Setup the vertex positions */ - positions = darray_float_data_get(&mesh->positions); - memset(positions, 0xFF, sizeof(float[3])*nverts); - FOR_EACH(i, 0, darray_u32_size_get(&mesh->indices)) { - union { float f; uint32_t i; } ucast; - const unsigned ivert = darray_u32_cdata_get(&mesh->indices)[i]; - const unsigned ipos = ivert * 3; - - ucast.f = positions[ipos]; - if(ucast.i == 0xFFFFFFFF) /* The vertex was not setuped */ - desc->get_position(ivert, positions + ipos, desc->data); - } - return RES_OK; -} - -static res_T -mesh_setup_normals - (struct mesh* mesh, - const struct s3d_trimesh_desc* desc, - const unsigned nverts) -{ - float* normals; - unsigned i, nverts_prev; - res_T res; - ASSERT(mesh && desc && nverts); - - nverts_prev = darray_float_size_get(&mesh->normals); - ASSERT(nverts_prev % 3 == 0); - nverts_prev /= 3; - - if(!desc->get_normal) { - if(nverts_prev && nverts != nverts_prev) { /* Inconsistant descriptor */ - return RES_BAD_ARG; - } else { /* Keep the previous normals or do not setup them */ - return RES_OK; + positions = darray_float_data_get(&mesh->attribs[S3D_POSITION]); + if(attr->type == S3D_FLOAT3) { + FOR_EACH(ivert, 0, nverts) { + attr->get(ivert, positions + ivert*3, data); + } + } else { + FOR_EACH(ivert, 0, nverts) { + float pos[4]; + unsigned ipos = ivert * 3; + attr->get(ivert, pos, data); + switch(attr->type) { + case S3D_FLOAT: + positions[ipos + 0] = pos[0]; + positions[ipos + 1] = 0.f; + positions[ipos + 2] = 0.f; + break; + case S3D_FLOAT2: + positions[ipos + 0] = pos[0]; + positions[ipos + 1] = pos[1]; + positions[ipos + 2] = 0.f; + break; + case S3D_FLOAT4: /* Homogeneous coordinates */ + positions[ipos + 0] = pos[0] / pos[3]; + positions[ipos + 1] = pos[1] / pos[3]; + positions[ipos + 2] = pos[2] / pos[3]; + break; + default: FATAL("Unreachable code\n"); break; + } } } - - res = darray_float_resize(&mesh->normals, nverts*3); - if(res != RES_OK) return res; - - /* Setup the vertex normals */ - normals = darray_float_data_get(&mesh->normals); - memset(normals, 0xFF, sizeof(float[3])*nverts); - FOR_EACH(i, 0, darray_u32_size_get(&mesh->indices)) { - union { float f; uint32_t i; } ucast; - const unsigned ivert = darray_u32_cdata_get(&mesh->indices)[i]; - const unsigned inormal = ivert * 3; - - ucast.f = normals[inormal]; - if(ucast.i == 0xFFFFFFFF) /* The normal was not setuped */ - desc->get_normal(ivert, normals + inormal, desc->data); - } - return RES_OK; } -static res_T -mesh_setup_uvs +static void +mesh_setup_attribs (struct mesh* mesh, - const struct s3d_trimesh_desc* desc, - const unsigned nverts) + const unsigned nverts, + const struct s3d_vertex_data* attr, + void* data) { - float* uvs; - unsigned i, nverts_prev; + float* attr_data; + size_t attr_dimension; + unsigned ivert, nverts_prev; res_T res; - ASSERT(mesh && desc && nverts); - - nverts_prev = darray_float_size_get(&mesh->uvs); - ASSERT(nverts_prev % 2 == 0); - nverts_prev /= 2; - - if(!desc->get_uv) { - if(nverts_prev && nverts != nverts_prev) { /* Inconsistant descriptor */ - return RES_BAD_ARG; - } else { /* Keep the previous normals or do not setup them */ - return RES_OK; - } + ASSERT(mesh && nverts && attr); + ASSERT(attr->usage >= S3D_ATTRIB_0 && attr->usage < S3D_ATTRIBS_COUNT__); + + nverts_prev = darray_float_size_get(&mesh->attribs[attr->usage]); + attr_dimension = get_s3d_type_dimension(mesh->attribs_type[attr->usage]); + ASSERT(nverts_prev % attr_dimension == 0); + nverts_prev /= attr_dimension; + + if(attr->get == S3D_KEEP) { + ASSERT(mesh->attribs_type[attr->usage] == attr->type); + ASSERT(nverts == nverts_prev); + return; } - res = darray_float_resize(&mesh->uvs, nverts*2); - if(res != RES_OK) return res; + attr_dimension = get_s3d_type_dimension(attr->type); + res = darray_float_resize(&mesh->attribs[attr->usage], nverts*attr_dimension); + if(res != RES_OK) FATAL("Unsufficient memory\n"); - /* Setup the vertex normals */ - uvs = darray_float_data_get(&mesh->uvs); - memset(uvs, 0xFF, sizeof(float[2])*nverts); - FOR_EACH(i, 0, darray_u32_size_get(&mesh->indices)) { - union { float f; uint32_t i; } ucast; - const unsigned ivert = darray_u32_cdata_get(&mesh->indices)[i]; - const unsigned iuv = ivert * 3; - - ucast.f = uvs[iuv]; - if(ucast.i == 0xFFFFFFFF) /* The normal was not setuped */ - desc->get_uv(ivert, uvs + iuv, desc->data); + /* Setup the vertex attrib */ + attr_data = darray_float_data_get(&mesh->attribs[attr->usage]); + FOR_EACH(ivert, 0, nverts) { + attr->get(ivert, attr_data, data); + attr_data += attr_dimension; } - return RES_OK; -} - -static res_T -mesh_setup(struct mesh* mesh, const struct s3d_trimesh_desc* desc) -{ - unsigned nverts; - res_T res = RES_OK; - - res = mesh_setup_indices(mesh, desc, &nverts); - if(res != RES_OK) return res; - res = mesh_setup_positions(mesh, desc, nverts); - if(res != RES_OK) return res; - res = mesh_setup_normals(mesh, desc, nverts); - if(res != RES_OK) return res; - res = mesh_setup_uvs(mesh, desc, nverts); - if(res != RES_OK) return res; - return RES_OK; + mesh->attribs_type[attr->usage] = attr->type; } static void @@ -278,7 +243,7 @@ shape_release_data(struct s3d_shape* shape) ASSERT(shape); switch(shape->type) { case SHAPE_MESH: mesh_release(&shape->data.mesh); break; - case SHAPE_NONE: /* DO nothing */ break; + case SHAPE_NONE: /* Do nothing */ break; default: FATAL("Unreachable code\n"); break; } shape->type = SHAPE_NONE; @@ -306,7 +271,8 @@ shape_release(ref_T* ref) * Exported s3d_shape functions: ******************************************************************************/ res_T -s3d_shape_create(struct s3d_device* dev, struct s3d_shape** out_shape) +s3d_shape_create_mesh + (struct s3d_device* dev, struct s3d_shape** out_shape) { struct s3d_shape* shape = NULL; res_T res = RES_OK; @@ -322,7 +288,8 @@ s3d_shape_create(struct s3d_device* dev, struct s3d_shape** out_shape) goto error; } list_init(&shape->scene_attachment); - shape->type = SHAPE_NONE; + mesh_init(dev->allocator, &shape->data.mesh); + shape->type = SHAPE_MESH; shape->rtc_geom = INVALID_RTC_GEOMETRY; S3D(device_ref_get(dev)); shape->dev = dev; @@ -371,30 +338,78 @@ s3d_shape_detach(struct s3d_shape* shape) } res_T -s3d_shape_setup_trimesh +s3d_shape_mesh_setup_indexed_vertices (struct s3d_shape* shape, - const struct s3d_trimesh_desc* desc) + const unsigned ntris, + void (*get_indices)(const unsigned itri, unsigned ids[3], void* ctx), + const unsigned nverts, + struct s3d_vertex_data attribs[], + void* data) { + uint32_t* indices; + unsigned itri; + unsigned nids, nids_prev; + unsigned iattr; + unsigned nverts_check, nverts_prev; + char has_position = 0; res_T res = RES_OK; - if(!shape || !desc) { + if(!shape || shape->type != SHAPE_MESH || !ntris || !nverts || !attribs) { res = RES_BAD_ARG; goto error; } - if(shape->type != SHAPE_MESH) { - shape_release_data(shape); - mesh_init(shape->dev->allocator, &shape->data.mesh); - shape->type = SHAPE_MESH; + /* Check indices description */ + if(get_indices == S3D_KEEP) { + const unsigned nids_prev = darray_u32_size_get(&shape->data.mesh.indices); + const unsigned ntris_prev = nids_prev / 3; + if(ntris_prev != ntris) { /* Inconsistant data */ + res = RES_BAD_ARG; + goto error; + } } - res = mesh_setup(&shape->data.mesh, desc); - if(res != RES_OK) goto error; + /* Check the vertex data description */ + iattr = 0; + has_position = 0; + do { + if(attribs[iattr].get == S3D_KEEP) { + const enum s3d_attrib_usage attr_usage = attribs[iattr].usage; + const enum s3d_type type = attribs[iattr].type; + const enum s3d_type type_prev = shape->data.mesh.attribs_type[attr_usage]; + const struct darray_float* attr = shape->data.mesh.attribs + attr_usage; + size_t nverts_prev = darray_float_size_get(attr); + nverts_prev /= get_s3d_type_dimension(type_prev); + if(type_prev != type || nverts_prev != nverts) { /* Inconsistant data */ + res = RES_BAD_ARG; + goto error; + } + } + if(attribs[iattr].usage == S3D_POSITION) + has_position = 1; + ++iattr; + } while(attribs[iattr].usage != S3D_ATTRIBS_COUNT__); + + if(!has_position) { /* The vertex must have a position */ + res = RES_BAD_ARG; + goto error; + } + + /* Setup indices */ + if(get_indices != S3D_KEEP) { + mesh_setup_indices(&shape->data.mesh, ntris, get_indices, nverts, data); + } + /* Setup vertex data */ + for(iattr = 0; attribs[iattr].usage != S3D_ATTRIBS_COUNT__; ++iattr) { + if(attribs[iattr].usage == S3D_POSITION) { + mesh_setup_positions(&shape->data.mesh, nverts, attribs + iattr, data); + } else { + mesh_setup_attribs(&shape->data.mesh, nverts, attribs + iattr, data); + } + } exit: return res; error: - if(shape && desc) - shape_release_data(shape); goto exit; } diff --git a/src/s3d_shape_c.h b/src/s3d_shape_c.h @@ -56,9 +56,8 @@ enum shape_type { struct mesh { /* Triangular mesh */ darray_u32 indices; - darray_float positions; /* list of 3 floats */ - darray_float normals; /* list of 3 floats */ - darray_float uvs; /* list of 2 floats */ + darray_float attribs[S3D_ATTRIBS_COUNT__]; + enum s3d_type attribs_type[S3D_ATTRIBS_COUNT__]; /* Combination of shape_buffer */ int update_mask; /* Define which shape buffers were updated */ diff --git a/src/test_s3d_cbox.h b/src/test_s3d_cbox.h @@ -65,7 +65,7 @@ static const float cbox_verts[] = { 314.0f, 456.0f, 330.f, 472.0f, 406.0f, 330.f }; -const size_t cbox_nverts = sizeof(cbox_verts) / (sizeof(float[3])); +const unsigned cbox_nverts = (unsigned)(sizeof(cbox_verts)/(sizeof(float[3]))); const uint32_t cbox_ids[] = { /* Box */ @@ -87,9 +87,10 @@ const uint32_t cbox_ids[] = { 18, 19, 23, 23, 22, 18, 16, 17, 21, 21, 20, 16 }; -const size_t cbox_nids = sizeof(cbox_ids)/sizeof(uint32_t); +const unsigned cbox_nids = (unsigned)(sizeof(cbox_ids)/sizeof(uint32_t)); +const unsigned cbox_ntris = (unsigned)(sizeof(cbox_ids)/sizeof(uint32_t)/3); -static unsigned +static INLINE unsigned cbox_get_ntris(void* data) { (void)data; @@ -97,7 +98,7 @@ cbox_get_ntris(void* data) return (unsigned)(cbox_nids / 3); } -static void +static INLINE void cbox_get_ids(const unsigned itri, unsigned ids[3], void* data) { const unsigned id = itri * 3; @@ -109,7 +110,7 @@ cbox_get_ids(const unsigned itri, unsigned ids[3], void* data) ids[2] = cbox_ids[id + 2]; } -static void +static INLINE void cbox_get_position(const unsigned ivert, float position[3], void* data) { (void)data; @@ -119,7 +120,7 @@ cbox_get_position(const unsigned ivert, float position[3], void* data) position[2] = cbox_verts[ivert*3 + 2]; } -static void +static INLINE void cbox_get_normal(const unsigned ivert, float normal[3], void* data) { (void)ivert, (void)data; @@ -128,7 +129,7 @@ cbox_get_normal(const unsigned ivert, float normal[3], void* data) normal[2] = 0.f; } -static void +static INLINE void cbox_get_uv(const unsigned ivert, float uv[2], void* data) { (void)ivert, (void)data; diff --git a/src/test_s3d_scene.c b/src/test_s3d_scene.c @@ -48,7 +48,7 @@ main(int argc, char** argv) CHECK(s3d_device_create(NULL, &allocator, &dev), RES_OK); FOR_EACH(i, 0, nshapes) - CHECK(s3d_shape_create(dev, shapes + i), RES_OK); + CHECK(s3d_shape_create_mesh(dev, shapes + i), RES_OK); CHECK(s3d_scene_create(NULL, NULL), RES_BAD_ARG); CHECK(s3d_scene_create(dev, NULL), RES_BAD_ARG); diff --git a/src/test_s3d_shape.c b/src/test_s3d_shape.c @@ -40,55 +40,142 @@ main(int argc, char** argv) struct mem_allocator allocator; struct s3d_device* dev; struct s3d_shape* shape; - struct s3d_trimesh_desc trimesh = S3D_TRIMESH_DESC_NULL; + struct s3d_vertex_data attribs[4]; (void)argc, (void)argv; mem_init_proxy_allocator(&allocator, &mem_default_allocator); CHECK(s3d_device_create(NULL, &allocator, &dev), RES_OK); - CHECK(s3d_shape_create(NULL, NULL), RES_BAD_ARG); - CHECK(s3d_shape_create(dev, NULL), RES_BAD_ARG); - CHECK(s3d_shape_create(NULL, &shape), RES_BAD_ARG); - CHECK(s3d_shape_create(dev, &shape), RES_OK); + CHECK(s3d_shape_create_mesh(NULL, NULL), RES_BAD_ARG); + CHECK(s3d_shape_create_mesh(dev, NULL), RES_BAD_ARG); + CHECK(s3d_shape_create_mesh(NULL, &shape), RES_BAD_ARG); + CHECK(s3d_shape_create_mesh(dev, &shape), RES_OK); CHECK(s3d_shape_detach(NULL), RES_BAD_ARG); CHECK(s3d_shape_detach(shape), RES_OK); - CHECK(s3d_shape_setup_trimesh(NULL, NULL), RES_BAD_ARG); - CHECK(s3d_shape_setup_trimesh(shape, NULL), RES_BAD_ARG); - CHECK(s3d_shape_setup_trimesh(NULL, &trimesh), RES_BAD_ARG); - CHECK(s3d_shape_setup_trimesh(shape, &trimesh), RES_BAD_ARG); - trimesh.get_tricount = cbox_get_ntris; - CHECK(s3d_shape_setup_trimesh(shape, &trimesh), RES_BAD_ARG); - trimesh.get_indices = cbox_get_ids; - CHECK(s3d_shape_setup_trimesh(shape, &trimesh), RES_BAD_ARG); - trimesh.get_position = cbox_get_position; - CHECK(s3d_shape_setup_trimesh(shape, &trimesh), RES_OK); - CHECK(s3d_shape_setup_trimesh(NULL, &trimesh), RES_BAD_ARG); - trimesh.get_normal = cbox_get_normal; - CHECK(s3d_shape_setup_trimesh(shape, &trimesh), RES_OK); - trimesh.get_uv = cbox_get_uv; - CHECK(s3d_shape_setup_trimesh(shape, &trimesh), RES_OK); - - trimesh = S3D_TRIMESH_DESC_NULL; - trimesh.get_tricount = cbox_get_ntris; - trimesh.get_indices = cbox_get_ids; - CHECK(s3d_shape_setup_trimesh(shape, &trimesh), RES_OK); - trimesh.get_tricount = NULL; - trimesh.get_indices = NULL; - trimesh.get_position = cbox_get_position; - CHECK(s3d_shape_setup_trimesh(shape, &trimesh), RES_OK); - trimesh.get_position = NULL; - trimesh.get_normal = cbox_get_normal; - CHECK(s3d_shape_setup_trimesh(shape, &trimesh), RES_OK); - trimesh.get_normal = NULL; - trimesh.get_uv = cbox_get_uv; - CHECK(s3d_shape_setup_trimesh(shape, &trimesh), RES_OK); - - trimesh = S3D_TRIMESH_DESC_NULL; - trimesh.get_indices = cbox_get_ids; - CHECK(s3d_shape_setup_trimesh(shape, &trimesh), RES_BAD_ARG); + attribs[0].type = S3D_FLOAT3; + attribs[0].usage = S3D_POSITION; + attribs[0].get = cbox_get_position; + attribs[1] = S3D_VERTEX_DATA_NULL; + CHECK(s3d_shape_mesh_setup_indexed_vertices + (NULL, 0, NULL, 0, NULL, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, 0, NULL, 0, NULL, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (NULL, cbox_ntris, NULL, 0, NULL, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, cbox_ntris, NULL, 0, NULL, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (NULL, 0, cbox_get_ids, 0, NULL, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, 0, cbox_get_ids, 0, NULL, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (NULL, cbox_ntris, cbox_get_ids, 0, NULL, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, cbox_ntris, cbox_get_ids, 0, NULL, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (NULL, 0, NULL, cbox_nverts, NULL, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, 0, NULL, cbox_nverts, NULL, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (NULL, cbox_ntris, NULL, cbox_nverts, NULL, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, cbox_ntris, NULL, cbox_nverts, NULL, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (NULL, 0, cbox_get_ids, cbox_nverts, NULL, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, 0, cbox_get_ids, cbox_nverts, NULL, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (NULL, cbox_ntris, cbox_get_ids, cbox_nverts, NULL, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, cbox_ntris, cbox_get_ids, cbox_nverts, NULL, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (NULL, 0, NULL, 0, attribs, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, 0, NULL, 0, attribs, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (NULL, cbox_ntris, NULL, 0, attribs, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, cbox_ntris, NULL, 0, attribs, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (NULL, 0, cbox_get_ids, 0, attribs, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, 0, cbox_get_ids, 0, attribs, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (NULL, cbox_ntris, cbox_get_ids, 0, attribs, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, cbox_ntris, cbox_get_ids, 0, attribs, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (NULL, 0, NULL, cbox_nverts, attribs, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, 0, NULL, cbox_nverts, attribs, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (NULL, cbox_ntris, NULL, cbox_nverts, attribs, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, cbox_ntris, NULL, cbox_nverts, attribs, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (NULL, 0, cbox_get_ids, cbox_nverts, attribs, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, 0, cbox_get_ids, cbox_nverts, attribs, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (NULL, cbox_ntris, cbox_get_ids, cbox_nverts, attribs, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, cbox_ntris, cbox_get_ids, cbox_nverts, attribs, NULL), RES_OK); + + attribs[0] = S3D_VERTEX_DATA_NULL; + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, cbox_ntris, cbox_get_ids, cbox_nverts, attribs, NULL), RES_BAD_ARG); + + attribs[0].type = S3D_FLOAT3; + attribs[0].usage = S3D_POSITION; + attribs[0].get = S3D_KEEP; + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, cbox_ntris, cbox_get_ids, cbox_nverts, attribs, NULL), RES_OK); + + attribs[0].get = cbox_get_position; + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, cbox_ntris, S3D_KEEP, cbox_nverts, attribs, NULL), RES_OK); + + attribs[0].type = S3D_FLOAT3; + attribs[0].usage = S3D_ATTRIB_0; + attribs[0].get = cbox_get_normal; + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, cbox_ntris, S3D_KEEP, cbox_nverts, attribs, NULL), RES_BAD_ARG); + + attribs[1].type = S3D_FLOAT3; + attribs[1].usage = S3D_POSITION; + attribs[1].get = S3D_KEEP; + attribs[2] = S3D_VERTEX_DATA_NULL; + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, cbox_ntris, S3D_KEEP, cbox_nverts, attribs, NULL), RES_OK); + + attribs[2].type = S3D_FLOAT2; + attribs[2].usage = S3D_ATTRIB_2; + attribs[2].get = cbox_get_uv; + attribs[3] = S3D_VERTEX_DATA_NULL; + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, cbox_ntris, S3D_KEEP, cbox_nverts, attribs, NULL), RES_OK); + + attribs[0].get = S3D_KEEP; + attribs[1].get = S3D_KEEP; + attribs[2].get = S3D_KEEP; + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, 2, S3D_KEEP, cbox_nverts, attribs, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, cbox_ntris, S3D_KEEP, cbox_nverts+1, attribs, NULL), RES_BAD_ARG); + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, cbox_ntris, S3D_KEEP, cbox_nverts, attribs, NULL), RES_OK); + + attribs[2].type = S3D_FLOAT3; + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, cbox_ntris, S3D_KEEP, cbox_nverts, attribs, NULL), RES_BAD_ARG); + + attribs[0].get = cbox_get_position; + attribs[2] = S3D_VERTEX_DATA_NULL; + CHECK(s3d_shape_mesh_setup_indexed_vertices + (shape, cbox_ntris, S3D_KEEP, cbox_nverts, attribs, NULL), RES_OK); CHECK(s3d_shape_ref_get(NULL), RES_BAD_ARG); CHECK(s3d_shape_ref_get(shape), RES_OK);