star-2d

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

commit e24675d4017ca2f1cd5ac5d17018b1265cfca0b5
parent a8dd084c2b885f130b99aff9903570f99e5831db
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Fri, 17 Jun 2016 15:27:25 +0200

Implement the line_segments_setup_indexed_vertices back-end function

Diffstat:
Asrc/s2d_c.h | 48++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/s2d_line_segments.c | 367++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Msrc/s2d_line_segments.h | 28++++++++++++++--------------
3 files changed, 369 insertions(+), 74 deletions(-)

diff --git a/src/s2d_c.h b/src/s2d_c.h @@ -0,0 +1,48 @@ +/* Copyright (C) |Meso|Star> 2016 (contact@meso-star.com) + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. */ + +#ifndef S2D_C_H +#define S2D_C_H + +#include "s2d.h" + +#include <rsys/rsys.h> + +static INLINE unsigned +s2d_type_get_dimension(const enum s2d_type type) +{ + switch(type) { + case S2D_FLOAT: return 1; + case S2D_FLOAT2: return 2; + case S2D_FLOAT3: return 3; + default: FATAL("Unreachable code\n"); break; + } +} + +#endif /* S2D_C_H */ + diff --git a/src/s2d_line_segments.c b/src/s2d_line_segments.c @@ -26,6 +26,7 @@ * 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 "s2d_c.h" #include "s2d_device_c.h" #include "s2d_line_segments.h" @@ -35,16 +36,180 @@ * Helper functions ******************************************************************************/ static void -line_segments_release(ref_T* ref) +line_setup_indices + (struct line_segments* line, + const unsigned nsegments, + void (*get_indices)(const unsigned isegment, unsigned ids[2], void*), + const unsigned nverts, + void* data) { - struct line_segments* lines; + uint32_t* indices; + unsigned isegment; + unsigned nsegments_prev; + unsigned nverts_new; + res_T res = RES_OK; + ASSERT(line && nsegments && nverts); + + nsegments_prev = (unsigned)line_segments_get_nsegments(line); + ASSERT(get_indices != S2D_KEEP || nsegments == nsegments_prev); + + if(get_indices == S2D_KEEP) + return; + + if(nsegments == nsegments_prev) { + line->update_mask |= (INDEX_BUFFER & !line->resize_mask); + } else { + line->resize_mask |= INDEX_BUFFER; + line->update_mask &= !INDEX_BUFFER; + } + + if(line->indices) { /* Release the old index buffer */ + index_buffer_ref_put(line->indices); + line->indices = NULL; + } + + /* Allocate the new index buffer */ + res = index_buffer_create(line->dev->allocator, &line->indices); + if(res != RES_OK) FATAL("Insufficient memory\n"); + res = darray_u32_resize(&line->indices->data, nsegments * 2/*# segmet ids*/); + if(res != RES_OK) FATAL("Insufficient memory\n"); + + /* Setup the line indices */ + indices = line_segments_get_ids(line); + nverts_new = 0; + FOR_EACH(isegment, 0, nsegments) { + uint32_t* ids = indices + isegment*2/*#ids per segment*/; + STATIC_ASSERT(sizeof(unsigned) == sizeof(uint32_t), Unexpected_Type); + get_indices(isegment, ids, data); + nverts_new = MMAX(nverts_new, ids[0]); + nverts_new = MMAX(nverts_new, ids[1]); + } + /* Transform nverts from the last vertex id to vertices count */ + if(nverts_new > nverts) + FATAL("Out of bound indexation\n"); +} + +static void +line_setup_positions + (struct line_segments* line, + const unsigned nverts, + struct s2d_vertex_data* attr, + void* data) +{ + float* positions; + unsigned ivert, nverts_prev; + res_T res; + ASSERT(line && nverts && attr && attr->usage == S2D_POSITION); + + if(attr->get == S2D_KEEP) { + ASSERT(line->attribs[S2D_POSITION]); + ASSERT(darray_float_size_get(&line->attribs[S2D_POSITION]->data) == nverts*2); + return; + } + + nverts_prev = (unsigned)line_segments_get_nverts(line); + if(nverts == nverts_prev) { + line->update_mask |= (VERTEX_BUFFER & ~line->resize_mask); + } else { + line->resize_mask |= VERTEX_BUFFER; + line->update_mask &= !VERTEX_BUFFER; + } + + /* Release the old vertex buffer */ + if(line->attribs[S2D_POSITION]) { + vertex_buffer_ref_put(line->attribs[S2D_POSITION]); + line->attribs[S2D_POSITION] = NULL; + } + + /* Allocate the vertex positions */ + res = vertex_buffer_create(line->dev->allocator, &line->attribs[S2D_POSITION]); + if(res != RES_OK) FATAL("Insufficient memory\n"); + res = darray_float_resize(&line->attribs[S2D_POSITION]->data, nverts*2); + if(res != RES_OK) FATAL("Insufficient memory\n"); + line->attribs_type[S2D_POSITION] = S2D_FLOAT2; + + /* Setup the vertex positions */ + positions = darray_float_data_get(&line->attribs[S2D_POSITION]->data); + if(attr->type == S2D_FLOAT2) { + FOR_EACH(ivert, 0, nverts) { + attr->get(ivert, positions + ivert*3, data); + } + } else { + FOR_EACH(ivert, 0, nverts) { + float pos[3]; + unsigned ipos = ivert * 2/*# coords per vertex*/; + attr->get(ivert, pos, data); + switch(attr->type) { + case S2D_FLOAT: + positions[ipos + 0] = pos[0]; + positions[ipos + 1] = 0.f; + break; + case S2D_FLOAT2: + positions[ipos + 0] = pos[0]; + positions[ipos + 1] = pos[1]; + break; + case S2D_FLOAT3: + positions[ipos + 0] = pos[0] / pos[2]; + positions[ipos + 1] = pos[1] / pos[2]; + break; + default: FATAL("Unreachable code\n"); break; + } + } + } +} + +static void +line_setup_attribs + (struct line_segments* line, + const unsigned nverts, + const struct s2d_vertex_data* attr, + void* data) +{ + float* attr_data; + unsigned dim; + unsigned ivert; + res_T res; + ASSERT(line && nverts && attr); + ASSERT(attr->usage!=S2D_POSITION && (unsigned)attr->usage<S2D_ATTRIBS_COUNT__); + + dim = s2d_type_get_dimension(attr->type); + if(attr->get == S2D_KEEP) { + ASSERT(line->attribs_type[attr->usage] == attr->type); + ASSERT(line->attribs[attr->usage]); + ASSERT(darray_float_size_get(&line->attribs[attr->usage]->data) == nverts*dim); + return; + } + + if(line->attribs[attr->usage]) { /* Release the previous vertex buffer */ + vertex_buffer_ref_put(line->attribs[attr->usage]); + line->attribs[attr->usage] = NULL; + } + + /* Allocate the new vertex buffer */ + res = vertex_buffer_create(line->dev->allocator, &line->attribs[attr->usage]); + if(res != RES_OK) FATAL("Insufficient memory\n"); + res = darray_float_resize(&line->attribs[attr->usage]->data, nverts * dim); + if(res != RES_OK) FATAL("Insufficient memory\n"); + + /* Setup the vertex attrib */ + attr_data = darray_float_data_get(&line->attribs[attr->usage]->data); + FOR_EACH(ivert, 0, nverts) { + attr->get(ivert, attr_data, data); + attr_data += dim; + } +} + +static void +line_release(ref_T* ref) +{ + struct line_segments* line; struct s2d_device* dev; ASSERT(ref); - lines = CONTAINER_OF(ref, struct line_segments, ref); - line_segments_clear(lines); - dev = lines->dev; - MEM_RM(dev->allocator, lines); + line = CONTAINER_OF(ref, struct line_segments, ref); + line_segments_clear(line); + dev = line->dev; + MEM_RM(dev->allocator, line); S2D(device_ref_put(dev)); } @@ -54,128 +219,128 @@ line_segments_release(ref_T* ref) res_T line_segments_create(struct s2d_device* dev, struct line_segments** out_lines) { - struct line_segments* lines = NULL; + struct line_segments* line = NULL; res_T res = RES_OK; ASSERT(dev && out_lines); - lines = (struct line_segments*)MEM_CALLOC + line = (struct line_segments*)MEM_CALLOC (dev->allocator, 1, sizeof(struct line_segments)); - if(!lines) { + if(!line) { res = RES_MEM_ERR; goto error; } - ref_init(&lines->ref); + ref_init(&line->ref); S2D(device_ref_get(dev)); - lines->dev = dev; + line->dev = dev; exit: - *out_lines = lines; + *out_lines = line; return res; error: - if(lines) { - line_segments_ref_put(lines); - lines = NULL; + if(line) { + line_segments_ref_put(line); + line = NULL; } goto exit; } void -line_segments_ref_get(struct line_segments* lines) +line_segments_ref_get(struct line_segments* line) { - ASSERT(lines); - ref_get(&lines->ref); + ASSERT(line); + ref_get(&line->ref); } void -line_segments_ref_put(struct line_segments* lines) +line_segments_ref_put(struct line_segments* line) { - ASSERT(lines); - ref_put(&lines->ref, line_segments_release); + ASSERT(line); + ref_put(&line->ref, line_release); } void -line_segments_clear(struct line_segments* lines) +line_segments_clear(struct line_segments* line) { size_t iattr; - ASSERT(lines); - if(lines->indices) { - index_buffer_ref_put(lines->indices); - lines->indices = NULL; + ASSERT(line); + if(line->indices) { + index_buffer_ref_put(line->indices); + line->indices = NULL; } FOR_EACH(iattr, 0, S2D_ATTRIBS_COUNT__) { - if(lines->attribs[iattr]) { - vertex_buffer_ref_put(lines->attribs[iattr]); - lines->attribs[iattr] = NULL; + if(line->attribs[iattr]) { + vertex_buffer_ref_put(line->attribs[iattr]); + line->attribs[iattr] = NULL; } } - lines->resize_mask = 0; - lines->update_mask = 0; + line->resize_mask = 0; + line->update_mask = 0; } size_t -line_segments_get_nsegments(const struct line_segments* lines) +line_segments_get_nsegments(const struct line_segments* line) { size_t nids; - ASSERT(lines); - if(!lines->indices) + ASSERT(line); + if(!line->indices) return 0; - nids = darray_u32_size_get(&lines->indices->data); + nids = darray_u32_size_get(&line->indices->data); ASSERT(nids % 2 == 0); /* 2 vertices per segment */ return nids / 2/* #vertices per segement */; } size_t -line_segments_get_nverts(const struct line_segments* lines) +line_segments_get_nverts(const struct line_segments* line) { size_t ncoords; - ASSERT(lines); - if(!lines->attribs[S2D_POSITION]) + ASSERT(line); + if(!line->attribs[S2D_POSITION]) return 0; - ASSERT(lines->attribs_type[S2D_POSITION] == S2D_FLOAT2); - ncoords = darray_float_size_get(&lines->attribs[S2D_POSITION]->data); + ASSERT(line->attribs_type[S2D_POSITION] == S2D_FLOAT2); + ncoords = darray_float_size_get(&line->attribs[S2D_POSITION]->data); ASSERT(ncoords % 2 == 0); return ncoords / 2/* #coords per vertices */; } uint32_t* -line_segments_get_ids(struct line_segments* lines) +line_segments_get_ids(struct line_segments* line) { - ASSERT(lines && lines->indices); - return darray_u32_data_get(&lines->indices->data); + ASSERT(line && line->indices); + return darray_u32_data_get(&line->indices->data); } float* -line_segments_get_pos(struct line_segments* lines) +line_segments_get_pos(struct line_segments* line) { - ASSERT(lines && lines->attribs[S2D_POSITION]); - ASSERT(lines->attribs_type[S2D_POSITION] == S2D_FLOAT2); - return darray_float_data_get(&lines->attribs[S2D_POSITION]->data); + ASSERT(line && line->attribs[S2D_POSITION]); + ASSERT(line->attribs_type[S2D_POSITION] == S2D_FLOAT2); + return darray_float_data_get(&line->attribs[S2D_POSITION]->data); } float* line_segments_get_attr - (struct line_segments* lines, + (struct line_segments* line, const enum s2d_attrib_usage usage) { - ASSERT(lines && usage < S2D_ATTRIBS_COUNT__ && lines->attribs[usage]); - return darray_float_data_get(&lines->attribs[usage]->data); + ASSERT(line && usage < S2D_ATTRIBS_COUNT__ && line->attribs[usage]); + return darray_float_data_get(&line->attribs[usage]->data); } float -line_segments_compute_length(struct line_segments* lines) +line_segments_compute_length(struct line_segments* line) { const uint32_t* ids; const float* pos; size_t iseg, nsegs; float tmp[2]; float length = 0.f; - ASSERT(lines); + ASSERT(line); - nsegs = line_segments_get_nsegments(lines); + nsegs = line_segments_get_nsegments(line); if(!nsegs) return 0.f; - ids = line_segments_get_ids(lines); - pos = line_segments_get_pos(lines); + ids = line_segments_get_ids(line); + pos = line_segments_get_pos(line); FOR_EACH(iseg, 0, nsegs) { const size_t id = iseg * 2/*#ids per segment*/; @@ -188,20 +353,20 @@ line_segments_compute_length(struct line_segments* lines) float line_segments_compute_area - (struct line_segments* lines, + (struct line_segments* line, const char flip_contour) { const uint32_t* ids; const float* pos; size_t iseg, nsegs; double area2 = 0.f; - ASSERT(lines); + ASSERT(line); - nsegs = line_segments_get_nsegments(lines); + nsegs = line_segments_get_nsegments(line); if(!nsegs) return 0.f; - ids = line_segments_get_ids(lines); - pos = line_segments_get_pos(lines); + ids = line_segments_get_ids(line); + pos = line_segments_get_pos(line); /* Build a triangle whose base is the contour segment and its appex is the * origin. Then compute the area of the triangle and add or sub it from the @@ -232,3 +397,85 @@ line_segments_compute_area return (float)(area2 * 0.5); } +res_T +line_segments_setup_indexed_vertices + (struct line_segments* line, + const unsigned nsegments, + void (*get_indices)(const unsigned isegment, unsigned ids[2], void* ctx), + const unsigned nverts, + struct s2d_vertex_data attribs[], + const unsigned nattribs, + void* data) +{ + unsigned iattr = 0; + int has_position = 0; + res_T res = RES_OK; + ASSERT(line); + + if(nsegments || nverts || !attribs || !nattribs) { + res = RES_BAD_ARG; + goto error; + } + + /* Check indices description */ + if(get_indices == S2D_KEEP) { + if(!line->indices) { /* No indice was previously set */ + res = RES_BAD_ARG; + goto error; + } else { + const size_t nsegments_prev = line_segments_get_nsegments(line); + if(nsegments_prev != nsegments) { /* Inconsistant data */ + res = RES_BAD_ARG; + goto error; + } + } + } + + /* Check the vertex data description */ + iattr = 0; + has_position = 0; + FOR_EACH(iattr, 0, nattribs) { + ASSERT((unsigned)attribs[iattr].usage < S2D_ATTRIBS_COUNT__); + if(attribs[iattr].get == S2D_KEEP) { + const enum s2d_attrib_usage attr_usage = attribs[iattr].usage; + const enum s2d_type type = attribs[iattr].type; + if(!line->attribs[attr_usage]) { /* The vertex attrib was not set */ + res = RES_BAD_ARG; + goto error; + } else { + const enum s2d_type type_prev = line->attribs_type[attr_usage]; + const struct darray_float* attr = &line->attribs[attr_usage]->data; + size_t nverts_prev = darray_float_size_get(attr); + nverts_prev /= s2d_type_get_dimension(type_prev); + if(type_prev != type || nverts_prev != nverts) { /* Inconsistant data */ + res = RES_BAD_ARG; + goto error; + } + } + } + if(attribs[iattr].usage == S2D_POSITION) + has_position = 1; + } + + if(!has_position) { /* The vertex must have a position */ + res = RES_BAD_ARG; + goto error; + } + + line_setup_indices(line, nsegments, get_indices, nverts, data); + + /* Setup vertex data */ + FOR_EACH(iattr, 0, nattribs) { + if(attribs[iattr].usage == S2D_POSITION) { + line_setup_positions(line, nverts, attribs + iattr, data); + } else { + line_setup_attribs(line, nverts, attribs + iattr, data); + } + } + +exit: + return res; +error: + goto exit; +} + diff --git a/src/s2d_line_segments.h b/src/s2d_line_segments.h @@ -66,52 +66,52 @@ struct line_segments { /* Segmented contour */ extern LOCAL_SYM res_T line_segments_create (struct s2d_device* dev, - struct line_segments* lines); + struct line_segments* line); extern LOCAL_SYM void line_segments_ref_get - (struct line_segments* lines); + (struct line_segments* line); extern LOCAL_SYM void line_segments_ref_put - (struct line_segments* lines); + (struct line_segments* line); extern LOCAL_SYM void line_segments_clear - (struct line_segments* lines); + (struct line_segments* line); extern LOCAL_SYM size_t line_segments_get_nsegments - (const struct line_segments* lines); + (const struct line_segments* line); extern LOCAL_SYM size_t line_segments_get_nverts - (const struct line_segments* lines); + (const struct line_segments* line); extern LOCAL_SYM uint32_t* line_segments_get_ids - (struct line_segments* lines); + (struct line_segments* line); extern LOCAL_SYM float* line_segments_get_pos - (struct line_segments* lines); + (struct line_segments* line); extern LOCAL_SYM float* line_segments_get_attr - (struct line_segments* lines); + (struct line_segments* line); extern LOCAL_SYM float line_segments_compute_length - (struct line_segments* lines); + (struct line_segments* line); extern LOCAL_SYM float line_segments_compute_area - (struct line_segments* lines, + (struct line_segments* line, const char flip_contour); -extern LOCAL_SYM float +extern LOCAL_SYM res_T line_segments_setup_indexed_vertices - (struct line_segments* lines, + (struct line_segments* line, const unsigned ntris, void (*get_indices)(const unsigned isegment, unsigned ids[2], void* ctx), const unsigned nverts, @@ -121,7 +121,7 @@ line_segments_setup_indexed_vertices extern LOCAL_SYM void line_segments_compute_aabb - (struct line_segments* lines, + (struct line_segments* line, float lower[2], float upper[2]);