Skip to content

Commit 9d5db19

Browse files
committed
Merge pull request #43 from sshirokov/more-verts-for-the-people
Allow a polygon to exceed 40 vertices.
2 parents e42b987 + 25abdea commit 9d5db19

File tree

7 files changed

+177
-23
lines changed

7 files changed

+177
-23
lines changed

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PATH
22
remote: .
33
specs:
4-
csg (0.0.0)
4+
csg (0.0.2)
55
ffi
66

77
GEM

csg.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Gem::Specification.new do |s|
22
s.name = 'csg'
3-
s.version = '0.0.2'
3+
s.version = '0.0.3'
44
s.summary = "A fast library for Constructive Solid Geometry"
55
s.description = s.summary
66
s.authors = ["Yaroslav Shirokov", "Sean Bryant"]

src/bsp.c

Lines changed: 78 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,9 @@ int bsp_subdivide(poly_t *divider, poly_t *poly,
6969
poly_t **coplanar_front, int *n_cp_front,
7070
poly_t **coplanar_back, int *n_cp_back,
7171
poly_t **front, int *n_front,
72-
poly_t **back, int *n_back) {
72+
poly_t **back, int *n_back,
73+
poly_t **unused, int *n_unused,
74+
poly_t **created, int *n_created) {
7375
switch(poly_classify_poly(divider, poly)) {
7476
case FRONT:
7577
front[*n_front] = poly;
@@ -99,6 +101,21 @@ int bsp_subdivide(poly_t *divider, poly_t *poly,
99101

100102
back[*n_back] = b;
101103
*n_back += 1;
104+
105+
// Do we care about telling the caller about polygons
106+
// who's pointers are not in any of the "real" lists?
107+
if(unused != NULL) {
108+
unused[*n_unused] = poly;
109+
*n_unused += 1;
110+
}
111+
112+
// How about polygons that we just made?
113+
if(created != NULL) {
114+
created[*n_created] = f;
115+
*n_created += 1;
116+
created[*n_created] = b;
117+
*n_created += 1;
118+
}
102119
break;
103120
}
104121
}
@@ -122,7 +139,7 @@ bsp_node_t *bsp_build(bsp_node_t *node, klist_t(poly) *polygons, int copy) {
122139
polys[i] = poly;
123140
}
124141

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

@@ -131,7 +148,8 @@ bsp_node_t *bsp_build(bsp_node_t *node, klist_t(poly) *polygons, int copy) {
131148
if(polys) free(polys);
132149
return NULL;
133150
}
134-
bsp_node_t *bsp_build_array(bsp_node_t *node, poly_t **polygons, size_t n_polys) {
151+
152+
bsp_node_t *bsp_build_array(bsp_node_t *node, poly_t **polygons, size_t n_polys, int free_unused) {
135153
int rc = 0;
136154

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

163+
// List and counter of unused polygons
164+
// These will get freed after the build
165+
// because they will not appear with identity
166+
// in coplanar, front_p, or back_p if free_unused
167+
// is true
168+
int n_unused = 0;
169+
poly_t **unused = NULL;
170+
145171
// Iterators
146172
poly_t *poly = NULL;
147173
size_t poly_i = 0;
@@ -172,20 +198,34 @@ bsp_node_t *bsp_build_array(bsp_node_t *node, poly_t **polygons, size_t n_polys)
172198
check_mem(coplanar = malloc(sizeof(poly_t*) * n_polys));
173199
check_mem(front_p = malloc(sizeof(poly_t*) * n_polys));
174200
check_mem(back_p = malloc(sizeof(poly_t*) * n_polys));
201+
check_mem(unused = malloc(sizeof(poly_t*) * n_polys));
175202
for(; poly_i < n_polys; poly_i++) {
176203
poly = polygons[poly_i];
177204
rc = bsp_subdivide(node->divider, poly,
178205
coplanar, &n_coplanar,
179206
coplanar, &n_coplanar,
180207
front_p, &n_front,
181-
back_p, &n_back);
208+
back_p, &n_back,
209+
unused, &n_unused,
210+
NULL, NULL);
182211
check(rc == 0, "Failed to subdivide: %p => %p", node->divider, poly);
183212
}
184213

214+
// Destroy the unused polygons now, if we're asked,
215+
// otherwise we'll lose the references
216+
int i = 0;
217+
if(free_unused != 0) {
218+
for(i = 0; i < n_unused; i++) {
219+
free_poly(unused[i], 1);
220+
}
221+
}
222+
// Free now and mark NULL to make sure it's not double free'd on `error:`
223+
free(unused);
224+
unused = NULL;
225+
185226
// Store the coplanar nodes in this node's polygon list
186227
// and free the container, letting the list destructor
187228
// clean up
188-
int i = 0;
189229
for(i = 0; i < n_coplanar; i++) {
190230
*kl_pushp(poly, node->polygons) = coplanar[i];
191231
}
@@ -195,13 +235,13 @@ bsp_node_t *bsp_build_array(bsp_node_t *node, poly_t **polygons, size_t n_polys)
195235
if((n_front > 0)) {
196236
if(node->front == NULL) node->front = alloc_bsp_node();
197237
check_mem(node->front);
198-
check(bsp_build_array(node->front, front_p, n_front) != NULL,
238+
check(bsp_build_array(node->front, front_p, n_front, free_unused) != NULL,
199239
"Failed to build front tree of bsp_node_array(%p)", node);
200240
}
201241
if((n_back > 0)) {
202242
if(node->back == NULL) node->back = alloc_bsp_node();
203243
check_mem(node->back);
204-
check(bsp_build_array(node->back, back_p, n_back) != NULL,
244+
check(bsp_build_array(node->back, back_p, n_back, free_unused) != NULL,
205245
"Failed to build back tree of bsp_node(%p)", node);
206246
}
207247
free(front_p);
@@ -213,6 +253,7 @@ bsp_node_t *bsp_build_array(bsp_node_t *node, poly_t **polygons, size_t n_polys)
213253
if(coplanar) free(coplanar);
214254
if(back_p) free(back_p);
215255
if(front_p) free(front_p);
256+
if(unused) free(unused);
216257
return NULL;
217258
}
218259

@@ -316,24 +357,28 @@ klist_t(poly) *bsp_clip_polygon_array(bsp_node_t *node, poly_t **polygons, size_
316357
poly_t **poly_buffer = static_poly_buffer;
317358
poly_t **front_array = NULL;
318359
poly_t **back_array = NULL;
360+
poly_t **created_array = NULL;
319361
int n_front = 0;
320362
int n_back = 0;
363+
int n_created = 0;
321364

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

325368
if(node->divider != NULL) {
326-
if((n_polys * 2) > STATIC_POLY_BUFFER_SIZE) {
327-
check_mem(poly_buffer = malloc((sizeof(poly_t*) * n_polys) * 2));
369+
if((n_polys * 3) > STATIC_POLY_BUFFER_SIZE) {
370+
check_mem(poly_buffer = malloc((sizeof(poly_t*) * n_polys) * 3));
328371
}
329372
front_array = poly_buffer;
330373
back_array = poly_buffer + n_polys;
374+
created_array = poly_buffer + (n_polys * 2);
331375
// Sort this node's polygons into the front or back
332376
for(i = 0; i < n_polys; i++) {
333377
p = polygons[i];
334378
rc = bsp_subdivide(node->divider, p,
335379
front_array, &n_front, back_array, &n_back,
336-
front_array, &n_front, back_array, &n_back);
380+
front_array, &n_front, back_array, &n_back,
381+
NULL, NULL, created_array, &n_created);
337382
check(rc != -1, "Failed to subdivide poly %p", p);
338383
}
339384

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

361-
if(poly_buffer != static_poly_buffer) free(poly_buffer);
406+
// Free all the polygons in 'created_array` since they would have
407+
// been cloned if they were important, and the input set is not our
408+
// responsibility
409+
for(int j = 0; j < n_created; j++) {
410+
free_poly(created_array[j], 1);
411+
}
412+
362413
// Clean up the result halves, now that they're copied into `result`
414+
if(poly_buffer != static_poly_buffer) free(poly_buffer);
363415
}
364416
else {
365417
// If we don't have a divider we just copy out the polygons
@@ -386,23 +438,27 @@ klist_t(poly) *bsp_clip_polygons(bsp_node_t *node, klist_t(poly) *polygons, klis
386438
poly_t **poly_buffer = static_poly_buffer;
387439
poly_t **front_array = NULL;
388440
poly_t **back_array = NULL;
441+
poly_t **created_array = NULL;
389442
int n_front = 0;
390443
int n_back = 0;
444+
int n_created = 0;
391445

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

395449
if(node->divider != NULL) {
396-
if((polygons->size * 2) > STATIC_POLY_BUFFER_SIZE) {
397-
check_mem(poly_buffer = malloc(sizeof(poly_t*) * polygons->size * 2));
450+
if((polygons->size * 3) > STATIC_POLY_BUFFER_SIZE) {
451+
check_mem(poly_buffer = malloc(sizeof(poly_t*) * polygons->size * 3));
398452
}
399453
front_array = poly_buffer;
400454
back_array = poly_buffer + polygons->size;
455+
created_array = poly_buffer + (polygons->size * 2);
401456
// Sort this node's polygons into the front or back
402457
for(iter = kl_begin(polygons); iter != kl_end(polygons); iter = kl_next(iter)) {
403458
rc = bsp_subdivide(node->divider, kl_val(iter),
404459
front_array, &n_front, back_array, &n_back,
405-
front_array, &n_front, back_array, &n_back);
460+
front_array, &n_front, back_array, &n_back,
461+
NULL, NULL, created_array, &n_created);
406462
check(rc != -1, "Failed to subdivide poly %p", kl_val(iter));
407463
}
408464

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

486+
// Free all the polygons in 'created_array` since they would have
487+
// been cloned if they were important, and the input set is not our
488+
// responsibility
489+
for(int j = 0; j < n_created; j++) {
490+
free_poly(created_array[j], 1);
491+
}
492+
493+
430494
if(poly_buffer != static_poly_buffer) free(poly_buffer);
431-
// Clean up the result halves, now that they're copied into `result`
432495
}
433496
else {
434497
// If we don't have a divider we just copy out the polygons

src/bsp.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@ int bsp_subdivide(poly_t *divider, poly_t *poly,
3333
poly_t **coplanar_front, int *n_cp_front,
3434
poly_t **coplanar_back, int *n_cp_back,
3535
poly_t **front, int *n_front,
36-
poly_t **back, int *n_back);
36+
poly_t **back, int *n_back,
37+
poly_t **unused, int *n_unused,
38+
poly_t **created, int *n_created);
3739

3840
bsp_node_t *bsp_build(bsp_node_t *node, klist_t(poly) *polygons, int copy);
39-
bsp_node_t *bsp_build_array(bsp_node_t *node, poly_t **polygons, size_t n_polys);
41+
bsp_node_t *bsp_build_array(bsp_node_t *node, poly_t **polygons, size_t n_polys, int free_unused);
4042
klist_t(poly) *bsp_to_polygons(bsp_node_t *tree, int make_triangles, klist_t(poly) *dst);
4143

4244
bsp_node_t *bsp_invert(bsp_node_t *tree);

src/poly.c

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,41 @@ poly_t *alloc_poly(void) {
1313

1414
void free_poly(poly_t *p, int free_self) {
1515
if(p == NULL) return;
16+
if(poly_vertex_dynamic_p(p) == 1) {
17+
if(p->vertices != NULL) free(p->vertices);
18+
p->vertices = NULL;
19+
}
1620
if(free_self) free(p);
1721
}
1822

1923
poly_t *poly_init(poly_t *poly) {
2024
poly->vertex_count = 0;
25+
poly->vertex_max = POLY_MAX_VERTS;
26+
poly->vertices = poly->_vbuffer;
2127
return poly;
2228
}
2329

2430
poly_t *clone_poly(poly_t *poly) {
2531
poly_t *copy = NULL;
2632
check_mem(copy = alloc_poly());
2733
memcpy(copy, poly, sizeof(poly_t));
34+
35+
// Either point the clone at its own copied
36+
// buffer, or copy over the dynamic vertex buffer
37+
if(poly_vertex_dynamic_p(poly) == 0) {
38+
copy->vertices = copy->_vbuffer;
39+
}
40+
else {
41+
// We can lean on the `copy->*` memebers
42+
// since they would have been memcpy'd over
43+
copy->vertices = malloc(poly_vertex_max(copy) * sizeof(float3));
44+
check_mem(copy->vertices);
45+
memcpy(copy->vertices, poly->vertices, poly_vertex_max(copy) * sizeof(float3));
46+
}
47+
2848
return copy;
2949
error:
50+
if(copy != NULL) free_poly(copy, 1);
3051
return NULL;
3152
}
3253

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

56-
// Add a vertex to the end of the polygon vertex list
77+
int poly_vertex_max(poly_t *poly) {
78+
return poly->vertex_max;
79+
}
80+
81+
int poly_vertex_available(poly_t *poly) {
82+
return poly->vertex_max - poly->vertex_count;
83+
}
84+
85+
// Has the vertex buffer been dynamically allocated?
86+
int poly_vertex_dynamic_p(poly_t *poly) {
87+
return (poly->vertices != poly->_vbuffer) ? 1 : 0;
88+
}
89+
90+
int poly_vertex_expand(poly_t *poly) {
91+
// Not using realloc because the original buffer may be struct-owned
92+
int new_size = poly->vertex_max * 2;
93+
float3 *new_verts = malloc(new_size * sizeof(float3));
94+
check_mem(new_verts);
95+
96+
memcpy(new_verts, poly->vertices, poly->vertex_max * sizeof(float3));
97+
poly->vertex_max = new_size;
98+
99+
// Free the existing buffer if it's not part of the struct's space
100+
if(poly_vertex_dynamic_p(poly) == 1) {
101+
free(poly->vertices);
102+
}
103+
104+
// Install the new vertex buffer
105+
poly->vertices = new_verts;
106+
107+
return 0;
108+
error:
109+
if(new_verts != NULL) free(new_verts);
110+
return -1;
111+
}
112+
113+
// add a vertex to the end of the polygon vertex list
57114
int poly_push_vertex(poly_t *poly, float3 v) {
58-
// TODO: Don't assert, grow
59-
assert(poly->vertex_count < POLY_MAX_VERTS);
115+
if(poly_vertex_available(poly) == 0) {
116+
poly_vertex_expand(poly);
117+
}
60118

61119
// Dat assignment copy
62120
poly->vertices[poly->vertex_count][0] = v[0];

src/poly.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,19 @@
1212
#define BACK 2
1313
#define SPANNING 3
1414

15+
#ifndef POLY_MAX_VERTS
1516
#define POLY_MAX_VERTS 40
17+
#endif
1618

1719
typedef struct s_poly {
18-
float3 vertices[POLY_MAX_VERTS];
20+
float3 *vertices;
1921
int vertex_count;
22+
int vertex_max;
2023

2124
float3 normal;
2225
float w;
26+
27+
float3 _vbuffer[POLY_MAX_VERTS];
2328
} poly_t;
2429

2530
poly_t *alloc_poly(void);
@@ -32,6 +37,10 @@ int poly_update(poly_t *poly);
3237
poly_t *poly_invert(poly_t *poly);
3338

3439
int poly_vertex_count(poly_t *poly);
40+
int poly_vertex_max(poly_t *poly);
41+
int poly_vertex_available(poly_t *poly);
42+
int poly_vertex_dynamic_p(poly_t *poly);
43+
int poly_vertex_expand(poly_t *poly);
3544
int poly_push_vertex(poly_t *poly, float3 v);
3645

3746
int poly_classify_vertex(poly_t *poly, float3 v);

0 commit comments

Comments
 (0)