csg 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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: []
|