commit 5e60e840f66b6842d6579775b64518555765f1c4
parent 82efe24bb04436872fd72cde3811fd46c5f961f0
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Wed, 22 Jun 2016 16:10:04 +0200
Implement and test the s2d_scene session API
Diffstat:
6 files changed, 568 insertions(+), 154 deletions(-)
diff --git a/src/s2d_line_segments.c b/src/s2d_line_segments.c
@@ -37,7 +37,7 @@
******************************************************************************/
static void
line_setup_indices
- (struct line_segments* line,
+ (struct line_segments* lines,
const unsigned nsegments,
void (*get_indices)(const unsigned isegment, unsigned ids[2], void*),
const unsigned nverts,
@@ -48,34 +48,34 @@ line_setup_indices
unsigned nsegments_prev;
unsigned nverts_new;
res_T res = RES_OK;
- ASSERT(line && nsegments && nverts);
+ ASSERT(lines && nsegments && nverts);
- nsegments_prev = (unsigned)line_segments_get_nsegments(line);
+ nsegments_prev = (unsigned)line_segments_get_nsegments(lines);
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);
+ lines->update_mask |= (INDEX_BUFFER & !lines->resize_mask);
} else {
- line->resize_mask |= INDEX_BUFFER;
- line->update_mask &= !INDEX_BUFFER;
+ lines->resize_mask |= INDEX_BUFFER;
+ lines->update_mask &= !INDEX_BUFFER;
}
- if(line->indices) { /* Release the old index buffer */
- index_buffer_ref_put(line->indices);
- line->indices = NULL;
+ if(lines->indices) { /* Release the old index buffer */
+ index_buffer_ref_put(lines->indices);
+ lines->indices = NULL;
}
/* Allocate the new index buffer */
- res = index_buffer_create(line->dev->allocator, &line->indices);
+ res = index_buffer_create(lines->dev->allocator, &lines->indices);
if(res != RES_OK) FATAL("Insufficient memory\n");
- res = darray_u32_resize(&line->indices->data, nsegments * 2/*# segmet ids*/);
+ res = darray_u32_resize(&lines->indices->data, nsegments * 2/*# segmet ids*/);
if(res != RES_OK) FATAL("Insufficient memory\n");
- /* Setup the line indices */
- indices = line_segments_get_ids(line);
+ /* Setup the lines indices */
+ indices = line_segments_get_ids(lines);
nverts_new = 0;
FOR_EACH(isegment, 0, nsegments) {
uint32_t* ids = indices + isegment*2/*#ids per segment*/;
@@ -91,7 +91,7 @@ line_setup_indices
static void
line_setup_positions
- (struct line_segments* line,
+ (struct line_segments* lines,
const unsigned nverts,
struct s2d_vertex_data* attr,
void* data)
@@ -99,37 +99,37 @@ line_setup_positions
float* positions;
unsigned ivert, nverts_prev;
res_T res;
- ASSERT(line && nverts && attr && attr->usage == S2D_POSITION);
+ ASSERT(lines && 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);
+ ASSERT(lines->attribs[S2D_POSITION]);
+ ASSERT(darray_float_size_get(&lines->attribs[S2D_POSITION]->data) == nverts*2);
return;
}
- nverts_prev = (unsigned)line_segments_get_nverts(line);
+ nverts_prev = (unsigned)line_segments_get_nverts(lines);
if(nverts == nverts_prev) {
- line->update_mask |= (VERTEX_BUFFER & ~line->resize_mask);
+ lines->update_mask |= (VERTEX_BUFFER & ~lines->resize_mask);
} else {
- line->resize_mask |= VERTEX_BUFFER;
- line->update_mask &= !VERTEX_BUFFER;
+ lines->resize_mask |= VERTEX_BUFFER;
+ lines->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;
+ if(lines->attribs[S2D_POSITION]) {
+ vertex_buffer_ref_put(lines->attribs[S2D_POSITION]);
+ lines->attribs[S2D_POSITION] = NULL;
}
/* Allocate the vertex positions */
- res = vertex_buffer_create(line->dev->allocator, &line->attribs[S2D_POSITION]);
+ res = vertex_buffer_create(lines->dev->allocator, &lines->attribs[S2D_POSITION]);
if(res != RES_OK) FATAL("Insufficient memory\n");
- res = darray_float_resize(&line->attribs[S2D_POSITION]->data, nverts*2);
+ res = darray_float_resize(&lines->attribs[S2D_POSITION]->data, nverts*2);
if(res != RES_OK) FATAL("Insufficient memory\n");
- line->attribs_type[S2D_POSITION] = S2D_FLOAT2;
+ lines->attribs_type[S2D_POSITION] = S2D_FLOAT2;
/* Setup the vertex positions */
- positions = darray_float_data_get(&line->attribs[S2D_POSITION]->data);
+ positions = darray_float_data_get(&lines->attribs[S2D_POSITION]->data);
if(attr->type == S2D_FLOAT2) {
FOR_EACH(ivert, 0, nverts) {
attr->get(ivert, positions + ivert*2/*# coords per vertex*/, data);
@@ -160,7 +160,7 @@ line_setup_positions
static void
line_setup_attribs
- (struct line_segments* line,
+ (struct line_segments* lines,
const unsigned nverts,
const struct s2d_vertex_data* attr,
void* data)
@@ -169,30 +169,30 @@ line_setup_attribs
unsigned dim;
unsigned ivert;
res_T res;
- ASSERT(line && nverts && attr);
+ ASSERT(lines && 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);
+ ASSERT(lines->attribs_type[attr->usage] == attr->type);
+ ASSERT(lines->attribs[attr->usage]);
+ ASSERT(darray_float_size_get(&lines->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;
+ if(lines->attribs[attr->usage]) { /* Release the previous vertex buffer */
+ vertex_buffer_ref_put(lines->attribs[attr->usage]);
+ lines->attribs[attr->usage] = NULL;
}
/* Allocate the new vertex buffer */
- res = vertex_buffer_create(line->dev->allocator, &line->attribs[attr->usage]);
+ res = vertex_buffer_create(lines->dev->allocator, &lines->attribs[attr->usage]);
if(res != RES_OK) FATAL("Insufficient memory\n");
- res = darray_float_resize(&line->attribs[attr->usage]->data, nverts * dim);
+ res = darray_float_resize(&lines->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);
+ attr_data = darray_float_data_get(&lines->attribs[attr->usage]->data);
FOR_EACH(ivert, 0, nverts) {
attr->get(ivert, attr_data, data);
attr_data += dim;
@@ -202,14 +202,14 @@ line_setup_attribs
static void
line_release(ref_T* ref)
{
- struct line_segments* line;
+ struct line_segments* lines;
struct s2d_device* dev;
ASSERT(ref);
- line = CONTAINER_OF(ref, struct line_segments, ref);
- line_segments_clear(line);
- dev = line->dev;
- MEM_RM(dev->allocator, line);
+ 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));
}
@@ -219,128 +219,128 @@ line_release(ref_T* ref)
res_T
line_segments_create(struct s2d_device* dev, struct line_segments** out_lines)
{
- struct line_segments* line = NULL;
+ struct line_segments* lines = NULL;
res_T res = RES_OK;
ASSERT(dev && out_lines);
- line = (struct line_segments*)MEM_CALLOC
+ lines = (struct line_segments*)MEM_CALLOC
(dev->allocator, 1, sizeof(struct line_segments));
- if(!line) {
+ if(!lines) {
res = RES_MEM_ERR;
goto error;
}
- ref_init(&line->ref);
+ ref_init(&lines->ref);
S2D(device_ref_get(dev));
- line->dev = dev;
+ lines->dev = dev;
exit:
- *out_lines = line;
+ *out_lines = lines;
return res;
error:
- if(line) {
- line_segments_ref_put(line);
- line = NULL;
+ if(lines) {
+ line_segments_ref_put(lines);
+ lines = NULL;
}
goto exit;
}
void
-line_segments_ref_get(struct line_segments* line)
+line_segments_ref_get(struct line_segments* lines)
{
- ASSERT(line);
- ref_get(&line->ref);
+ ASSERT(lines);
+ ref_get(&lines->ref);
}
void
-line_segments_ref_put(struct line_segments* line)
+line_segments_ref_put(struct line_segments* lines)
{
- ASSERT(line);
- ref_put(&line->ref, line_release);
+ ASSERT(lines);
+ ref_put(&lines->ref, line_release);
}
void
-line_segments_clear(struct line_segments* line)
+line_segments_clear(struct line_segments* lines)
{
size_t iattr;
- ASSERT(line);
- if(line->indices) {
- index_buffer_ref_put(line->indices);
- line->indices = NULL;
+ ASSERT(lines);
+ if(lines->indices) {
+ index_buffer_ref_put(lines->indices);
+ lines->indices = NULL;
}
FOR_EACH(iattr, 0, S2D_ATTRIBS_COUNT__) {
- if(line->attribs[iattr]) {
- vertex_buffer_ref_put(line->attribs[iattr]);
- line->attribs[iattr] = NULL;
+ if(lines->attribs[iattr]) {
+ vertex_buffer_ref_put(lines->attribs[iattr]);
+ lines->attribs[iattr] = NULL;
}
}
- line->resize_mask = 0;
- line->update_mask = 0;
+ lines->resize_mask = 0;
+ lines->update_mask = 0;
}
size_t
-line_segments_get_nsegments(const struct line_segments* line)
+line_segments_get_nsegments(const struct line_segments* lines)
{
size_t nids;
- ASSERT(line);
- if(!line->indices)
+ ASSERT(lines);
+ if(!lines->indices)
return 0;
- nids = darray_u32_size_get(&line->indices->data);
+ 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* line)
+line_segments_get_nverts(const struct line_segments* lines)
{
size_t ncoords;
- ASSERT(line);
- if(!line->attribs[S2D_POSITION])
+ ASSERT(lines);
+ if(!lines->attribs[S2D_POSITION])
return 0;
- ASSERT(line->attribs_type[S2D_POSITION] == S2D_FLOAT2);
- ncoords = darray_float_size_get(&line->attribs[S2D_POSITION]->data);
+ 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* line)
+line_segments_get_ids(struct line_segments* lines)
{
- ASSERT(line && line->indices);
- return darray_u32_data_get(&line->indices->data);
+ ASSERT(lines && lines->indices);
+ return darray_u32_data_get(&lines->indices->data);
}
float*
-line_segments_get_pos(struct line_segments* line)
+line_segments_get_pos(struct line_segments* lines)
{
- ASSERT(line && line->attribs[S2D_POSITION]);
- ASSERT(line->attribs_type[S2D_POSITION] == S2D_FLOAT2);
- return darray_float_data_get(&line->attribs[S2D_POSITION]->data);
+ 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* line,
+ (struct line_segments* lines,
const enum s2d_attrib_usage usage)
{
- ASSERT(line && usage < S2D_ATTRIBS_COUNT__ && line->attribs[usage]);
- return darray_float_data_get(&line->attribs[usage]->data);
+ 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* line)
+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(line);
+ ASSERT(lines);
- nsegs = line_segments_get_nsegments(line);
+ nsegs = line_segments_get_nsegments(lines);
if(!nsegs) return 0.f;
- ids = line_segments_get_ids(line);
- pos = line_segments_get_pos(line);
+ 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*/;
@@ -353,20 +353,20 @@ line_segments_compute_length(struct line_segments* line)
float
line_segments_compute_area
- (struct line_segments* line,
+ (struct line_segments* lines,
const char flip_contour)
{
const uint32_t* ids;
const float* pos;
size_t iseg, nsegs;
double area2 = 0.f;
- ASSERT(line);
+ ASSERT(lines);
- nsegs = line_segments_get_nsegments(line);
+ nsegs = line_segments_get_nsegments(lines);
if(!nsegs) return 0.f;
- ids = line_segments_get_ids(line);
- pos = line_segments_get_pos(line);
+ 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
@@ -399,7 +399,7 @@ line_segments_compute_area
res_T
line_segments_setup_indexed_vertices
- (struct line_segments* line,
+ (struct line_segments* lines,
const unsigned nsegments,
void (*get_indices)(const unsigned isegment, unsigned ids[2], void* ctx),
const unsigned nverts,
@@ -410,7 +410,7 @@ line_segments_setup_indexed_vertices
unsigned iattr = 0;
int has_position = 0;
res_T res = RES_OK;
- ASSERT(line);
+ ASSERT(lines);
if(!nsegments || !nverts || !attribs || !nattribs) {
res = RES_BAD_ARG;
@@ -419,11 +419,11 @@ line_segments_setup_indexed_vertices
/* Check indices description */
if(get_indices == S2D_KEEP) {
- if(!line->indices) { /* No indice was previously set */
+ if(!lines->indices) { /* No indice was previously set */
res = RES_BAD_ARG;
goto error;
} else {
- const size_t nsegments_prev = line_segments_get_nsegments(line);
+ const size_t nsegments_prev = line_segments_get_nsegments(lines);
if(nsegments_prev != nsegments) { /* Inconsistant data */
res = RES_BAD_ARG;
goto error;
@@ -442,12 +442,12 @@ line_segments_setup_indexed_vertices
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 */
+ if(!lines->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;
+ const enum s2d_type type_prev = lines->attribs_type[attr_usage];
+ const struct darray_float* attr = &lines->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 */
@@ -465,14 +465,14 @@ line_segments_setup_indexed_vertices
goto error;
}
- line_setup_indices(line, nsegments, get_indices, nverts, data);
+ line_setup_indices(lines, 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);
+ line_setup_positions(lines, nverts, attribs + iattr, data);
} else {
- line_setup_attribs(line, nverts, attribs + iattr, data);
+ line_setup_attribs(lines, nverts, attribs + iattr, data);
}
}
@@ -484,21 +484,21 @@ error:
void
line_segments_compute_aabb
- (struct line_segments* line,
+ (struct line_segments* lines,
float lower[2],
float upper[2])
{
float* pos;
size_t ivert, nverts;
- ASSERT(line && lower && upper);
+ ASSERT(lines && lower && upper);
f2_splat(lower, FLT_MAX);
f2_splat(upper,-FLT_MAX);
- nverts = line_segments_get_nverts(line);
+ nverts = line_segments_get_nverts(lines);
if(!nverts) return;
- pos = line_segments_get_pos(line);
+ pos = line_segments_get_pos(lines);
FOR_EACH(ivert, 0, nverts) {
const size_t ipos = ivert * 2/*#coords per vertex*/;
f2_min(lower, lower, pos + ipos);
diff --git a/src/s2d_line_segments.h b/src/s2d_line_segments.h
@@ -73,53 +73,53 @@ struct line_segments { /* Segmented contour */
extern LOCAL_SYM res_T
line_segments_create
(struct s2d_device* dev,
- struct line_segments** line);
+ struct line_segments** lines);
extern LOCAL_SYM void
line_segments_ref_get
- (struct line_segments* line);
+ (struct line_segments* lines);
extern LOCAL_SYM void
line_segments_ref_put
- (struct line_segments* line);
+ (struct line_segments* lines);
extern LOCAL_SYM void
line_segments_clear
- (struct line_segments* line);
+ (struct line_segments* lines);
extern LOCAL_SYM size_t
line_segments_get_nsegments
- (const struct line_segments* line);
+ (const struct line_segments* lines);
extern LOCAL_SYM size_t
line_segments_get_nverts
- (const struct line_segments* line);
+ (const struct line_segments* lines);
extern LOCAL_SYM uint32_t*
line_segments_get_ids
- (struct line_segments* line);
+ (struct line_segments* lines);
extern LOCAL_SYM float*
line_segments_get_pos
- (struct line_segments* line);
+ (struct line_segments* lines);
extern LOCAL_SYM float*
line_segments_get_attr
- (struct line_segments* line,
+ (struct line_segments* lines,
const enum s2d_attrib_usage usage);
extern LOCAL_SYM float
line_segments_compute_length
- (struct line_segments* line);
+ (struct line_segments* lines);
extern LOCAL_SYM float
line_segments_compute_area
- (struct line_segments* line,
+ (struct line_segments* lines,
const char flip_contour);
extern LOCAL_SYM res_T
line_segments_setup_indexed_vertices
- (struct line_segments* line,
+ (struct line_segments* lines,
const unsigned ntris,
void (*get_indices)(const unsigned isegment, unsigned ids[2], void* ctx),
const unsigned nverts,
@@ -129,7 +129,7 @@ line_segments_setup_indexed_vertices
extern LOCAL_SYM void
line_segments_compute_aabb
- (struct line_segments* line,
+ (struct line_segments* lines,
float lower[2],
float upper[2]);
diff --git a/src/s2d_scene.c b/src/s2d_scene.c
@@ -28,6 +28,7 @@
#include "s2d.h"
#include "s2d_device_c.h"
+#include "s2d_line_segments.h"
#include "s2d_geometry.h"
#include "s2d_scene_c.h"
#include "s2d_shape_c.h"
@@ -36,9 +37,265 @@
#include <rsys/float2.h>
#include <rsys/mem_allocator.h>
+struct ray_extended : public RTCRay {
+ struct s2d_scene* scene;
+ void* data; /* User defined data */
+};
+
/*******************************************************************************
* Helper functions
******************************************************************************/
+static INLINE void
+hit_setup(struct s2d_scene* scn, const RTCRay* ray, struct s2d_hit* hit)
+{
+ (void)scn, (void)ray, (void)hit;
+ /* TODO */
+}
+
+static void
+filter_wrapper(void* user_ptr, RTCRay& ray)
+{
+ struct s2d_hit hit;
+ struct hit_filter* filter = (struct hit_filter*)user_ptr;
+ struct ray_extended* ray_ex = static_cast<struct ray_extended*>(&ray);
+
+ hit_setup(ray_ex->scene, &ray, &hit);
+ if(filter->func(&hit, ray_ex->org, ray_ex->dir, ray_ex->data, filter->data)) {
+ /* Discard the intersection */
+ ray.geomID = RTC_INVALID_GEOMETRY_ID;
+ }
+}
+
+static void
+scene_geometry_flush_enable_state
+ (struct s2d_scene* scn,
+ struct geometry* geom,
+ const struct s2d_shape* shape)
+{
+ ASSERT(scn && geom && shape && geom->irtc != RTC_INVALID_GEOMETRY_ID);
+ if(geom->is_enabled == shape->is_enabled)
+ return;
+
+ geom->is_enabled = shape->is_enabled;
+ if(geom->is_enabled) {
+ rtcEnable(scn->rtc_scn, geom->irtc);
+ } else {
+ rtcDisable(scn->rtc_scn, geom->irtc);
+ }
+ scn->is_rtc_scn_outdated = 1;
+}
+
+static void
+scene_geometry_flush_filter_function
+ (struct s2d_scene* scn,
+ struct geometry* geom,
+ const struct s2d_shape* shape)
+{
+ ASSERT(scn && geom && shape && geom->irtc != RTC_INVALID_GEOMETRY_ID);
+
+ if(geom->lines->filter.func == shape->lines->filter.func
+ && geom->lines->filter.data == shape->lines->filter.data)
+ return; /* Up to date */
+
+ geom->lines->filter = shape->lines->filter;
+ if(!geom->lines->filter.func) {
+ rtcSetIntersectionFilterFunction(scn->rtc_scn, geom->irtc, NULL);
+ } else {
+ rtcSetIntersectionFilterFunction(scn->rtc_scn, geom->irtc, filter_wrapper);
+ rtcSetUserData(scn->rtc_scn, geom->irtc, &geom->lines->filter);
+ }
+ scn->is_rtc_scn_outdated = 1;
+}
+
+
+static res_T
+scene_register_geometry(struct s2d_scene* scn, struct geometry* geom)
+{
+ ASSERT(scn && geom);
+
+ /* Create the embree geometry if it is not valid */
+ if(geom->irtc == RTC_INVALID_GEOMETRY_ID) {
+ geom->irtc = rtcNewQuadMesh
+ (scn->rtc_scn,
+ RTC_GEOMETRY_DYNAMIC,
+ line_segments_get_nsegments(geom->lines),
+ line_segments_get_nverts(geom->lines)*2/*Lines are extruded as quads*/);
+ if(geom->irtc == RTC_INVALID_GEOMETRY_ID)
+ return RES_UNKNOWN_ERR;
+ scn->is_rtc_scn_outdated = 1;
+ }
+ if(geom->irtc >= darray_geom_size_get(&scn->embree2geoms)) {
+ const res_T res = darray_geom_resize(&scn->embree2geoms, geom->irtc + 1);
+ if(res != RES_OK) {
+ rtcDeleteGeometry(scn->rtc_scn, geom->irtc);
+ geom->irtc = RTC_INVALID_GEOMETRY_ID;
+ return res;
+ }
+ }
+ geometry_ref_get(geom);
+ darray_geom_data_get(&scn->embree2geoms)[geom->irtc] = geom;
+ return RES_OK;
+}
+
+static void
+scene_geometry_flush_positions(struct s2d_scene* scn, struct geometry* geom)
+{
+ size_t nverts;
+ size_t i;
+ float* verts;
+ float* rtc_verts;
+ ASSERT(scn && geom && geom->irtc != RTC_INVALID_GEOMETRY_ID);
+
+ /* Extrude segment vertices as quad whose Z is [-1, 1] */
+ nverts = line_segments_get_nverts(geom->lines);
+ verts = line_segments_get_attr(geom->lines, S2D_POSITION);
+ rtc_verts = (float*)rtcMapBuffer(scn->rtc_scn, geom->irtc, RTC_VERTEX_BUFFER);
+ FOR_EACH(i, 0, nverts) {
+ size_t ivert = i*2/*#coords per vertex*/;
+ size_t rtc_ivert = i*4/*#coords + padding*/ * 2/*#rtc vertices per line vertex*/;
+
+ rtc_verts[rtc_ivert + 0] = verts[ivert + 0];
+ rtc_verts[rtc_ivert + 1] = verts[ivert + 1];
+ rtc_verts[rtc_ivert + 2] = 1.f;
+ rtc_verts[rtc_ivert + 3] = 0.f; /* Padding */
+
+ rtc_verts[rtc_ivert + 4] = verts[ivert + 0];
+ rtc_verts[rtc_ivert + 5] = verts[ivert + 1];
+ rtc_verts[rtc_ivert + 6] = -1.f;
+ rtc_verts[rtc_ivert + 7] = 0.f; /* Padding */
+ }
+ rtcUnmapBuffer(scn->rtc_scn, geom->irtc, RTC_VERTEX_BUFFER);
+}
+
+static void
+scene_geometry_flush_indices(struct s2d_scene* scn, struct geometry* geom)
+{
+ size_t nsegs;
+ size_t i;
+ uint32_t* ids;
+ uint32_t* rtc_ids;
+ ASSERT(scn && geom && geom->irtc != RTC_INVALID_GEOMETRY_ID);
+
+ /* Define the index of the extruded line segments */
+ nsegs = line_segments_get_nsegments(geom->lines);
+ ids = line_segments_get_ids(geom->lines);
+ rtc_ids = (uint32_t*)rtcMapBuffer(scn->rtc_scn, geom->irtc, RTC_INDEX_BUFFER);
+ FOR_EACH(i, 0, nsegs) {
+ size_t id = i*2/*#ids per segment*/;
+ size_t rtc_id = i*4/*#ids per quad*/;
+
+ rtc_ids[rtc_id + 0] = ids[id + 0] * 2/*#rtc vertices per line vertex*/ + 0;
+ rtc_ids[rtc_id + 1] = ids[id + 0] * 2/*#rtc vertices per line vertex*/ + 1;
+ rtc_ids[rtc_id + 2] = ids[id + 1] * 2/*#rtc vertices per line vertex*/ + 1;
+ rtc_ids[rtc_id + 3] = ids[id + 1] * 2/*#rtc vertices per line vertex*/ + 0;
+ }
+ rtcUnmapBuffer(scn->rtc_scn, geom->irtc, RTC_INDEX_BUFFER);
+}
+
+static res_T
+scene_register_line_segments
+ (struct s2d_scene* scn,
+ struct s2d_shape* shape)
+{
+ struct geometry** pgeom = NULL;
+ struct geometry* geom = NULL;
+ size_t iattr;
+ char upd_pos, upd_ids;
+
+ res_T res = RES_OK;
+ ASSERT(scn && shape);
+
+ /* Retrieved the cached geometry */
+ pgeom = htable_geom_find(&scn->cached_geoms, &shape);
+ if(pgeom) {
+ geom = *pgeom;
+ } else {
+ res = geometry_create(scn->dev, &geom);
+ if(res != RES_OK) goto error;
+ res = line_segments_create(scn->dev, &geom->lines);
+ if(res != RES_OK) goto error;
+ res = htable_geom_set(&scn->cached_geoms, &shape, &geom);
+ if(res != RES_OK) goto error;
+ geom->name = shape->id.index;
+ }
+
+ /* Discard the geometries that are not geometrically valid */
+ if(!shape->lines->indices || !shape->lines->attribs[S2D_POSITION]) {
+ if(geom->irtc != RTC_INVALID_GEOMETRY_ID) {
+ rtcDeleteGeometry(scn->rtc_scn, geom->irtc);
+ geom->irtc = RTC_INVALID_GEOMETRY_ID;
+ scn->is_rtc_scn_outdated = 1;
+ }
+ line_segments_clear(geom->lines);
+ goto exit;
+ }
+
+ /* Define which geometry buffers were updated */
+ upd_ids = geom->lines->indices != shape->lines->indices
+ || ((shape->lines->update_mask & INDEX_BUFFER) != 0);
+ upd_pos = geom->lines->attribs[S2D_POSITION] != shape->lines->attribs[S2D_POSITION]
+ || ((shape->lines->update_mask & VERTEX_BUFFER) != 0);
+
+ /* Get a reference onto the shape lines segments indices */
+ if(geom->lines->indices != shape->lines->indices) {
+ if(geom->lines->indices) { /* Release previous indices of the geometry */
+ index_buffer_ref_put(geom->lines->indices);
+ geom->lines->indices = NULL;
+ }
+ ASSERT(shape->lines->indices);
+ index_buffer_ref_get(shape->lines->indices);
+ geom->lines->indices = shape->lines->indices;
+ }
+
+ /* Get a reference onto the shape line segments attribs */
+ FOR_EACH(iattr, 0, S2D_ATTRIBS_COUNT__) {
+ if(geom->lines->attribs[iattr] == shape->lines->attribs[iattr])
+ continue;
+
+ if(geom->lines->attribs[iattr]) { /* Release the previous geometry attribs */
+ vertex_buffer_ref_put(geom->lines->attribs[iattr]);
+ geom->lines->attribs[iattr] = NULL;
+ }
+
+ if(!shape->lines->attribs[iattr]) continue;
+
+ vertex_buffer_ref_get(shape->lines->attribs[iattr]);
+ geom->lines->attribs[iattr] = shape->lines->attribs[iattr];
+ geom->lines->attribs_type[iattr] = shape->lines->attribs_type[iattr];
+ }
+
+ /* The line segments were resize => the Embree geometry is no more valid */
+ if(shape->lines->resize_mask && geom->irtc != RTC_INVALID_GEOMETRY_ID) {
+ rtcDeleteGeometry(scn->rtc_scn, geom->irtc);
+ geom->irtc = RTC_INVALID_GEOMETRY_ID;
+ scn->is_rtc_scn_outdated = 1;
+ }
+
+ res = scene_register_geometry(scn, geom);
+ if(res != RES_OK) goto error;
+
+ if(upd_pos) { /* Update the Embree vertex buffer if necessary */
+ scene_geometry_flush_positions(scn, geom);
+ }
+ if(upd_ids) { /* Update the Embree index buffer if necessary */
+ scene_geometry_flush_indices(scn, geom);
+ }
+
+ /* Flush the remaining geometry states */
+ scene_geometry_flush_enable_state(scn, geom, shape);
+ scene_geometry_flush_filter_function(scn, geom, shape);
+ geom->flip_contour = shape->flip_contour;
+
+ /* Flush the shape line segments states */
+ shape->lines->resize_mask = 0;
+ shape->lines->update_mask = 0;
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
static void
scene_session_clear(struct s2d_scene* scn)
{
@@ -56,16 +313,25 @@ scene_session_clear(struct s2d_scene* scn)
scn->session_mask = 0;
}
-static void
-scene_detach_shape(struct s2d_scene* scn, struct s2d_shape* shape)
+static res_T
+scene_detach_shape
+ (struct s2d_scene* scn, struct s2d_shape* shape, const char* caller_name)
{
struct geometry** pgeom;
ASSERT(scn && shape && !is_list_empty(&shape->scene_attachment));
- ASSERT(scn->session_mask == 0);
pgeom = htable_geom_find(&scn->cached_geoms, &shape);
if(pgeom) { /* Remove the cached geometry */
struct geometry* geom = *pgeom;
+
+ if(scn->session_mask != 0) {
+ if(scn->dev->verbose) {
+ logger_print(scn->dev->logger, LOG_ERROR,
+ "%s: Cannot detach a shape currently in used in a scene session.\n",
+ caller_name);
+ }
+ return RES_BAD_OP;
+ }
if(geom->irtc != RTC_INVALID_GEOMETRY_ID) {
rtcDeleteGeometry(scn->rtc_scn, geom->irtc);
geom->irtc = RTC_INVALID_GEOMETRY_ID;
@@ -77,6 +343,77 @@ scene_detach_shape(struct s2d_scene* scn, struct s2d_shape* shape)
list_del(&shape->scene_attachment);
S2D(shape_ref_put(shape));
+ return RES_OK;
+}
+
+static void
+scene_compute_aabb(struct s2d_scene* scn)
+{
+ struct list_node* node;
+ struct s2d_shape* shape;
+ struct geometry** pgeom;
+ struct geometry* geom;
+ float lower[2], upper[2];
+
+ f2_splat(scn->lower, FLT_MAX);
+ f2_splat(scn->upper,-FLT_MAX);
+
+ LIST_FOR_EACH(node, &scn->shapes) {
+ shape = CONTAINER_OF(node, struct s2d_shape, scene_attachment);
+ pgeom = htable_geom_find(&scn->cached_geoms, &shape);
+ ASSERT(pgeom != NULL);
+ geom = *pgeom;
+
+ if(!geom->is_enabled) continue;
+
+ line_segments_compute_aabb(geom->lines, lower, upper);
+ f2_min(scn->lower, scn->lower, lower);
+ f2_max(scn->upper, scn->upper, upper);
+ }
+}
+
+static res_T
+scene_sync
+ (struct s2d_scene* scn, const int session_mask, const char* caller_name)
+{
+ struct list_node* node;
+ struct s2d_shape* shape;
+ res_T res = RES_OK;
+ ASSERT(scn);
+
+ if(scn->session_mask != 0) {
+ if(scn->dev->verbose) {
+ logger_print(scn->dev->logger, LOG_ERROR,
+ "%s: Invalid operation. The scene cannot be synced several times.\n",
+ caller_name);
+ }
+ res = RES_BAD_OP;
+ goto error;
+ }
+
+ LIST_FOR_EACH(node, &scn->shapes) {
+ shape = CONTAINER_OF(node, struct s2d_shape, scene_attachment);
+ res = scene_register_line_segments(scn, shape);
+ if(res != RES_OK) goto error;
+ }
+
+ if((session_mask & S2D_SAMPLE) != 0) {
+ FATAL("The S2D_SAMPLE session is not implemented yet!\n");
+ }
+ if((session_mask & S2D_GET_PRIMITIVE) != 0) {
+ FATAL("The S2D_GET_PRIMITIVE session is not implemented yet!\n");
+ }
+ if((session_mask & S2D_TRACE) != 0 && scn->is_rtc_scn_outdated) {
+ rtcCommit(scn->rtc_scn);
+ scn->is_rtc_scn_outdated = 0;
+ }
+ scn->session_mask = session_mask;
+ scene_compute_aabb(scn);
+
+exit:
+ return res;
+error:
+ goto exit;
}
static void
@@ -186,16 +523,11 @@ s2d_scene_attach_shape(struct s2d_scene* scn, struct s2d_shape* shape)
res_T
s2d_scene_detach_shape(struct s2d_scene* scn, struct s2d_shape* shape)
{
+ res_T res = RES_OK;
char is_attached;
+
+
if(!scn || !shape) return RES_BAD_ARG;
- if(scn->session_mask != 0) {
- if(scn->dev->verbose) {
- logger_print(scn->dev->logger, LOG_ERROR,
- "%s: Cannot detach a shape while a session is active onto the scene.\n",
- __FUNCTION__);
- }
- return RES_BAD_OP;
- }
if(!(S2D(shape_is_attached(shape, &is_attached)), is_attached)) {
if(scn->dev->verbose) {
logger_print(scn->dev->logger, LOG_ERROR,
@@ -217,7 +549,9 @@ s2d_scene_detach_shape(struct s2d_scene* scn, struct s2d_shape* shape)
ASSERT(is_found);
}
#endif
- scene_detach_shape(scn, shape);
+ res = scene_detach_shape(scn, shape, __FUNCTION__);
+ if(res != RES_OK) return res;
+
return RES_OK;
}
@@ -237,8 +571,52 @@ s2d_scene_clear(struct s2d_scene* scn)
LIST_FOR_EACH_SAFE(node, tmp, &scn->shapes) {
struct s2d_shape* shape = CONTAINER_OF
(node, struct s2d_shape, scene_attachment);
- scene_detach_shape(scn, shape);
+ res_T res = scene_detach_shape(scn, shape, __FUNCTION__);
+ ASSERT(res == RES_OK); (void)res;
+ }
+ return RES_OK;
+}
+
+res_T
+s2d_scene_begin_session(struct s2d_scene* scn, const int session_mask)
+{
+ if(!scn) return RES_BAD_ARG;
+ if(!(session_mask & S2D_TRACE)
+ && !(session_mask & S2D_SAMPLE)
+ && !(session_mask & S2D_GET_PRIMITIVE)) {
+ if(scn->dev->verbose) {
+ logger_print(scn->dev->logger, LOG_ERROR,
+ "%s: Invalid session mask. No valid session is defined.\n",
+ __FUNCTION__);
+ }
+ return RES_BAD_ARG;
}
+ return scene_sync(scn, session_mask, __FUNCTION__);
+}
+
+res_T
+s2d_scene_end_session(struct s2d_scene* scn)
+{
+ if(!scn)
+ return RES_BAD_ARG;
+ if(!scn->session_mask) {
+ if(scn->dev->verbose) {
+ logger_print(scn->dev->logger, LOG_ERROR,
+ "%s: Cannot end session. No session is currently active onto the scene.\n",
+ __FUNCTION__);
+ }
+ return RES_BAD_ARG;
+ }
+ scene_session_clear(scn);
+ return RES_OK;
+}
+
+res_T
+s2d_scene_get_session_mask(struct s2d_scene* scn, int* session_mask)
+{
+ if(!scn || !session_mask)
+ return RES_BAD_ARG;
+ *session_mask = scn->session_mask;
return RES_OK;
}
diff --git a/src/s2d_shape.c b/src/s2d_shape.c
@@ -48,7 +48,7 @@ shape_release(ref_T* ref)
/* The shape should not be attached */
ASSERT(is_list_empty(&shape->scene_attachment));
- line_segments_ref_put(shape->line);
+ line_segments_ref_put(shape->lines);
MEM_RM(dev->allocator, shape);
S2D(device_ref_put(dev));
}
@@ -81,7 +81,7 @@ s2d_shape_create_line_segments
shape->is_enabled = 1;
shape->flip_contour = 0;
- res = line_segments_create(dev, &shape->line);
+ res = line_segments_create(dev, &shape->lines);
if(res != RES_OK) goto error;
exit:
@@ -164,7 +164,7 @@ s2d_line_segments_setup_indexed_vertices
{
if(!shape) return RES_BAD_ARG;
return line_segments_setup_indexed_vertices
- (shape->line, nsegments, get_indices, nverts, attribs, nattribs, data);
+ (shape->lines, nsegments, get_indices, nverts, attribs, nattribs, data);
}
res_T
@@ -174,7 +174,7 @@ s2d_line_segments_copy(const struct s2d_shape* src, struct s2d_shape* dst)
if(src == dst) return RES_OK;
dst->flip_contour = src->flip_contour;
dst->is_enabled = src->is_enabled;
- line_segments_copy_indexed_vertices(src->line, dst->line);
+ line_segments_copy_indexed_vertices(src->lines, dst->lines);
return RES_OK;
}
@@ -183,7 +183,7 @@ s2d_line_segments_get_vertices_count
(const struct s2d_shape* shape, unsigned* nverts)
{
if(!shape || !nverts) return RES_BAD_ARG;
- *nverts = (unsigned)line_segments_get_nverts(shape->line);
+ *nverts = (unsigned)line_segments_get_nverts(shape->lines);
return RES_OK;
}
@@ -199,16 +199,16 @@ s2d_line_segments_get_vertex_attrib
if(!shape
|| (unsigned)usage >= S2D_ATTRIBS_COUNT__
- || !shape->line->attribs[usage]
+ || !shape->lines->attribs[usage]
|| !attrib
- || ivert >= (unsigned)line_segments_get_nverts(shape->line))
+ || ivert >= (unsigned)line_segments_get_nverts(shape->lines))
return RES_BAD_ARG;
attrib->usage = usage;
- attrib->type = shape->line->attribs_type[usage];
+ attrib->type = shape->lines->attribs_type[usage];
dim = s2d_type_get_dimension(attrib->type);
- data = line_segments_get_attr(shape->line, usage) + ivert * dim;
+ data = line_segments_get_attr(shape->lines, usage) + ivert * dim;
FOR_EACH(i, 0, dim) attrib->value[i] = data[i];
return RES_OK;
}
@@ -218,7 +218,7 @@ s2d_line_segments_get_segments_count
(const struct s2d_shape* shape, unsigned* nsegments)
{
if(!shape || !nsegments) return RES_BAD_ARG;
- *nsegments = (unsigned)line_segments_get_nsegments(shape->line);
+ *nsegments = (unsigned)line_segments_get_nsegments(shape->lines);
return RES_OK;
}
@@ -231,10 +231,10 @@ s2d_line_segments_get_segment_indices
const unsigned* data;
if(!shape
|| !ids
- || isegment >= (unsigned)line_segments_get_nsegments(shape->line))
+ || isegment >= (unsigned)line_segments_get_nsegments(shape->lines))
return RES_BAD_ARG;
- data = line_segments_get_ids(shape->line) + isegment * 2/*#ids per segment*/;
+ data = line_segments_get_ids(shape->lines) + isegment * 2/*#ids per segment*/;
ids[0] = data[0];
ids[1] = data[1];
return RES_OK;
@@ -247,8 +247,8 @@ s2d_line_segments_set_hit_filter_function
void* data)
{
if(!shape) return RES_BAD_ARG;
- shape->line->filter.func = func;
- shape->line->filter.data = data;
+ shape->lines->filter.func = func;
+ shape->lines->filter.data = data;
return RES_OK;
}
@@ -256,7 +256,7 @@ res_T
s2d_line_segments_get_hit_filter_data(struct s2d_shape* shape, void** data)
{
if(!shape || !data) return RES_BAD_ARG;
- *data = shape->line->filter.data;
+ *data = shape->lines->filter.data;
return RES_OK;
}
diff --git a/src/s2d_shape_c.h b/src/s2d_shape_c.h
@@ -42,7 +42,7 @@ struct s2d_shape {
char flip_contour;
char is_enabled;
- struct line_segments* line;
+ struct line_segments* lines;
struct s2d_device* dev;
ref_T ref;
};
diff --git a/src/test_s2d_scene.c b/src/test_s2d_scene.c
@@ -33,9 +33,11 @@ int
main(int argc, char** argv)
{
struct mem_allocator allocator;
+ struct s2d_vertex_data attrib;
struct s2d_device* dev;
struct s2d_scene* scn;
struct s2d_shape* shape;
+ int mask;
(void)argc, (void)argv;
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
@@ -74,6 +76,40 @@ main(int argc, char** argv)
CHECK(s2d_scene_attach_shape(scn, shape), RES_OK);
CHECK(s2d_scene_clear(scn), RES_OK);
+ CHECK(s2d_scene_begin_session(NULL, 0), RES_BAD_ARG);
+ CHECK(s2d_scene_begin_session(scn, 0), RES_BAD_ARG);
+ CHECK(s2d_scene_begin_session(NULL, S2D_TRACE), RES_BAD_ARG);
+ CHECK(s2d_scene_begin_session(scn, S2D_TRACE), RES_OK);
+
+ CHECK(s2d_scene_get_session_mask(NULL, NULL), RES_BAD_ARG);
+ CHECK(s2d_scene_get_session_mask(scn, NULL), RES_BAD_ARG);
+ CHECK(s2d_scene_get_session_mask(NULL, &mask), RES_BAD_ARG);
+ CHECK(s2d_scene_get_session_mask(scn, &mask), RES_OK);
+ CHECK(mask, S2D_TRACE);
+
+ CHECK(s2d_scene_attach_shape(scn, shape), RES_OK);
+ CHECK(s2d_scene_clear(scn), RES_BAD_OP);
+ CHECK(s2d_scene_detach_shape(scn, shape), RES_OK);
+
+ CHECK(s2d_scene_end_session(NULL), RES_BAD_ARG);
+ CHECK(s2d_scene_end_session(scn), RES_OK);
+ CHECK(s2d_scene_end_session(scn), RES_BAD_ARG);
+ CHECK(s2d_scene_get_session_mask(scn, &mask), RES_OK);
+ CHECK(mask, 0);
+
+
+ attrib.type = S2D_FLOAT2;
+ attrib.usage = S2D_POSITION;
+ attrib.get = box_get_position;
+ CHECK(s2d_line_segments_setup_indexed_vertices
+ (shape, box_nsegs, box_get_ids, box_nverts, &attrib, 1, (void*)&box_desc),
+ RES_OK);
+
+ CHECK(s2d_scene_attach_shape(scn, shape), RES_OK);
+ CHECK(s2d_scene_begin_session(scn, S2D_TRACE), RES_OK);
+ CHECK(s2d_scene_detach_shape(scn, shape), RES_BAD_OP);
+ CHECK(s2d_scene_end_session(scn), RES_OK);
+
CHECK(s2d_shape_ref_put(shape), RES_OK);
CHECK(s2d_scene_ref_put(scn), RES_OK);
CHECK(s2d_device_ref_put(dev), RES_OK);