Skip to content

Commit

Permalink
Merge pull request #43 from sshirokov/more-verts-for-the-people
Browse files Browse the repository at this point in the history
Allow a polygon to exceed 40 vertices.
  • Loading branch information
sshirokov committed Sep 23, 2013
2 parents e42b987 + 25abdea commit 9d5db19
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 23 deletions.
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
csg (0.0.0)
csg (0.0.2)
ffi

GEM
Expand Down
2 changes: 1 addition & 1 deletion csg.gemspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Gem::Specification.new do |s|
s.name = 'csg'
s.version = '0.0.2'
s.version = '0.0.3'
s.summary = "A fast library for Constructive Solid Geometry"
s.description = s.summary
s.authors = ["Yaroslav Shirokov", "Sean Bryant"]
Expand Down
93 changes: 78 additions & 15 deletions src/bsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ int bsp_subdivide(poly_t *divider, poly_t *poly,
poly_t **coplanar_front, int *n_cp_front,
poly_t **coplanar_back, int *n_cp_back,
poly_t **front, int *n_front,
poly_t **back, int *n_back) {
poly_t **back, int *n_back,
poly_t **unused, int *n_unused,
poly_t **created, int *n_created) {
switch(poly_classify_poly(divider, poly)) {
case FRONT:
front[*n_front] = poly;
Expand Down Expand Up @@ -99,6 +101,21 @@ int bsp_subdivide(poly_t *divider, poly_t *poly,

back[*n_back] = b;
*n_back += 1;

// Do we care about telling the caller about polygons
// who's pointers are not in any of the "real" lists?
if(unused != NULL) {
unused[*n_unused] = poly;
*n_unused += 1;
}

// How about polygons that we just made?
if(created != NULL) {
created[*n_created] = f;
*n_created += 1;
created[*n_created] = b;
*n_created += 1;
}
break;
}
}
Expand All @@ -122,7 +139,7 @@ bsp_node_t *bsp_build(bsp_node_t *node, klist_t(poly) *polygons, int copy) {
polys[i] = poly;
}

check((node = bsp_build_array(node, polys, polygons->size)),
check((node = bsp_build_array(node, polys, polygons->size, copy)),
"Failed to build node from list(%p) of %zd polys", polygons, polygons->size);
free(polys);

Expand All @@ -131,7 +148,8 @@ bsp_node_t *bsp_build(bsp_node_t *node, klist_t(poly) *polygons, int copy) {
if(polys) free(polys);
return NULL;
}
bsp_node_t *bsp_build_array(bsp_node_t *node, poly_t **polygons, size_t n_polys) {

bsp_node_t *bsp_build_array(bsp_node_t *node, poly_t **polygons, size_t n_polys, int free_unused) {
int rc = 0;

// Polygon lists and counters
Expand All @@ -142,6 +160,14 @@ bsp_node_t *bsp_build_array(bsp_node_t *node, poly_t **polygons, size_t n_polys)
poly_t **front_p = NULL;
poly_t **back_p = NULL;

// List and counter of unused polygons
// These will get freed after the build
// because they will not appear with identity
// in coplanar, front_p, or back_p if free_unused
// is true
int n_unused = 0;
poly_t **unused = NULL;

// Iterators
poly_t *poly = NULL;
size_t poly_i = 0;
Expand Down Expand Up @@ -172,20 +198,34 @@ bsp_node_t *bsp_build_array(bsp_node_t *node, poly_t **polygons, size_t n_polys)
check_mem(coplanar = malloc(sizeof(poly_t*) * n_polys));
check_mem(front_p = malloc(sizeof(poly_t*) * n_polys));
check_mem(back_p = malloc(sizeof(poly_t*) * n_polys));
check_mem(unused = malloc(sizeof(poly_t*) * n_polys));
for(; poly_i < n_polys; poly_i++) {
poly = polygons[poly_i];
rc = bsp_subdivide(node->divider, poly,
coplanar, &n_coplanar,
coplanar, &n_coplanar,
front_p, &n_front,
back_p, &n_back);
back_p, &n_back,
unused, &n_unused,
NULL, NULL);
check(rc == 0, "Failed to subdivide: %p => %p", node->divider, poly);
}

// Destroy the unused polygons now, if we're asked,
// otherwise we'll lose the references
int i = 0;
if(free_unused != 0) {
for(i = 0; i < n_unused; i++) {
free_poly(unused[i], 1);
}
}
// Free now and mark NULL to make sure it's not double free'd on `error:`
free(unused);
unused = NULL;

// Store the coplanar nodes in this node's polygon list
// and free the container, letting the list destructor
// clean up
int i = 0;
for(i = 0; i < n_coplanar; i++) {
*kl_pushp(poly, node->polygons) = coplanar[i];
}
Expand All @@ -195,13 +235,13 @@ bsp_node_t *bsp_build_array(bsp_node_t *node, poly_t **polygons, size_t n_polys)
if((n_front > 0)) {
if(node->front == NULL) node->front = alloc_bsp_node();
check_mem(node->front);
check(bsp_build_array(node->front, front_p, n_front) != NULL,
check(bsp_build_array(node->front, front_p, n_front, free_unused) != NULL,
"Failed to build front tree of bsp_node_array(%p)", node);
}
if((n_back > 0)) {
if(node->back == NULL) node->back = alloc_bsp_node();
check_mem(node->back);
check(bsp_build_array(node->back, back_p, n_back) != NULL,
check(bsp_build_array(node->back, back_p, n_back, free_unused) != NULL,
"Failed to build back tree of bsp_node(%p)", node);
}
free(front_p);
Expand All @@ -213,6 +253,7 @@ bsp_node_t *bsp_build_array(bsp_node_t *node, poly_t **polygons, size_t n_polys)
if(coplanar) free(coplanar);
if(back_p) free(back_p);
if(front_p) free(front_p);
if(unused) free(unused);
return NULL;
}

Expand Down Expand Up @@ -316,24 +357,28 @@ klist_t(poly) *bsp_clip_polygon_array(bsp_node_t *node, poly_t **polygons, size_
poly_t **poly_buffer = static_poly_buffer;
poly_t **front_array = NULL;
poly_t **back_array = NULL;
poly_t **created_array = NULL;
int n_front = 0;
int n_back = 0;
int n_created = 0;

// Let's end this quick if there's nothing to do.
if(n_polys == 0) return result;

if(node->divider != NULL) {
if((n_polys * 2) > STATIC_POLY_BUFFER_SIZE) {
check_mem(poly_buffer = malloc((sizeof(poly_t*) * n_polys) * 2));
if((n_polys * 3) > STATIC_POLY_BUFFER_SIZE) {
check_mem(poly_buffer = malloc((sizeof(poly_t*) * n_polys) * 3));
}
front_array = poly_buffer;
back_array = poly_buffer + n_polys;
created_array = poly_buffer + (n_polys * 2);
// Sort this node's polygons into the front or back
for(i = 0; i < n_polys; i++) {
p = polygons[i];
rc = bsp_subdivide(node->divider, p,
front_array, &n_front, back_array, &n_back,
front_array, &n_front, back_array, &n_back);
front_array, &n_front, back_array, &n_back,
NULL, NULL, created_array, &n_created);
check(rc != -1, "Failed to subdivide poly %p", p);
}

Expand All @@ -358,8 +403,15 @@ klist_t(poly) *bsp_clip_polygon_array(bsp_node_t *node, poly_t **polygons, size_
check(result != NULL, "Failed to clip back tree");
}

if(poly_buffer != static_poly_buffer) free(poly_buffer);
// Free all the polygons in 'created_array` since they would have
// been cloned if they were important, and the input set is not our
// responsibility
for(int j = 0; j < n_created; j++) {
free_poly(created_array[j], 1);
}

// Clean up the result halves, now that they're copied into `result`
if(poly_buffer != static_poly_buffer) free(poly_buffer);
}
else {
// If we don't have a divider we just copy out the polygons
Expand All @@ -386,23 +438,27 @@ klist_t(poly) *bsp_clip_polygons(bsp_node_t *node, klist_t(poly) *polygons, klis
poly_t **poly_buffer = static_poly_buffer;
poly_t **front_array = NULL;
poly_t **back_array = NULL;
poly_t **created_array = NULL;
int n_front = 0;
int n_back = 0;
int n_created = 0;

// Let's end this quick if there's nothing to do.
if(polygons->size == 0) return result;

if(node->divider != NULL) {
if((polygons->size * 2) > STATIC_POLY_BUFFER_SIZE) {
check_mem(poly_buffer = malloc(sizeof(poly_t*) * polygons->size * 2));
if((polygons->size * 3) > STATIC_POLY_BUFFER_SIZE) {
check_mem(poly_buffer = malloc(sizeof(poly_t*) * polygons->size * 3));
}
front_array = poly_buffer;
back_array = poly_buffer + polygons->size;
created_array = poly_buffer + (polygons->size * 2);
// Sort this node's polygons into the front or back
for(iter = kl_begin(polygons); iter != kl_end(polygons); iter = kl_next(iter)) {
rc = bsp_subdivide(node->divider, kl_val(iter),
front_array, &n_front, back_array, &n_back,
front_array, &n_front, back_array, &n_back);
front_array, &n_front, back_array, &n_back,
NULL, NULL, created_array, &n_created);
check(rc != -1, "Failed to subdivide poly %p", kl_val(iter));
}

Expand All @@ -427,8 +483,15 @@ klist_t(poly) *bsp_clip_polygons(bsp_node_t *node, klist_t(poly) *polygons, klis
check(result != NULL, "Failed to clip back tree");
}

// Free all the polygons in 'created_array` since they would have
// been cloned if they were important, and the input set is not our
// responsibility
for(int j = 0; j < n_created; j++) {
free_poly(created_array[j], 1);
}


if(poly_buffer != static_poly_buffer) free(poly_buffer);
// Clean up the result halves, now that they're copied into `result`
}
else {
// If we don't have a divider we just copy out the polygons
Expand Down
6 changes: 4 additions & 2 deletions src/bsp.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@ int bsp_subdivide(poly_t *divider, poly_t *poly,
poly_t **coplanar_front, int *n_cp_front,
poly_t **coplanar_back, int *n_cp_back,
poly_t **front, int *n_front,
poly_t **back, int *n_back);
poly_t **back, int *n_back,
poly_t **unused, int *n_unused,
poly_t **created, int *n_created);

bsp_node_t *bsp_build(bsp_node_t *node, klist_t(poly) *polygons, int copy);
bsp_node_t *bsp_build_array(bsp_node_t *node, poly_t **polygons, size_t n_polys);
bsp_node_t *bsp_build_array(bsp_node_t *node, poly_t **polygons, size_t n_polys, int free_unused);
klist_t(poly) *bsp_to_polygons(bsp_node_t *tree, int make_triangles, klist_t(poly) *dst);

bsp_node_t *bsp_invert(bsp_node_t *tree);
Expand Down
64 changes: 61 additions & 3 deletions src/poly.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,41 @@ poly_t *alloc_poly(void) {

void free_poly(poly_t *p, int free_self) {
if(p == NULL) return;
if(poly_vertex_dynamic_p(p) == 1) {
if(p->vertices != NULL) free(p->vertices);
p->vertices = NULL;
}
if(free_self) free(p);
}

poly_t *poly_init(poly_t *poly) {
poly->vertex_count = 0;
poly->vertex_max = POLY_MAX_VERTS;
poly->vertices = poly->_vbuffer;
return poly;
}

poly_t *clone_poly(poly_t *poly) {
poly_t *copy = NULL;
check_mem(copy = alloc_poly());
memcpy(copy, poly, sizeof(poly_t));

// Either point the clone at its own copied
// buffer, or copy over the dynamic vertex buffer
if(poly_vertex_dynamic_p(poly) == 0) {
copy->vertices = copy->_vbuffer;
}
else {
// We can lean on the `copy->*` memebers
// since they would have been memcpy'd over
copy->vertices = malloc(poly_vertex_max(copy) * sizeof(float3));
check_mem(copy->vertices);
memcpy(copy->vertices, poly->vertices, poly_vertex_max(copy) * sizeof(float3));
}

return copy;
error:
if(copy != NULL) free_poly(copy, 1);
return NULL;
}

Expand All @@ -53,10 +74,47 @@ int poly_vertex_count(poly_t *poly) {
return poly->vertex_count;
}

// Add a vertex to the end of the polygon vertex list
int poly_vertex_max(poly_t *poly) {
return poly->vertex_max;
}

int poly_vertex_available(poly_t *poly) {
return poly->vertex_max - poly->vertex_count;
}

// Has the vertex buffer been dynamically allocated?
int poly_vertex_dynamic_p(poly_t *poly) {
return (poly->vertices != poly->_vbuffer) ? 1 : 0;
}

int poly_vertex_expand(poly_t *poly) {
// Not using realloc because the original buffer may be struct-owned
int new_size = poly->vertex_max * 2;
float3 *new_verts = malloc(new_size * sizeof(float3));
check_mem(new_verts);

memcpy(new_verts, poly->vertices, poly->vertex_max * sizeof(float3));
poly->vertex_max = new_size;

// Free the existing buffer if it's not part of the struct's space
if(poly_vertex_dynamic_p(poly) == 1) {
free(poly->vertices);
}

// Install the new vertex buffer
poly->vertices = new_verts;

return 0;
error:
if(new_verts != NULL) free(new_verts);
return -1;
}

// add a vertex to the end of the polygon vertex list
int poly_push_vertex(poly_t *poly, float3 v) {
// TODO: Don't assert, grow
assert(poly->vertex_count < POLY_MAX_VERTS);
if(poly_vertex_available(poly) == 0) {
poly_vertex_expand(poly);
}

// Dat assignment copy
poly->vertices[poly->vertex_count][0] = v[0];
Expand Down
11 changes: 10 additions & 1 deletion src/poly.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,19 @@
#define BACK 2
#define SPANNING 3

#ifndef POLY_MAX_VERTS
#define POLY_MAX_VERTS 40
#endif

typedef struct s_poly {
float3 vertices[POLY_MAX_VERTS];
float3 *vertices;
int vertex_count;
int vertex_max;

float3 normal;
float w;

float3 _vbuffer[POLY_MAX_VERTS];
} poly_t;

poly_t *alloc_poly(void);
Expand All @@ -32,6 +37,10 @@ int poly_update(poly_t *poly);
poly_t *poly_invert(poly_t *poly);

int poly_vertex_count(poly_t *poly);
int poly_vertex_max(poly_t *poly);
int poly_vertex_available(poly_t *poly);
int poly_vertex_dynamic_p(poly_t *poly);
int poly_vertex_expand(poly_t *poly);
int poly_push_vertex(poly_t *poly, float3 v);

int poly_classify_vertex(poly_t *poly, float3 v);
Expand Down
Loading

0 comments on commit 9d5db19

Please sign in to comment.