commit a8dd084c2b885f130b99aff9903570f99e5831db
parent 71a2fc0b49c6b592d18f6f98653a820cc2e4374c
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Wed, 8 Jun 2016 17:52:57 +0200
Begin the implementation of the line segment back-end
Diffstat:
5 files changed, 483 insertions(+), 3 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -56,10 +56,13 @@ set(VERSION_PATCH 0)
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
set(S2D_FILES_SRC
- s2d_device.c)
+ s2d_device.c
+ s2d_line_segments.c)
set(S2D_FILES_INC_API s2d.h)
set(S2D_FILES_INC
- s2d_device_c.h)
+ s2d_buffer.h
+ s2d_device_c.h
+ s2d_line_segments.h)
set(S2D_FILES_DOC COPYING.fr COPYING.en README.md)
# Prepend each file in the `S2D_FILES_<SRC|INC>' list by `S2D_SOURCE_DIR'
diff --git a/src/s2d.h b/src/s2d.h
@@ -389,7 +389,7 @@ s2d_line_segments_setup_indexed_vertices
(struct s2d_shape* shape,
const unsigned nsegments,
void (*get_indices) /* May be S2D_KEEP, i.e. do not update the indices */
- (const unsigned isegment, unsigned ids[3], void* ctx),
+ (const unsigned isegment, unsigned ids[2], void* ctx),
const unsigned nverts,
/* List of the shape vertex data. Must have at least an attrib with the
* S2D_POSITION usage. */
diff --git a/src/s2d_buffer.h b/src/s2d_buffer.h
@@ -0,0 +1,109 @@
+/* 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. */
+
+#if !defined(BUFFER_NAME) && !defined(BUFFER_DARRAY)
+
+#ifndef S2D_BUFFER_H
+#define S2D_BUFFER_H
+
+#include <rsys/mem_allocator.h>
+#include <rsys/ref_count.h>
+
+#endif /* S2D_BUFFER_H */
+#else
+/*
+ * Generate the buffer type with respect to the following macros:
+ * - BUFFER_NAME: name of the structure and prefix of the functions;
+ * - BUFFER_DARRAY: type of the dynamic array of the buffer;
+ */
+#if !defined(BUFFER_NAME) || !defined(BUFFER_DARRAY)
+ #error "Missing macro definition"
+#endif
+
+#define BUFFER_FUNC__(Func) CONCAT(CONCAT(BUFFER_NAME, _), Func)
+#define BUFFER_DARRAY_FUNC__(Func) CONCAT(CONCAT(BUFFER_DARRAY, _), Func)
+
+struct BUFFER_NAME {
+ BUFFER_DARRAY data;
+ struct mem_allocator* allocator;
+ ref_T ref;
+};
+
+/*******************************************************************************
+ * Helper function
+ ******************************************************************************/
+static INLINE void
+BUFFER_FUNC__(release__)(ref_T* ref)
+{
+ struct BUFFER_NAME* buffer;
+ ASSERT(ref);
+ buffer = CONTAINER_OF(ref, struct BUFFER_NAME, ref);
+ BUFFER_DARRAY_FUNC__(release)(&buffer->data);
+ MEM_RM(buffer->allocator, buffer);
+}
+
+/*******************************************************************************
+ * Buffer function
+ ******************************************************************************/
+static INLINE res_T
+BUFFER_FUNC__(create)
+ (struct mem_allocator* allocator,
+ struct BUFFER_NAME** out_buffer)
+{
+ struct BUFFER_NAME* buffer;
+ ASSERT(allocator && out_buffer);
+
+ buffer = (struct BUFFER_NAME*)MEM_CALLOC
+ (allocator, 1, sizeof(struct BUFFER_NAME));
+ if(!buffer) return RES_MEM_ERR;
+ BUFFER_DARRAY_FUNC__(init)(allocator, &buffer->data);
+ buffer->allocator = allocator;
+ ref_init(&buffer->ref);
+ *out_buffer = buffer;
+ return RES_OK;
+}
+
+static INLINE void
+BUFFER_FUNC__(ref_get)(struct BUFFER_NAME* buffer)
+{
+ ASSERT(buffer);
+ ref_get(&buffer->ref);
+}
+
+static INLINE void
+BUFFER_FUNC__(ref_put)(struct BUFFER_NAME* buffer)
+{
+ ASSERT(buffer);
+ ref_put(&buffer->ref, BUFFER_FUNC__(release__));
+}
+
+#undef BUFFER_NAME
+#undef BUFFER_DARRAY
+
+#endif /* !BUFFER_NAME || !BUFFER_DARRAY */
+
diff --git a/src/s2d_line_segments.c b/src/s2d_line_segments.c
@@ -0,0 +1,234 @@
+/* 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. */
+
+#include "s2d_device_c.h"
+#include "s2d_line_segments.h"
+
+#include <rsys/float2.h>
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static void
+line_segments_release(ref_T* ref)
+{
+ struct line_segments* lines;
+ 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);
+ S2D(device_ref_put(dev));
+}
+
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
+res_T
+line_segments_create(struct s2d_device* dev, struct line_segments** out_lines)
+{
+ struct line_segments* lines = NULL;
+ res_T res = RES_OK;
+ ASSERT(dev && out_lines);
+
+ lines = (struct line_segments*)MEM_CALLOC
+ (dev->allocator, 1, sizeof(struct line_segments));
+ if(!lines) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ ref_init(&lines->ref);
+ S2D(device_ref_get(dev));
+ lines->dev = dev;
+
+exit:
+ *out_lines = lines;
+ return res;
+error:
+ if(lines) {
+ line_segments_ref_put(lines);
+ lines = NULL;
+ }
+ goto exit;
+}
+
+void
+line_segments_ref_get(struct line_segments* lines)
+{
+ ASSERT(lines);
+ ref_get(&lines->ref);
+}
+
+void
+line_segments_ref_put(struct line_segments* lines)
+{
+ ASSERT(lines);
+ ref_put(&lines->ref, line_segments_release);
+}
+
+void
+line_segments_clear(struct line_segments* lines)
+{
+ size_t iattr;
+ ASSERT(lines);
+ if(lines->indices) {
+ index_buffer_ref_put(lines->indices);
+ lines->indices = NULL;
+ }
+ FOR_EACH(iattr, 0, S2D_ATTRIBS_COUNT__) {
+ if(lines->attribs[iattr]) {
+ vertex_buffer_ref_put(lines->attribs[iattr]);
+ lines->attribs[iattr] = NULL;
+ }
+ }
+ lines->resize_mask = 0;
+ lines->update_mask = 0;
+}
+
+size_t
+line_segments_get_nsegments(const struct line_segments* lines)
+{
+ size_t nids;
+ ASSERT(lines);
+ if(!lines->indices)
+ return 0;
+ nids = darray_u32_size_get(&lines->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)
+{
+ size_t ncoords;
+ ASSERT(lines);
+ if(!lines->attribs[S2D_POSITION])
+ return 0;
+ ASSERT(lines->attribs_type[S2D_POSITION] == S2D_FLOAT2);
+ ncoords = darray_float_size_get(&lines->attribs[S2D_POSITION]->data);
+ ASSERT(ncoords % 2 == 0);
+ return ncoords / 2/* #coords per vertices */;
+}
+
+uint32_t*
+line_segments_get_ids(struct line_segments* lines)
+{
+ ASSERT(lines && lines->indices);
+ return darray_u32_data_get(&lines->indices->data);
+}
+
+float*
+line_segments_get_pos(struct line_segments* lines)
+{
+ ASSERT(lines && lines->attribs[S2D_POSITION]);
+ ASSERT(lines->attribs_type[S2D_POSITION] == S2D_FLOAT2);
+ return darray_float_data_get(&lines->attribs[S2D_POSITION]->data);
+}
+
+float*
+line_segments_get_attr
+ (struct line_segments* lines,
+ const enum s2d_attrib_usage usage)
+{
+ ASSERT(lines && usage < S2D_ATTRIBS_COUNT__ && lines->attribs[usage]);
+ return darray_float_data_get(&lines->attribs[usage]->data);
+}
+
+float
+line_segments_compute_length(struct line_segments* lines)
+{
+ const uint32_t* ids;
+ const float* pos;
+ size_t iseg, nsegs;
+ float tmp[2];
+ float length = 0.f;
+ ASSERT(lines);
+
+ nsegs = line_segments_get_nsegments(lines);
+ if(!nsegs) return 0.f;
+
+ ids = line_segments_get_ids(lines);
+ pos = line_segments_get_pos(lines);
+
+ FOR_EACH(iseg, 0, nsegs) {
+ const size_t id = iseg * 2/*#ids per segment*/;
+ const float* v0 = pos + ids[id+0]*2/*#coords*/;
+ const float* v1 = pos + ids[id+1]*2/*#coords*/;
+ length += f2_len(f2_sub(tmp, v0, v1));
+ }
+ return length;
+}
+
+float
+line_segments_compute_area
+ (struct line_segments* lines,
+ const char flip_contour)
+{
+ const uint32_t* ids;
+ const float* pos;
+ size_t iseg, nsegs;
+ double area2 = 0.f;
+ ASSERT(lines);
+
+ nsegs = line_segments_get_nsegments(lines);
+ if(!nsegs) return 0.f;
+
+ ids = line_segments_get_ids(lines);
+ pos = line_segments_get_pos(lines);
+
+ /* 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
+ * overall area whether the normal point toward or backward the appex */
+ FOR_EACH(iseg, 0, nsegs) {
+ const size_t id = iseg * 2/*#ids per segment*/;
+ const float* v0 = pos + ids[id+0]*2/*#coords*/;
+ const float* v1 = pos + ids[id+1]*2/*#coords*/;
+ double tmp;
+ float dx, dy, N[2], C;
+
+ dx = v1[0] - v0[0];
+ dy = v1[1] - v0[1];
+
+ if(flip_contour) {
+ N[0] = -dy;
+ N[1] = dx;
+ } else {
+ N[0] = dy;
+ N[1] = -dx;
+ }
+ C = -f2_dot(N, v0); /* N.v0 + C = 0 */
+
+ tmp = v0[0]*v1[1] - v0[1]*v1[0]; /* Cross product */
+ tmp = sqrt(tmp*tmp); /* 2 * area of the triangle */
+ area2 += C > 0 ? tmp : -tmp;
+ }
+ return (float)(area2 * 0.5);
+}
+
diff --git a/src/s2d_line_segments.h b/src/s2d_line_segments.h
@@ -0,0 +1,134 @@
+/* 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_LINE_SEGMENTS_H
+#define S2D_LINE_SEGMENTS_H
+
+#include "s2d.h"
+
+#include "s2d_buffer.h"
+
+#include <rsys/dynamic_array_u32.h>
+#include <rsys/dynamic_array_float.h>
+#include <rsys/ref_count.h>
+
+/* Generate the index buffer data type */
+#define BUFFER_NAME index_buffer
+#define BUFFER_DARRAY darray_u32
+#include "s2d_buffer.h"
+
+/* Generate the vertex buffer data type */
+#define BUFFER_NAME vertex_buffer
+#define BUFFER_DARRAY darray_float
+#include "s2d_buffer.h"
+
+enum buffer_type {
+ INDEX_BUFFER = BIT(0),
+ VERTEX_BUFFER = BIT(1)
+};
+
+struct line_segments { /* Segmented contour */
+ struct index_buffer* indices;
+ struct vertex_buffer* attribs[S2D_ATTRIBS_COUNT__];
+ enum s2d_type attribs_type[S2D_ATTRIBS_COUNT__];
+
+ int resize_mask; /* Combination of buffer_type */
+ int update_mask; /* Combination of buffer_type */
+ struct s2d_device* dev;
+ ref_T ref;
+};
+
+extern LOCAL_SYM res_T
+line_segments_create
+ (struct s2d_device* dev,
+ struct line_segments* lines);
+
+extern LOCAL_SYM void
+line_segments_ref_get
+ (struct line_segments* lines);
+
+extern LOCAL_SYM void
+line_segments_ref_put
+ (struct line_segments* lines);
+
+extern LOCAL_SYM void
+line_segments_clear
+ (struct line_segments* lines);
+
+extern LOCAL_SYM size_t
+line_segments_get_nsegments
+ (const struct line_segments* lines);
+
+extern LOCAL_SYM size_t
+line_segments_get_nverts
+ (const struct line_segments* lines);
+
+extern LOCAL_SYM uint32_t*
+line_segments_get_ids
+ (struct line_segments* lines);
+
+extern LOCAL_SYM float*
+line_segments_get_pos
+ (struct line_segments* lines);
+
+extern LOCAL_SYM float*
+line_segments_get_attr
+ (struct line_segments* lines);
+
+extern LOCAL_SYM float
+line_segments_compute_length
+ (struct line_segments* lines);
+
+extern LOCAL_SYM float
+line_segments_compute_area
+ (struct line_segments* lines,
+ const char flip_contour);
+
+extern LOCAL_SYM float
+line_segments_setup_indexed_vertices
+ (struct line_segments* lines,
+ const unsigned ntris,
+ void (*get_indices)(const unsigned isegment, unsigned ids[2], void* ctx),
+ const unsigned nverts,
+ struct s2d_vertex_data attribs[],
+ const unsigned nattribs,
+ void* data);
+
+extern LOCAL_SYM void
+line_segments_compute_aabb
+ (struct line_segments* lines,
+ float lower[2],
+ float upper[2]);
+
+extern LOCAL_SYM void
+line_segments_copy_indexed_vertices
+ (const struct line_segments* src,
+ struct line_segments* dst);
+
+#endif /* S2D_LINE_SEGMENTS_H */
+