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:
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]);