csg 0.0.4 → 0.1.0
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 +4 -4
- data/lib/csg.rb +56 -29
- data/src/bsp.c +48 -0
- data/src/bsp_mesh.h +12 -0
- data/src/commands.c +24 -23
- data/src/export.c +46 -0
- data/src/export.h +4 -0
- data/src/mesh.c +113 -0
- data/src/mesh.h +34 -0
- data/src/reader.c +49 -0
- data/src/reader.h +22 -0
- data/src/stl.c +53 -0
- data/src/stl.h +9 -2
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cab611b90101912c713c832df26091680edf4d3d
|
4
|
+
data.tar.gz: 52de356c4a37b4032ae815bef964731eb8872c07
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 11b9ffd8267d6cfa66c30f02ac8dc62db7debdc1aac0ebe91401d317b682cde589ac075ae5b5fc2e635904d6b36bfe2a677b0876597035b8d4eae22cf641a556
|
7
|
+
data.tar.gz: 56e441bbe90cc44e96d551dcd1224149f276164389ab4ec277cfa32998d8416901cfd8c6c384a28deb5d6d3e100f9a821462663e6bb644b73b96462158e90365
|
data/lib/csg.rb
CHANGED
@@ -9,20 +9,26 @@ module CSG
|
|
9
9
|
end
|
10
10
|
ffi_lib ['csg'] + candidates
|
11
11
|
|
12
|
-
class
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
class Mesh < FFI::ManagedStruct
|
13
|
+
# WARNING: You should probably never call `:destroy`, because it's a managed
|
14
|
+
# struct, and should get destroyed by Ruby using this very method
|
15
|
+
# inside of `Mesh.release`
|
16
|
+
layout :type, [:uint8, 4],
|
17
|
+
:init, callback([:pointer, :pointer], :int),
|
18
|
+
:destroy, callback([:pointer], :void),
|
19
|
+
:poly_count, callback([:pointer], :int),
|
20
|
+
:to_polygons, callback([:pointer], :pointer),
|
21
|
+
:to_bsp, callback([:pointer], :pointer),
|
22
|
+
:write, callback([:pointer, :string, :string], :int)
|
16
23
|
|
17
24
|
def self.release(ptr)
|
18
|
-
CSG::Native.
|
19
|
-
end
|
20
|
-
|
21
|
-
def write_file(path)
|
22
|
-
CSG::Native.stl_write_file self, path
|
25
|
+
CSG::Native.destroy_mesh ptr
|
23
26
|
end
|
24
27
|
end
|
25
28
|
|
29
|
+
attach_function :destroy_mesh, [:pointer], :void
|
30
|
+
attach_function :mesh_read_file, [:string], Mesh
|
31
|
+
|
26
32
|
class BSPNode < FFI::ManagedStruct
|
27
33
|
layout :polygons, :pointer,
|
28
34
|
:divider, :pointer,
|
@@ -34,50 +40,71 @@ module CSG
|
|
34
40
|
end
|
35
41
|
end
|
36
42
|
|
37
|
-
attach_function :stl_read_file, [:string, :bool], :pointer
|
38
|
-
attach_function :stl_write_file, [:pointer, :string], :int
|
39
|
-
|
40
|
-
attach_function :stl_free, [:pointer], :void
|
41
43
|
attach_function :free_bsp_tree, [:pointer], :void
|
42
|
-
|
43
|
-
attach_function :stl_to_bsp, [:pointer], :pointer
|
44
|
-
attach_function :bsp_to_stl, [:pointer], :pointer
|
44
|
+
attach_function :mesh_to_bsp, [Mesh], BSPNode
|
45
45
|
|
46
46
|
attach_function :bsp_union, [:pointer, :pointer], :pointer
|
47
47
|
attach_function :bsp_subtract, [:pointer, :pointer], :pointer
|
48
48
|
attach_function :bsp_intersect, [:pointer, :pointer], :pointer
|
49
|
+
|
50
|
+
attach_function :bsp_to_mesh, [:pointer, :int], :pointer
|
49
51
|
end
|
52
|
+
end
|
50
53
|
|
54
|
+
module CSG
|
51
55
|
class Solid
|
52
|
-
attr_reader :
|
56
|
+
attr_reader :mesh
|
53
57
|
|
54
58
|
def initialize(opts)
|
55
59
|
if opts[:file]
|
56
60
|
load_from_file opts[:file]
|
57
|
-
elsif opts[:
|
58
|
-
@
|
61
|
+
elsif opts[:mesh]
|
62
|
+
@mesh = opts[:mesh]
|
59
63
|
end
|
60
|
-
raise ArgumentError.new "Failed to load
|
64
|
+
raise ArgumentError.new "Failed to load mesh with: #{opts.inspect}" unless @mesh
|
61
65
|
end
|
62
66
|
|
63
67
|
def load_from_file(path)
|
64
68
|
File.stat(path) # Stat before load to raise a sane "Does not exist" error
|
65
|
-
|
66
|
-
|
69
|
+
mesh_ptr = CSG::Native::mesh_read_file path
|
70
|
+
if not mesh_ptr.null?
|
71
|
+
@mesh = CSG::Native::Mesh.new mesh_ptr
|
72
|
+
else
|
73
|
+
raise Exception.new("Failed to produce Mesh from #{path}")
|
74
|
+
end
|
67
75
|
end
|
68
76
|
|
69
|
-
def
|
70
|
-
|
71
|
-
|
77
|
+
def write(path)
|
78
|
+
rc = mesh[:write].call(mesh, path, "STL")
|
79
|
+
raise Exception.new("Failed to write to '#{path}") if rc != 0
|
72
80
|
end
|
73
81
|
|
74
|
-
# Build the CSG methods with ManagedStruct wrappers
|
75
82
|
[:intersect, :subtract, :union].each do |name|
|
76
83
|
define_method name do |solid|
|
77
|
-
|
78
|
-
|
79
|
-
|
84
|
+
# I'm so paranoid because ruby will gladly FFI through a
|
85
|
+
# *NULL and explode if you ask, and that's much worse.
|
86
|
+
raise Exception.new("The calling mesh is a NULL pointer") if mesh.null?
|
87
|
+
raise Exception.new("The parameter mesh is a NULL pointer") if solid.mesh.null?
|
88
|
+
|
89
|
+
raise Exception.new("My BSP tree is NULL.") if (my_bsp_ptr = mesh[:to_bsp].call mesh).null?
|
90
|
+
# Assign ASAP in case the exception triggers an unwind, and I want the GC to know about this
|
91
|
+
my_bsp = CSG::Native::BSPNode.new(my_bsp_ptr)
|
92
|
+
|
93
|
+
raise Exception.new("My BSP tree is NULL.") if (their_bsp_ptr = solid.mesh[:to_bsp].call solid.mesh).null?
|
94
|
+
their_bsp = CSG::Native::BSPNode.new(their_bsp_ptr)
|
95
|
+
|
96
|
+
result_ptr = CSG::Native.send "bsp_#{name}", my_bsp, their_bsp
|
97
|
+
raise Exception.new("Result of #{name} is NULL") if result_ptr.null?
|
98
|
+
|
99
|
+
# We will not wrap the result in a CSG::Native::BSPNode because
|
100
|
+
# to avoid garbage collection, and we'll manage this pointer
|
101
|
+
# inside of the CSG::Native::Mesh object we get with
|
102
|
+
# bsp_to_mesh(.., 0) - which will not clone the input parameter
|
103
|
+
result_mesh_ptr = CSG::Native.bsp_to_mesh result_ptr, 0
|
104
|
+
raise Exception.new("Failed to wrap BSPNode(#{result_mesh_ptr} pointer as a Mesh, got NULL") if result_mesh_ptr.null?
|
105
|
+
CSG::Solid.new :mesh => CSG::Native::Mesh.new(result_mesh_ptr)
|
80
106
|
end
|
81
107
|
end
|
108
|
+
|
82
109
|
end
|
83
110
|
end
|
data/src/bsp.c
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
#include "bsp.h"
|
4
4
|
#include "dbg.h"
|
5
|
+
#include "export.h"
|
6
|
+
#include "bsp_mesh.h"
|
5
7
|
|
6
8
|
bsp_node_t *alloc_bsp_node(void) {
|
7
9
|
bsp_node_t *node = NULL;
|
@@ -627,3 +629,49 @@ error:
|
|
627
629
|
if(result != NULL) free_bsp_tree(result);
|
628
630
|
return NULL;
|
629
631
|
}
|
632
|
+
|
633
|
+
int bsp_count_polygons(bsp_node_t *tree) {
|
634
|
+
if(tree == NULL) return 0;
|
635
|
+
|
636
|
+
return (tree->polygons == NULL) ? 0 : tree->polygons->size +
|
637
|
+
bsp_count_polygons(tree->front) +
|
638
|
+
bsp_count_polygons(tree->back);
|
639
|
+
}
|
640
|
+
|
641
|
+
// bsp_node_t tree backed mesh methods and mesh prototype
|
642
|
+
int bsp_mesh_init(void *self, void *data) {
|
643
|
+
bsp_mesh_t *mesh = (bsp_mesh_t*)self;
|
644
|
+
if(data == NULL) {
|
645
|
+
check_mem(mesh->bsp = alloc_bsp_node());
|
646
|
+
}
|
647
|
+
else {
|
648
|
+
mesh->bsp = (bsp_node_t*)data;
|
649
|
+
}
|
650
|
+
return 0;
|
651
|
+
error:
|
652
|
+
return -1;
|
653
|
+
}
|
654
|
+
|
655
|
+
void bsp_mesh_destroy(void *self) {
|
656
|
+
bsp_mesh_t *mesh = (bsp_mesh_t*)self;
|
657
|
+
free_bsp_tree(mesh->bsp);
|
658
|
+
free(self);
|
659
|
+
}
|
660
|
+
|
661
|
+
int bsp_mesh_poly_count(void *self) {
|
662
|
+
bsp_mesh_t *mesh = (bsp_mesh_t*)self;
|
663
|
+
return bsp_count_polygons(mesh->bsp);
|
664
|
+
}
|
665
|
+
|
666
|
+
klist_t(poly)* bsp_mesh_to_polygons(void *self) {
|
667
|
+
bsp_mesh_t *mesh = (bsp_mesh_t*)self;
|
668
|
+
return bsp_to_polygons(mesh->bsp, 0, NULL);
|
669
|
+
}
|
670
|
+
|
671
|
+
// bsp_mesh_t prototype definition
|
672
|
+
mesh_t bsp_mesh_t_Proto = {
|
673
|
+
.init = bsp_mesh_init,
|
674
|
+
.destroy = bsp_mesh_destroy,
|
675
|
+
.poly_count = bsp_mesh_poly_count,
|
676
|
+
.to_polygons = bsp_mesh_to_polygons,
|
677
|
+
};
|
data/src/bsp_mesh.h
ADDED
data/src/commands.c
CHANGED
@@ -2,8 +2,9 @@
|
|
2
2
|
#include "dbg.h"
|
3
3
|
|
4
4
|
#include "commands.h"
|
5
|
-
#include "
|
5
|
+
#include "mesh.h"
|
6
6
|
#include "bsp.h"
|
7
|
+
#include "bsp_mesh.h"
|
7
8
|
#include "export.h"
|
8
9
|
|
9
10
|
typedef bsp_node_t* (*bsp_binary_op)(bsp_node_t *, bsp_node_t *);
|
@@ -12,39 +13,39 @@ typedef bsp_node_t* (*bsp_binary_op)(bsp_node_t *, bsp_node_t *);
|
|
12
13
|
// in `path1` and `path1` defined by an operation `op` from` bsp.h
|
13
14
|
// Result is freshly allocated, and needs to be freed with `free_bsp_tree()`
|
14
15
|
bsp_node_t* bsp_binary_operation(char *path1, char *path2, bsp_binary_op op) {
|
15
|
-
|
16
|
+
mesh_t *file1 = NULL;
|
16
17
|
bsp_node_t *bsp1 = NULL;
|
17
18
|
|
18
|
-
|
19
|
+
mesh_t *file2 = NULL;
|
19
20
|
bsp_node_t *bsp2 = NULL;
|
20
21
|
|
21
22
|
bsp_node_t *result = NULL;
|
22
23
|
|
23
24
|
// Read 1
|
24
|
-
file1 =
|
25
|
-
check(file1 != NULL, "Failed to read
|
26
|
-
log_info("Loaded file: %s %d facets", path1, file1->
|
27
|
-
bsp1 =
|
25
|
+
file1 = mesh_read_file(path1);
|
26
|
+
check(file1 != NULL, "Failed to read mesh from '%s'", path1);
|
27
|
+
log_info("Loaded file: %s %d facets", path1, file1->poly_count(file1));
|
28
|
+
bsp1 = mesh_to_bsp(file1);
|
28
29
|
check_mem(bsp1);
|
29
30
|
|
30
31
|
// Read 2
|
31
|
-
file2 =
|
32
|
-
check(file2 != NULL, "Failed to read
|
33
|
-
log_info("Loaded file: %s %d facets", path2, file2->
|
34
|
-
bsp2 =
|
32
|
+
file2 = mesh_read_file(path2);
|
33
|
+
check(file2 != NULL, "Failed to read mesh from '%s'", path2);
|
34
|
+
log_info("Loaded file: %s %d facets", path2, file2->poly_count(file2));
|
35
|
+
bsp2 = mesh_to_bsp(file2);
|
35
36
|
check_mem(bsp2);
|
36
37
|
|
37
38
|
// Operate
|
38
39
|
result = op(bsp1, bsp2);
|
39
40
|
|
40
|
-
if(file1 != NULL)
|
41
|
-
if(file2 != NULL)
|
41
|
+
if(file1 != NULL) file1->destroy(file1);
|
42
|
+
if(file2 != NULL) file2->destroy(file2);
|
42
43
|
if(bsp1 != NULL) free_bsp_tree(bsp1);
|
43
44
|
if(bsp2 != NULL) free_bsp_tree(bsp2);
|
44
45
|
return result;
|
45
46
|
error:
|
46
|
-
if(file1 != NULL)
|
47
|
-
if(file2 != NULL)
|
47
|
+
if(file1 != NULL) file1->destroy(file1);
|
48
|
+
if(file2 != NULL) file2->destroy(file2);
|
48
49
|
if(bsp1 != NULL) free_bsp_tree(bsp1);
|
49
50
|
if(bsp2 != NULL) free_bsp_tree(bsp2);
|
50
51
|
if(result != NULL) free_bsp_tree(result);
|
@@ -61,23 +62,23 @@ error:
|
|
61
62
|
#define MAKE_CSG_COMMAND(name) \
|
62
63
|
int cmd_##name(int argc, char **argv) { \
|
63
64
|
bsp_node_t *result = NULL; \
|
64
|
-
|
65
|
+
mesh_t *out = NULL; \
|
65
66
|
char *out_path = "./out.stl"; \
|
66
67
|
\
|
67
68
|
check(argc >= 2, "At least two input files required."); \
|
68
69
|
if(argc > 2) out_path = argv[2]; \
|
69
70
|
\
|
70
|
-
result = bsp_binary_operation(argv[0], argv[1], bsp_##name);
|
71
|
-
|
71
|
+
result = bsp_binary_operation(argv[0], argv[1], bsp_##name); \
|
72
|
+
check(result != NULL, "Binary operation" #name "failed."); \
|
73
|
+
out = NEW(bsp_mesh_t, "BSP", result); \
|
72
74
|
log_info("Writing output to %s", out_path); \
|
73
|
-
check(
|
75
|
+
check(out->write(out, out_path, "STL") == 0, "Failed to write STL to %s", out_path); \
|
74
76
|
\
|
75
|
-
|
76
|
-
if(out != NULL) stl_free(out); \
|
77
|
+
out->destroy(out); \
|
77
78
|
return 0; \
|
78
79
|
error: \
|
79
|
-
if(
|
80
|
-
if(
|
80
|
+
if(out != NULL) out->destroy(out); \
|
81
|
+
else if(result != NULL) free_bsp_tree(result); \
|
81
82
|
return -1; \
|
82
83
|
}
|
83
84
|
|
data/src/export.c
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#include "export.h"
|
2
|
+
#include "bsp_mesh.h"
|
2
3
|
|
3
4
|
stl_object *stl_from_polys(klist_t(poly) *polygons) {
|
4
5
|
stl_object *stl = stl_alloc(NULL, polygons->size);
|
@@ -65,3 +66,48 @@ error:
|
|
65
66
|
}
|
66
67
|
return NULL;
|
67
68
|
}
|
69
|
+
|
70
|
+
bsp_node_t *mesh_to_bsp(mesh_t *mesh) {
|
71
|
+
return mesh->to_bsp(mesh);
|
72
|
+
}
|
73
|
+
|
74
|
+
mesh_t* bsp_to_mesh(bsp_node_t* bsp, int copy) {
|
75
|
+
bsp_node_t* input = (copy == 0) ? bsp : clone_bsp_tree(bsp);
|
76
|
+
|
77
|
+
return NEW(bsp_mesh_t, "BSP", input);
|
78
|
+
}
|
79
|
+
|
80
|
+
klist_t(poly)* polys_to_tris(klist_t(poly) *dst, klist_t(poly) *src) {
|
81
|
+
klist_t(poly) *result = dst;
|
82
|
+
if(result == NULL) result = kl_init(poly);
|
83
|
+
|
84
|
+
kliter_t(poly) *iter = NULL;
|
85
|
+
for(iter = kl_begin(src); iter != kl_end(src); iter = kl_next(iter)) {
|
86
|
+
poly_t *poly = kl_val(iter);
|
87
|
+
int vertex_count = poly_vertex_count(poly);
|
88
|
+
|
89
|
+
// Copy triangles, split higher-vertex polygons into triangle fans.
|
90
|
+
if(vertex_count == 3) {
|
91
|
+
poly_t *copy = clone_poly(poly);
|
92
|
+
check_mem(copy);
|
93
|
+
*kl_pushp(poly, result) = copy;
|
94
|
+
}
|
95
|
+
else if(vertex_count > 3) {
|
96
|
+
float3 *v_cur, *v_prev;
|
97
|
+
for(int i = 2; i < vertex_count; i++) {
|
98
|
+
v_cur = &poly->vertices[i];
|
99
|
+
v_prev = &poly->vertices[i - 1];
|
100
|
+
poly_t *tri = poly_make_triangle(poly->vertices[0], *v_prev, *v_cur);
|
101
|
+
check_mem(tri);
|
102
|
+
*kl_pushp(poly, result) = tri;
|
103
|
+
}
|
104
|
+
} else {
|
105
|
+
sentinel("polygon(%p) has less than three(%d) vertices.", poly, poly_vertex_count(poly));
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
return result;
|
110
|
+
error:
|
111
|
+
if(result != dst) if(result != NULL) kl_destroy(poly, result);
|
112
|
+
return NULL;
|
113
|
+
}
|
data/src/export.h
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
#include "stl.h"
|
6
6
|
#include "poly.h"
|
7
7
|
#include "bsp.h"
|
8
|
+
#include "mesh.h"
|
8
9
|
|
9
10
|
#ifndef __EXPORT_H
|
10
11
|
#define __EXPORT_H
|
@@ -12,5 +13,8 @@
|
|
12
13
|
stl_object *stl_from_polys(klist_t(poly) *polygons);
|
13
14
|
stl_object *bsp_to_stl(bsp_node_t *tree);
|
14
15
|
bsp_node_t *stl_to_bsp(stl_object *stl);
|
16
|
+
bsp_node_t *mesh_to_bsp(mesh_t *mesh);
|
17
|
+
mesh_t* bsp_to_mesh(bsp_node_t *tree, int copy);
|
18
|
+
klist_t(poly)* polys_to_tris(klist_t(poly)* dst, klist_t(poly)* src);
|
15
19
|
|
16
20
|
#endif
|
data/src/mesh.c
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
#include "dbg.h"
|
2
|
+
|
3
|
+
#include "stl.h"
|
4
|
+
#include "export.h"
|
5
|
+
#include "mesh.h"
|
6
|
+
#include "reader.h"
|
7
|
+
#include "bsp.h"
|
8
|
+
|
9
|
+
int mesh_init(void *self, void *unused) {
|
10
|
+
if(self == NULL) return -1;
|
11
|
+
return 0;
|
12
|
+
}
|
13
|
+
|
14
|
+
char* mesh_describe(void *self) {
|
15
|
+
mesh_t *mesh = (mesh_t*)self;
|
16
|
+
return mesh->type;
|
17
|
+
}
|
18
|
+
|
19
|
+
void free_mesh(void *self) {
|
20
|
+
if(self != NULL) free(self);
|
21
|
+
return;
|
22
|
+
}
|
23
|
+
|
24
|
+
void destroy_mesh(void *self) {
|
25
|
+
mesh_t *mesh = (mesh_t*)self;
|
26
|
+
if(mesh->destroy != NULL) {
|
27
|
+
mesh->destroy(mesh);
|
28
|
+
}
|
29
|
+
else {
|
30
|
+
free_mesh(mesh);
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
int _default_poly_count(void *self) {
|
35
|
+
return 0;
|
36
|
+
}
|
37
|
+
|
38
|
+
klist_t(poly)* _default_to_polygons(void *self) {
|
39
|
+
return NULL;
|
40
|
+
}
|
41
|
+
|
42
|
+
int _default_write(void *self, char *path, char type[4]) {
|
43
|
+
int rc = -1;
|
44
|
+
mesh_t *mesh = (mesh_t*)self;
|
45
|
+
stl_object *stl = NULL;
|
46
|
+
klist_t(poly) *polys = NULL;
|
47
|
+
klist_t(poly) *triangles = NULL;
|
48
|
+
|
49
|
+
// This is the only format we speak right now
|
50
|
+
if(strncmp(type, "STL", 3) != 0) goto error;
|
51
|
+
|
52
|
+
check((polys = mesh->to_polygons(mesh)) != NULL, "Failed to get polygons from mesh %p", mesh);
|
53
|
+
|
54
|
+
triangles = polys_to_tris(NULL, polys);
|
55
|
+
check(triangles != NULL, "Failed to convert polygons to trianges.");
|
56
|
+
|
57
|
+
// The default output format is STL
|
58
|
+
stl = stl_from_polys(triangles);
|
59
|
+
check(stl != NULL, "Failed to generate STL object for write.");
|
60
|
+
rc = stl_write_file(stl, path);
|
61
|
+
|
62
|
+
if(stl != NULL) stl_free(stl);
|
63
|
+
if(polys != NULL) kl_destroy(poly, polys);
|
64
|
+
if(triangles != NULL) kl_destroy(poly, triangles);
|
65
|
+
return rc;
|
66
|
+
error:
|
67
|
+
if(stl != NULL) stl_free(stl);
|
68
|
+
if(polys != NULL) kl_destroy(poly, polys);
|
69
|
+
if(triangles != NULL) kl_destroy(poly, triangles);
|
70
|
+
return -1;
|
71
|
+
}
|
72
|
+
|
73
|
+
bsp_node_t* _default_to_bsp(void *self) {
|
74
|
+
mesh_t *mesh = (mesh_t*)self;
|
75
|
+
bsp_node_t *bsp = NULL;
|
76
|
+
klist_t(poly)* polys = NULL;
|
77
|
+
|
78
|
+
check((polys = mesh->to_polygons(mesh)) != NULL,
|
79
|
+
"Failed to convert mesh %p to poly list", mesh);
|
80
|
+
|
81
|
+
check((bsp = bsp_build(NULL, polys, 1)) != NULL,
|
82
|
+
"Failed to build BSP tree from %zd polygons of %p", polys->size, self);
|
83
|
+
|
84
|
+
kl_destroy(poly, polys);
|
85
|
+
return bsp;
|
86
|
+
error:
|
87
|
+
if(polys != NULL) kl_destroy(poly, polys);
|
88
|
+
if(bsp != NULL) free_bsp_tree(bsp);
|
89
|
+
return NULL;
|
90
|
+
}
|
91
|
+
|
92
|
+
void *alloc_mesh(size_t size, mesh_t proto, char type[4], void *data) {
|
93
|
+
if(proto.init == NULL) proto.init = mesh_init;
|
94
|
+
if(proto.destroy == NULL) proto.destroy = free_mesh;
|
95
|
+
if(proto.poly_count == NULL) proto.poly_count = _default_poly_count;
|
96
|
+
if(proto.to_polygons == NULL) proto.to_polygons = _default_to_polygons;
|
97
|
+
if(proto.write == NULL) proto.write = _default_write;
|
98
|
+
if(proto.to_bsp == NULL) proto.to_bsp = _default_to_bsp;
|
99
|
+
|
100
|
+
mesh_t *m = calloc(1, size);
|
101
|
+
*m = proto;
|
102
|
+
strncpy(m->type, type, 3);
|
103
|
+
|
104
|
+
check(m->init(m, data) != -1, "Failed to initialize %p(%s, %p)", m, m->type, data);
|
105
|
+
return m;
|
106
|
+
error:
|
107
|
+
if(m != NULL) m->destroy(m);
|
108
|
+
return NULL;
|
109
|
+
}
|
110
|
+
|
111
|
+
mesh_t *mesh_read_file(char *path) {
|
112
|
+
return reader_load(path);
|
113
|
+
}
|
data/src/mesh.h
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#include <stdlib.h>
|
2
|
+
|
3
|
+
#include "poly.h"
|
4
|
+
#include "bsp.h"
|
5
|
+
|
6
|
+
#ifndef __MESH_H
|
7
|
+
#define __MESH_H
|
8
|
+
|
9
|
+
typedef struct s_mesh_t {
|
10
|
+
char type[4];
|
11
|
+
|
12
|
+
int (*init)(void *self, void *data);
|
13
|
+
void (*destroy)(void *self);
|
14
|
+
|
15
|
+
int (*poly_count)(void *self);
|
16
|
+
klist_t(poly)* (*to_polygons)(void *self);
|
17
|
+
bsp_node_t* (*to_bsp)(void *self);
|
18
|
+
|
19
|
+
int (*write)(void *self, char *path, char type[4]);
|
20
|
+
} mesh_t;
|
21
|
+
|
22
|
+
int mesh_init(void *self, void *data);
|
23
|
+
void free_mesh(void *self);
|
24
|
+
void destroy_mesh(void *self);
|
25
|
+
|
26
|
+
void *alloc_mesh(size_t size, mesh_t proto, char type[4], void *data);
|
27
|
+
|
28
|
+
#define NEW(T, N, D) alloc_mesh(sizeof(T), T##_Proto, N, D)
|
29
|
+
#define _(M) proto.M
|
30
|
+
|
31
|
+
// Load wrapper to read better
|
32
|
+
mesh_t *mesh_read_file(char *path);
|
33
|
+
|
34
|
+
#endif
|
data/src/reader.c
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
#include "stl.h"
|
2
|
+
#include "reader.h"
|
3
|
+
|
4
|
+
// API
|
5
|
+
mesh_t* reader_load(char *path) {
|
6
|
+
mesh_t *mesh = NULL;
|
7
|
+
|
8
|
+
// Walk the readers list and return the first thing that passes
|
9
|
+
// the test and loads a mesh_t != NULL
|
10
|
+
const reader_t *r = NULL;
|
11
|
+
for(r = readers; r->name != NULL; r++) {
|
12
|
+
if(r->test(path) == 1) {
|
13
|
+
if((mesh = r->load(path))) {
|
14
|
+
break;
|
15
|
+
}
|
16
|
+
}
|
17
|
+
}
|
18
|
+
|
19
|
+
return mesh;
|
20
|
+
}
|
21
|
+
|
22
|
+
// Wrappers
|
23
|
+
int _stl_predicate(char *path) {
|
24
|
+
// TODO: Valdiate the STL file instead of blindly trying a read.
|
25
|
+
// Ideally, try to read a line, and pass if binary, if it's text
|
26
|
+
// pass only if it begins with /^solid/i
|
27
|
+
return 1;
|
28
|
+
}
|
29
|
+
|
30
|
+
mesh_t* _stl_reader(char *path) {
|
31
|
+
stl_object *stl = NULL;
|
32
|
+
mesh_t *mesh = NULL;
|
33
|
+
|
34
|
+
check((stl = stl_read_file(path, 1)) != NULL,
|
35
|
+
"Failed to read '%s' as STL", path);
|
36
|
+
check((mesh = NEW(stl_mesh_t, "STL", stl)) != NULL,
|
37
|
+
"Failed to create mesh from STL(%p)", stl);
|
38
|
+
|
39
|
+
return mesh;
|
40
|
+
error:
|
41
|
+
return NULL;
|
42
|
+
}
|
43
|
+
|
44
|
+
// List of readers that should be tried in order
|
45
|
+
// {NULL, NULL, NULL} terminated.
|
46
|
+
const reader_t readers[] = {
|
47
|
+
{"STL", _stl_predicate, _stl_reader},
|
48
|
+
{NULL, NULL, NULL}
|
49
|
+
};
|
data/src/reader.h
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#include "mesh.h"
|
2
|
+
|
3
|
+
#ifndef __READER_H
|
4
|
+
#define __READER_H
|
5
|
+
|
6
|
+
// API
|
7
|
+
mesh_t* reader_load(char *path);
|
8
|
+
|
9
|
+
// Types
|
10
|
+
typedef int (reader_predicate_t)(char *path);
|
11
|
+
typedef mesh_t* (reader_loader_t)(char *path);
|
12
|
+
|
13
|
+
typedef struct s_reader_t {
|
14
|
+
char *name;
|
15
|
+
reader_predicate_t *test;
|
16
|
+
reader_loader_t *load;
|
17
|
+
} reader_t;
|
18
|
+
|
19
|
+
// Exported list of readers
|
20
|
+
extern const reader_t readers[];
|
21
|
+
|
22
|
+
#endif
|
data/src/stl.c
CHANGED
@@ -330,3 +330,56 @@ error:
|
|
330
330
|
if(fd != -1) close(fd);
|
331
331
|
return NULL;
|
332
332
|
}
|
333
|
+
|
334
|
+
// Mesh type prototype methods
|
335
|
+
int stl_mesh_init(void *self, void *data) {
|
336
|
+
stl_mesh_t *mesh = (stl_mesh_t*)self;
|
337
|
+
if(data == NULL) {
|
338
|
+
check_mem(mesh->stl = stl_alloc(NULL, 0));
|
339
|
+
}
|
340
|
+
else {
|
341
|
+
mesh->stl = (stl_object*)data;
|
342
|
+
}
|
343
|
+
return 0;
|
344
|
+
error:
|
345
|
+
return -1;
|
346
|
+
}
|
347
|
+
|
348
|
+
void stl_mesh_destroy(void *self) {
|
349
|
+
stl_mesh_t *mesh = (stl_mesh_t*)self;
|
350
|
+
stl_free(mesh->stl);
|
351
|
+
free(self);
|
352
|
+
}
|
353
|
+
|
354
|
+
int stl_mesh_poly_count(void *self) {
|
355
|
+
stl_mesh_t *mesh = (stl_mesh_t*)self;
|
356
|
+
return mesh->stl->facet_count;
|
357
|
+
}
|
358
|
+
|
359
|
+
klist_t(poly)* stl_mesh_to_polygons(void *self) {
|
360
|
+
stl_mesh_t *mesh = (stl_mesh_t*)self;
|
361
|
+
int count = mesh->_(poly_count)(mesh);
|
362
|
+
klist_t(poly)* polys = count > 0 ? kl_init(poly) : NULL;
|
363
|
+
|
364
|
+
for(int i = 0; i < count; i++) {
|
365
|
+
poly_t *poly = poly_make_triangle(mesh->stl->facets[i].vertices[0],
|
366
|
+
mesh->stl->facets[i].vertices[1],
|
367
|
+
mesh->stl->facets[i].vertices[2]);
|
368
|
+
check_mem(poly);
|
369
|
+
*kl_pushp(poly, polys) = poly;
|
370
|
+
}
|
371
|
+
|
372
|
+
|
373
|
+
return polys;
|
374
|
+
error:
|
375
|
+
if(polys != NULL) kl_destroy(poly, polys);
|
376
|
+
return NULL;
|
377
|
+
}
|
378
|
+
|
379
|
+
// Mesh type definitions
|
380
|
+
mesh_t stl_mesh_t_Proto = {
|
381
|
+
.init = stl_mesh_init,
|
382
|
+
.destroy = stl_mesh_destroy,
|
383
|
+
.poly_count = stl_mesh_poly_count,
|
384
|
+
.to_polygons = stl_mesh_to_polygons
|
385
|
+
};
|
data/src/stl.h
CHANGED
@@ -4,12 +4,11 @@
|
|
4
4
|
|
5
5
|
#include "klist.h"
|
6
6
|
#include "vector.h"
|
7
|
+
#include "mesh.h"
|
7
8
|
|
8
9
|
#ifndef __STL_H
|
9
10
|
#define __STL_H
|
10
11
|
|
11
|
-
|
12
|
-
|
13
12
|
// File format structs
|
14
13
|
typedef struct s_stl_facet {
|
15
14
|
float3 normal;
|
@@ -57,4 +56,12 @@ KLIST_INIT(stl_object, stl_object*, mp_stl_free)
|
|
57
56
|
#define mp_std_free(x) free(kl_val(x))
|
58
57
|
KLIST_INIT(stl_facet, stl_facet*, mp_std_free)
|
59
58
|
|
59
|
+
// mesh_t type and prototype
|
60
|
+
extern mesh_t stl_mesh_t_Proto;
|
61
|
+
|
62
|
+
typedef struct s_stl_mesh_t {
|
63
|
+
mesh_t proto;
|
64
|
+
stl_object *stl;
|
65
|
+
} stl_mesh_t;
|
66
|
+
|
60
67
|
#endif
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: csg
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yaroslav Shirokov
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-12-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ffi
|
@@ -40,20 +40,26 @@ files:
|
|
40
40
|
- src/commands.c
|
41
41
|
- src/dbg.c
|
42
42
|
- src/export.c
|
43
|
+
- src/mesh.c
|
43
44
|
- src/poly.c
|
45
|
+
- src/reader.c
|
44
46
|
- src/stl.c
|
45
47
|
- src/vector.c
|
46
48
|
- src/bsp.h
|
49
|
+
- src/bsp_mesh.h
|
47
50
|
- src/commands.h
|
48
51
|
- src/dbg.h
|
49
52
|
- src/export.h
|
50
53
|
- src/klist.h
|
54
|
+
- src/mesh.h
|
51
55
|
- src/poly.h
|
56
|
+
- src/reader.h
|
52
57
|
- src/stl.h
|
53
58
|
- src/vector.h
|
54
59
|
- ext/Rakefile
|
55
60
|
homepage: https://github.com/sshirokov/csgtool/
|
56
|
-
licenses:
|
61
|
+
licenses:
|
62
|
+
- MIT
|
57
63
|
metadata: {}
|
58
64
|
post_install_message:
|
59
65
|
rdoc_options: []
|