csg 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fd64c54271e04c5a8558bf143fea9a294fe50232
4
- data.tar.gz: 034f2b630435697ee0dfa0dd3dec15e9bf72dd13
3
+ metadata.gz: cab611b90101912c713c832df26091680edf4d3d
4
+ data.tar.gz: 52de356c4a37b4032ae815bef964731eb8872c07
5
5
  SHA512:
6
- metadata.gz: 933e067a95518c104a03b56828d095b564837ad6b76b0454160c6327865ff6730fd870d02bfabf0c9da58d9a22456646a5dd26ba3e604cd7a86990ecd7c14fc5
7
- data.tar.gz: 26b431c5484349f9d89f21fbedcc8ca43be066366e33d4608ac9875c9775e618011b828a05bd8faa5553f9d51faf368d0e6a6b0f62b511a9570319947cf125a0
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 STLObject < FFI::ManagedStruct
13
- layout :header, [:uint8, 80],
14
- :facet_count, :uint32,
15
- :stl_facet, :pointer
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.stl_free ptr
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 :tree
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[:tree]
58
- @tree = opts[:tree]
61
+ elsif opts[:mesh]
62
+ @mesh = opts[:mesh]
59
63
  end
60
- raise ArgumentError.new "Failed to load tree with: #{opts.inspect}" unless @tree
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
- stl = CSG::Native::STLObject.new CSG::Native.stl_read_file(path, false)
66
- @tree = CSG::Native::BSPNode.new CSG::Native.stl_to_bsp(stl)
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 to_stl
70
- ptr = CSG::Native.bsp_to_stl tree
71
- CSG::Native::STLObject.new(ptr)
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
- ptr = CSG::Native.send "bsp_#{name}", tree, solid.tree
78
- tree = CSG::Native::BSPNode.new(ptr)
79
- CSG::Solid.new :tree => tree
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
@@ -0,0 +1,12 @@
1
+
2
+ #ifndef __BSP_MESH_H
3
+ #define __BSP_MESH_H
4
+
5
+ extern mesh_t bsp_mesh_t_Proto;
6
+
7
+ typedef struct s_bsp_mesh_t {
8
+ mesh_t proto;
9
+ bsp_node_t *bsp;
10
+ } bsp_mesh_t;
11
+
12
+ #endif
data/src/commands.c CHANGED
@@ -2,8 +2,9 @@
2
2
  #include "dbg.h"
3
3
 
4
4
  #include "commands.h"
5
- #include "stl.h"
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
- stl_object *file1 = NULL;
16
+ mesh_t *file1 = NULL;
16
17
  bsp_node_t *bsp1 = NULL;
17
18
 
18
- stl_object *file2 = NULL;
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 = 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);
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 = 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);
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) stl_free(file1);
41
- if(file2 != NULL) stl_free(file2);
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) stl_free(file1);
47
- if(file2 != NULL) stl_free(file2);
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
- stl_object *out = NULL; \
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
- out = bsp_to_stl(result); \
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(stl_write_file(out, out_path) == 0, "Failed to write STL to %s", out_path); \
75
+ check(out->write(out, out_path, "STL") == 0, "Failed to write STL to %s", out_path); \
74
76
  \
75
- if(result != NULL) free_bsp_tree(result); \
76
- if(out != NULL) stl_free(out); \
77
+ out->destroy(out); \
77
78
  return 0; \
78
79
  error: \
79
- if(result != NULL) free_bsp_tree(result); \
80
- if(out != NULL) stl_free(out); \
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
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-09-24 00:00:00.000000000 Z
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: []