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 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: []