csg 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Makefile +7 -1
- data/src/bsp.c +78 -15
- data/src/bsp.h +4 -2
- data/src/commands.c +105 -0
- data/src/commands.h +17 -0
- data/src/poly.c +61 -3
- data/src/poly.h +10 -1
- metadata +11 -13
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0156d8c17eb3aa465dccdec30ce073b111c15f31
|
4
|
+
data.tar.gz: ffc2a35116bdd1cdd181943ae3e40ef51fcf5e88
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9dce1d39a95353b489193bcfa6427127e87b99e2de342e0d571e65678a6c0785dc9b86a53b0f4a5f4e8058a3c8d0050979e7b54002c04275d051cd845073dfe2
|
7
|
+
data.tar.gz: c4f6ec8bf5905402348f7daec9d3db3994aeb237bf9eb49d5057eaa5bd7ab7ce7c9ecda037c5e2274e6aa448c9d0a9fd9877822fafc2daee535543e8cd2667ff
|
data/Makefile
CHANGED
@@ -26,7 +26,7 @@ clean:
|
|
26
26
|
test:
|
27
27
|
@make -C tests clean test
|
28
28
|
|
29
|
-
.PHONY: all clean test libcsg
|
29
|
+
.PHONY: all clean test libcsg loc
|
30
30
|
|
31
31
|
$(TARGET): $(TARGET).o $(OBJS)
|
32
32
|
$(CC) $(CFLAGS) $^ $(LIBS) -o $@.new
|
@@ -39,3 +39,9 @@ libcsg: $(LIB_TARGET)
|
|
39
39
|
|
40
40
|
%.o: %.c
|
41
41
|
$(CC) -fPIC $(CFLAGS) -o $@ -c $^
|
42
|
+
|
43
|
+
loc:
|
44
|
+
@echo "=> Source:"
|
45
|
+
find src/ -name '*.[ch]' -not -name 'dbg.*' | xargs wc -l csgtool.c
|
46
|
+
@echo "=> Tests:"
|
47
|
+
find tests/ -name '*.[ch]' -not -path '*clar*' | xargs wc -l
|
data/src/bsp.c
CHANGED
@@ -69,7 +69,9 @@ int bsp_subdivide(poly_t *divider, poly_t *poly,
|
|
69
69
|
poly_t **coplanar_front, int *n_cp_front,
|
70
70
|
poly_t **coplanar_back, int *n_cp_back,
|
71
71
|
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) {
|
73
75
|
switch(poly_classify_poly(divider, poly)) {
|
74
76
|
case FRONT:
|
75
77
|
front[*n_front] = poly;
|
@@ -99,6 +101,21 @@ int bsp_subdivide(poly_t *divider, poly_t *poly,
|
|
99
101
|
|
100
102
|
back[*n_back] = b;
|
101
103
|
*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
|
+
}
|
102
119
|
break;
|
103
120
|
}
|
104
121
|
}
|
@@ -122,7 +139,7 @@ bsp_node_t *bsp_build(bsp_node_t *node, klist_t(poly) *polygons, int copy) {
|
|
122
139
|
polys[i] = poly;
|
123
140
|
}
|
124
141
|
|
125
|
-
check((node = bsp_build_array(node, polys, polygons->size)),
|
142
|
+
check((node = bsp_build_array(node, polys, polygons->size, copy)),
|
126
143
|
"Failed to build node from list(%p) of %zd polys", polygons, polygons->size);
|
127
144
|
free(polys);
|
128
145
|
|
@@ -131,7 +148,8 @@ error:
|
|
131
148
|
if(polys) free(polys);
|
132
149
|
return NULL;
|
133
150
|
}
|
134
|
-
|
151
|
+
|
152
|
+
bsp_node_t *bsp_build_array(bsp_node_t *node, poly_t **polygons, size_t n_polys, int free_unused) {
|
135
153
|
int rc = 0;
|
136
154
|
|
137
155
|
// 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)
|
|
142
160
|
poly_t **front_p = NULL;
|
143
161
|
poly_t **back_p = NULL;
|
144
162
|
|
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
|
+
|
145
171
|
// Iterators
|
146
172
|
poly_t *poly = NULL;
|
147
173
|
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)
|
|
172
198
|
check_mem(coplanar = malloc(sizeof(poly_t*) * n_polys));
|
173
199
|
check_mem(front_p = malloc(sizeof(poly_t*) * n_polys));
|
174
200
|
check_mem(back_p = malloc(sizeof(poly_t*) * n_polys));
|
201
|
+
check_mem(unused = malloc(sizeof(poly_t*) * n_polys));
|
175
202
|
for(; poly_i < n_polys; poly_i++) {
|
176
203
|
poly = polygons[poly_i];
|
177
204
|
rc = bsp_subdivide(node->divider, poly,
|
178
205
|
coplanar, &n_coplanar,
|
179
206
|
coplanar, &n_coplanar,
|
180
207
|
front_p, &n_front,
|
181
|
-
back_p, &n_back
|
208
|
+
back_p, &n_back,
|
209
|
+
unused, &n_unused,
|
210
|
+
NULL, NULL);
|
182
211
|
check(rc == 0, "Failed to subdivide: %p => %p", node->divider, poly);
|
183
212
|
}
|
184
213
|
|
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
|
+
|
185
226
|
// Store the coplanar nodes in this node's polygon list
|
186
227
|
// and free the container, letting the list destructor
|
187
228
|
// clean up
|
188
|
-
int i = 0;
|
189
229
|
for(i = 0; i < n_coplanar; i++) {
|
190
230
|
*kl_pushp(poly, node->polygons) = coplanar[i];
|
191
231
|
}
|
@@ -195,13 +235,13 @@ bsp_node_t *bsp_build_array(bsp_node_t *node, poly_t **polygons, size_t n_polys)
|
|
195
235
|
if((n_front > 0)) {
|
196
236
|
if(node->front == NULL) node->front = alloc_bsp_node();
|
197
237
|
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,
|
199
239
|
"Failed to build front tree of bsp_node_array(%p)", node);
|
200
240
|
}
|
201
241
|
if((n_back > 0)) {
|
202
242
|
if(node->back == NULL) node->back = alloc_bsp_node();
|
203
243
|
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,
|
205
245
|
"Failed to build back tree of bsp_node(%p)", node);
|
206
246
|
}
|
207
247
|
free(front_p);
|
@@ -213,6 +253,7 @@ error:
|
|
213
253
|
if(coplanar) free(coplanar);
|
214
254
|
if(back_p) free(back_p);
|
215
255
|
if(front_p) free(front_p);
|
256
|
+
if(unused) free(unused);
|
216
257
|
return NULL;
|
217
258
|
}
|
218
259
|
|
@@ -316,24 +357,28 @@ klist_t(poly) *bsp_clip_polygon_array(bsp_node_t *node, poly_t **polygons, size_
|
|
316
357
|
poly_t **poly_buffer = static_poly_buffer;
|
317
358
|
poly_t **front_array = NULL;
|
318
359
|
poly_t **back_array = NULL;
|
360
|
+
poly_t **created_array = NULL;
|
319
361
|
int n_front = 0;
|
320
362
|
int n_back = 0;
|
363
|
+
int n_created = 0;
|
321
364
|
|
322
365
|
// Let's end this quick if there's nothing to do.
|
323
366
|
if(n_polys == 0) return result;
|
324
367
|
|
325
368
|
if(node->divider != NULL) {
|
326
|
-
if((n_polys *
|
327
|
-
check_mem(poly_buffer = malloc((sizeof(poly_t*) * n_polys) *
|
369
|
+
if((n_polys * 3) > STATIC_POLY_BUFFER_SIZE) {
|
370
|
+
check_mem(poly_buffer = malloc((sizeof(poly_t*) * n_polys) * 3));
|
328
371
|
}
|
329
372
|
front_array = poly_buffer;
|
330
373
|
back_array = poly_buffer + n_polys;
|
374
|
+
created_array = poly_buffer + (n_polys * 2);
|
331
375
|
// Sort this node's polygons into the front or back
|
332
376
|
for(i = 0; i < n_polys; i++) {
|
333
377
|
p = polygons[i];
|
334
378
|
rc = bsp_subdivide(node->divider, p,
|
335
379
|
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);
|
337
382
|
check(rc != -1, "Failed to subdivide poly %p", p);
|
338
383
|
}
|
339
384
|
|
@@ -358,8 +403,15 @@ klist_t(poly) *bsp_clip_polygon_array(bsp_node_t *node, poly_t **polygons, size_
|
|
358
403
|
check(result != NULL, "Failed to clip back tree");
|
359
404
|
}
|
360
405
|
|
361
|
-
|
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
|
+
|
362
413
|
// Clean up the result halves, now that they're copied into `result`
|
414
|
+
if(poly_buffer != static_poly_buffer) free(poly_buffer);
|
363
415
|
}
|
364
416
|
else {
|
365
417
|
// 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
|
|
386
438
|
poly_t **poly_buffer = static_poly_buffer;
|
387
439
|
poly_t **front_array = NULL;
|
388
440
|
poly_t **back_array = NULL;
|
441
|
+
poly_t **created_array = NULL;
|
389
442
|
int n_front = 0;
|
390
443
|
int n_back = 0;
|
444
|
+
int n_created = 0;
|
391
445
|
|
392
446
|
// Let's end this quick if there's nothing to do.
|
393
447
|
if(polygons->size == 0) return result;
|
394
448
|
|
395
449
|
if(node->divider != NULL) {
|
396
|
-
if((polygons->size *
|
397
|
-
check_mem(poly_buffer = malloc(sizeof(poly_t*) * polygons->size *
|
450
|
+
if((polygons->size * 3) > STATIC_POLY_BUFFER_SIZE) {
|
451
|
+
check_mem(poly_buffer = malloc(sizeof(poly_t*) * polygons->size * 3));
|
398
452
|
}
|
399
453
|
front_array = poly_buffer;
|
400
454
|
back_array = poly_buffer + polygons->size;
|
455
|
+
created_array = poly_buffer + (polygons->size * 2);
|
401
456
|
// Sort this node's polygons into the front or back
|
402
457
|
for(iter = kl_begin(polygons); iter != kl_end(polygons); iter = kl_next(iter)) {
|
403
458
|
rc = bsp_subdivide(node->divider, kl_val(iter),
|
404
459
|
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);
|
406
462
|
check(rc != -1, "Failed to subdivide poly %p", kl_val(iter));
|
407
463
|
}
|
408
464
|
|
@@ -427,8 +483,15 @@ klist_t(poly) *bsp_clip_polygons(bsp_node_t *node, klist_t(poly) *polygons, klis
|
|
427
483
|
check(result != NULL, "Failed to clip back tree");
|
428
484
|
}
|
429
485
|
|
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
|
+
|
430
494
|
if(poly_buffer != static_poly_buffer) free(poly_buffer);
|
431
|
-
// Clean up the result halves, now that they're copied into `result`
|
432
495
|
}
|
433
496
|
else {
|
434
497
|
// If we don't have a divider we just copy out the polygons
|
data/src/bsp.h
CHANGED
@@ -33,10 +33,12 @@ int bsp_subdivide(poly_t *divider, poly_t *poly,
|
|
33
33
|
poly_t **coplanar_front, int *n_cp_front,
|
34
34
|
poly_t **coplanar_back, int *n_cp_back,
|
35
35
|
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);
|
37
39
|
|
38
40
|
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);
|
40
42
|
klist_t(poly) *bsp_to_polygons(bsp_node_t *tree, int make_triangles, klist_t(poly) *dst);
|
41
43
|
|
42
44
|
bsp_node_t *bsp_invert(bsp_node_t *tree);
|
data/src/commands.c
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
#include <string.h>
|
2
|
+
#include "dbg.h"
|
3
|
+
|
4
|
+
#include "commands.h"
|
5
|
+
#include "stl.h"
|
6
|
+
#include "bsp.h"
|
7
|
+
#include "export.h"
|
8
|
+
|
9
|
+
typedef bsp_node_t* (*bsp_binary_op)(bsp_node_t *, bsp_node_t *);
|
10
|
+
|
11
|
+
// A generalization of a binary CSG operation being performed on an STL
|
12
|
+
// in `path1` and `path1` defined by an operation `op` from` bsp.h
|
13
|
+
// Result is freshly allocated, and needs to be freed with `free_bsp_tree()`
|
14
|
+
bsp_node_t* bsp_binary_operation(char *path1, char *path2, bsp_binary_op op) {
|
15
|
+
stl_object *file1 = NULL;
|
16
|
+
bsp_node_t *bsp1 = NULL;
|
17
|
+
|
18
|
+
stl_object *file2 = NULL;
|
19
|
+
bsp_node_t *bsp2 = NULL;
|
20
|
+
|
21
|
+
bsp_node_t *result = NULL;
|
22
|
+
|
23
|
+
// Read 1
|
24
|
+
file1 = stl_read_file(path1, 1);
|
25
|
+
check(file1 != NULL, "Failed to read .stl from '%s'", path1);
|
26
|
+
log_info("Loaded file: %s %d facets", path1, file1->facet_count);
|
27
|
+
bsp1 = stl_to_bsp(file1);
|
28
|
+
check_mem(bsp1);
|
29
|
+
|
30
|
+
// Read 2
|
31
|
+
file2 = stl_read_file(path2, 1);
|
32
|
+
check(file2 != NULL, "Failed to read .stl from '%s'", path2);
|
33
|
+
log_info("Loaded file: %s %d facets", path2, file2->facet_count);
|
34
|
+
bsp2 = stl_to_bsp(file2);
|
35
|
+
check_mem(bsp2);
|
36
|
+
|
37
|
+
// Operate
|
38
|
+
result = op(bsp1, bsp2);
|
39
|
+
|
40
|
+
if(file1 != NULL) stl_free(file1);
|
41
|
+
if(file2 != NULL) stl_free(file2);
|
42
|
+
if(bsp1 != NULL) free_bsp_tree(bsp1);
|
43
|
+
if(bsp2 != NULL) free_bsp_tree(bsp2);
|
44
|
+
return result;
|
45
|
+
error:
|
46
|
+
if(file1 != NULL) stl_free(file1);
|
47
|
+
if(file2 != NULL) stl_free(file2);
|
48
|
+
if(bsp1 != NULL) free_bsp_tree(bsp1);
|
49
|
+
if(bsp2 != NULL) free_bsp_tree(bsp2);
|
50
|
+
if(result != NULL) free_bsp_tree(result);
|
51
|
+
return NULL;
|
52
|
+
}
|
53
|
+
|
54
|
+
// Constructor for commands named after the CSG functions they perform.
|
55
|
+
// Produces a function named `cmd_<name>(int argc, char **argv) that reads
|
56
|
+
// two files and an optional output path and calls a matching function
|
57
|
+
// bsp_<name>(bsp_node_t*,bsp_node_t*) and writes the resulting mesh
|
58
|
+
// to disk as either `./out.stl` or the value of argv[2]
|
59
|
+
// Uses the above `bsp_binary_operation(..)` wrapper to do most of the
|
60
|
+
// heavy lifting.
|
61
|
+
#define MAKE_CSG_COMMAND(name) \
|
62
|
+
int cmd_##name(int argc, char **argv) { \
|
63
|
+
bsp_node_t *result = NULL; \
|
64
|
+
stl_object *out = NULL; \
|
65
|
+
char *out_path = "./out.stl"; \
|
66
|
+
\
|
67
|
+
check(argc >= 2, "At least two input files required."); \
|
68
|
+
if(argc > 2) out_path = argv[2]; \
|
69
|
+
\
|
70
|
+
result = bsp_binary_operation(argv[0], argv[1], bsp_##name); \
|
71
|
+
out = bsp_to_stl(result); \
|
72
|
+
log_info("Writing output to %s", out_path); \
|
73
|
+
check(stl_write_file(out, out_path) == 0, "Failed to write STL to %s", out_path); \
|
74
|
+
\
|
75
|
+
if(result != NULL) free_bsp_tree(result); \
|
76
|
+
if(out != NULL) stl_free(out); \
|
77
|
+
return 0; \
|
78
|
+
error: \
|
79
|
+
if(result != NULL) free_bsp_tree(result); \
|
80
|
+
if(out != NULL) stl_free(out); \
|
81
|
+
return -1; \
|
82
|
+
}
|
83
|
+
|
84
|
+
// Each MAKE_BSP_COMMAND(name) results in a function named
|
85
|
+
// cmd_<name>(int argc, argv) which calls bsp_<name>() with
|
86
|
+
// two trees built from files in argv[0] and argv[1]
|
87
|
+
MAKE_CSG_COMMAND(intersect);
|
88
|
+
MAKE_CSG_COMMAND(union);
|
89
|
+
MAKE_CSG_COMMAND(subtract);
|
90
|
+
|
91
|
+
// Available commands
|
92
|
+
const cmd_t commands[] = {
|
93
|
+
{"intersect", "Intersect two geometries", cmd_intersect},
|
94
|
+
{"subtract", "Subtract two geometries", cmd_subtract},
|
95
|
+
{"union", "Union two geometries", cmd_union},
|
96
|
+
{NULL, NULL, NULL}
|
97
|
+
};
|
98
|
+
|
99
|
+
// Search for a command by name.
|
100
|
+
cmd_fun_t cmd_find(const char *name) {
|
101
|
+
for(cmd_t *c = (cmd_t*)commands; c->name != NULL; c++) {
|
102
|
+
if(0 == strcmp(c->name, name)) return c->fun;
|
103
|
+
}
|
104
|
+
return NULL;
|
105
|
+
}
|
data/src/commands.h
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
|
3
|
+
#ifndef __COMMANDS_H
|
4
|
+
#define __COMMANDS_H
|
5
|
+
|
6
|
+
typedef int (*cmd_fun_t)(int argc, char **argv);
|
7
|
+
|
8
|
+
typedef struct s_cmd_t {
|
9
|
+
char *name;
|
10
|
+
char *description;
|
11
|
+
cmd_fun_t fun;
|
12
|
+
} cmd_t;
|
13
|
+
|
14
|
+
extern const cmd_t commands[];
|
15
|
+
cmd_fun_t cmd_find(const char *name);
|
16
|
+
|
17
|
+
#endif
|
data/src/poly.c
CHANGED
@@ -13,11 +13,17 @@ error:
|
|
13
13
|
|
14
14
|
void free_poly(poly_t *p, int free_self) {
|
15
15
|
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
|
+
}
|
16
20
|
if(free_self) free(p);
|
17
21
|
}
|
18
22
|
|
19
23
|
poly_t *poly_init(poly_t *poly) {
|
20
24
|
poly->vertex_count = 0;
|
25
|
+
poly->vertex_max = POLY_MAX_VERTS;
|
26
|
+
poly->vertices = poly->_vbuffer;
|
21
27
|
return poly;
|
22
28
|
}
|
23
29
|
|
@@ -25,8 +31,23 @@ poly_t *clone_poly(poly_t *poly) {
|
|
25
31
|
poly_t *copy = NULL;
|
26
32
|
check_mem(copy = alloc_poly());
|
27
33
|
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
|
+
|
28
48
|
return copy;
|
29
49
|
error:
|
50
|
+
if(copy != NULL) free_poly(copy, 1);
|
30
51
|
return NULL;
|
31
52
|
}
|
32
53
|
|
@@ -53,10 +74,47 @@ int poly_vertex_count(poly_t *poly) {
|
|
53
74
|
return poly->vertex_count;
|
54
75
|
}
|
55
76
|
|
56
|
-
|
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
|
57
114
|
int poly_push_vertex(poly_t *poly, float3 v) {
|
58
|
-
|
59
|
-
|
115
|
+
if(poly_vertex_available(poly) == 0) {
|
116
|
+
poly_vertex_expand(poly);
|
117
|
+
}
|
60
118
|
|
61
119
|
// Dat assignment copy
|
62
120
|
poly->vertices[poly->vertex_count][0] = v[0];
|
data/src/poly.h
CHANGED
@@ -12,14 +12,19 @@
|
|
12
12
|
#define BACK 2
|
13
13
|
#define SPANNING 3
|
14
14
|
|
15
|
+
#ifndef POLY_MAX_VERTS
|
15
16
|
#define POLY_MAX_VERTS 40
|
17
|
+
#endif
|
16
18
|
|
17
19
|
typedef struct s_poly {
|
18
|
-
float3 vertices
|
20
|
+
float3 *vertices;
|
19
21
|
int vertex_count;
|
22
|
+
int vertex_max;
|
20
23
|
|
21
24
|
float3 normal;
|
22
25
|
float w;
|
26
|
+
|
27
|
+
float3 _vbuffer[POLY_MAX_VERTS];
|
23
28
|
} poly_t;
|
24
29
|
|
25
30
|
poly_t *alloc_poly(void);
|
@@ -32,6 +37,10 @@ int poly_update(poly_t *poly);
|
|
32
37
|
poly_t *poly_invert(poly_t *poly);
|
33
38
|
|
34
39
|
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);
|
35
44
|
int poly_push_vertex(poly_t *poly, float3 v);
|
36
45
|
|
37
46
|
int poly_classify_vertex(poly_t *poly, float3 v);
|
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: csg
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.0.3
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Yaroslav Shirokov
|
@@ -10,22 +9,20 @@ authors:
|
|
10
9
|
autorequire:
|
11
10
|
bindir: bin
|
12
11
|
cert_chain: []
|
13
|
-
date: 2013-
|
12
|
+
date: 2013-09-23 00:00:00.000000000 Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: ffi
|
17
16
|
requirement: !ruby/object:Gem::Requirement
|
18
|
-
none: false
|
19
17
|
requirements:
|
20
|
-
- -
|
18
|
+
- - '>='
|
21
19
|
- !ruby/object:Gem::Version
|
22
20
|
version: '0'
|
23
21
|
type: :runtime
|
24
22
|
prerelease: false
|
25
23
|
version_requirements: !ruby/object:Gem::Requirement
|
26
|
-
none: false
|
27
24
|
requirements:
|
28
|
-
- -
|
25
|
+
- - '>='
|
29
26
|
- !ruby/object:Gem::Version
|
30
27
|
version: '0'
|
31
28
|
description: A fast library for Constructive Solid Geometry
|
@@ -40,12 +37,14 @@ files:
|
|
40
37
|
- Makefile
|
41
38
|
- lib/csg.rb
|
42
39
|
- src/bsp.c
|
40
|
+
- src/commands.c
|
43
41
|
- src/dbg.c
|
44
42
|
- src/export.c
|
45
43
|
- src/poly.c
|
46
44
|
- src/stl.c
|
47
45
|
- src/vector.c
|
48
46
|
- src/bsp.h
|
47
|
+
- src/commands.h
|
49
48
|
- src/dbg.h
|
50
49
|
- src/export.h
|
51
50
|
- src/klist.h
|
@@ -55,26 +54,25 @@ files:
|
|
55
54
|
- ext/Rakefile
|
56
55
|
homepage: https://github.com/sshirokov/csgtool/
|
57
56
|
licenses: []
|
57
|
+
metadata: {}
|
58
58
|
post_install_message:
|
59
59
|
rdoc_options: []
|
60
60
|
require_paths:
|
61
61
|
- lib
|
62
62
|
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
-
none: false
|
64
63
|
requirements:
|
65
|
-
- -
|
64
|
+
- - '>='
|
66
65
|
- !ruby/object:Gem::Version
|
67
66
|
version: '0'
|
68
67
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
-
none: false
|
70
68
|
requirements:
|
71
|
-
- -
|
69
|
+
- - '>='
|
72
70
|
- !ruby/object:Gem::Version
|
73
71
|
version: '0'
|
74
72
|
requirements: []
|
75
73
|
rubyforge_project:
|
76
|
-
rubygems_version:
|
74
|
+
rubygems_version: 2.0.3
|
77
75
|
signing_key:
|
78
|
-
specification_version:
|
76
|
+
specification_version: 4
|
79
77
|
summary: A fast library for Constructive Solid Geometry
|
80
78
|
test_files: []
|