csg 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Makefile +41 -0
- data/ext/Rakefile +6 -0
- data/lib/csg.rb +83 -0
- data/src/bsp.c +555 -0
- data/src/bsp.h +40 -0
- data/src/dbg.c +48 -0
- data/src/dbg.h +76 -0
- data/src/export.c +68 -0
- data/src/export.h +16 -0
- data/src/klist.h +121 -0
- data/src/poly.c +206 -0
- data/src/poly.h +45 -0
- data/src/stl.c +333 -0
- data/src/stl.h +60 -0
- data/src/vector.c +55 -0
- data/src/vector.h +35 -0
- metadata +80 -0
data/src/bsp.h
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
#include "klist.h"
|
2
|
+
#include "poly.h"
|
3
|
+
|
4
|
+
#ifndef __BSP_H
|
5
|
+
#define __BSP_H
|
6
|
+
|
7
|
+
typedef struct s_bsp_node {
|
8
|
+
klist_t(poly) *polygons;
|
9
|
+
poly_t *divider;
|
10
|
+
|
11
|
+
struct s_bsp_node *front;
|
12
|
+
struct s_bsp_node *back;
|
13
|
+
} bsp_node_t;
|
14
|
+
|
15
|
+
bsp_node_t *alloc_bsp_node(void);
|
16
|
+
bsp_node_t *clone_bsp_tree(bsp_node_t *tree);
|
17
|
+
|
18
|
+
void free_bsp_node(bsp_node_t *node);
|
19
|
+
void free_bsp_tree(bsp_node_t *tree);
|
20
|
+
|
21
|
+
int bsp_subdivide(poly_t *divider, poly_t *poly,
|
22
|
+
poly_t **coplanar_front, int *n_cp_front,
|
23
|
+
poly_t **coplanar_back, int *n_cp_back,
|
24
|
+
poly_t **front, int *n_front,
|
25
|
+
poly_t **back, int *n_back);
|
26
|
+
|
27
|
+
bsp_node_t *bsp_build(bsp_node_t *node, klist_t(poly) *polygons, int copy);
|
28
|
+
bsp_node_t *bsp_build_array(bsp_node_t *node, poly_t **polygons, size_t n_polys);
|
29
|
+
klist_t(poly) *bsp_to_polygons(bsp_node_t *tree, int make_triangles, klist_t(poly) *dst);
|
30
|
+
|
31
|
+
bsp_node_t *bsp_invert(bsp_node_t *tree);
|
32
|
+
bsp_node_t *bsp_clip(bsp_node_t *us, bsp_node_t *them);
|
33
|
+
klist_t(poly) *bsp_clip_polygons(bsp_node_t *node, klist_t(poly) *polygons, klist_t(poly) *dst);
|
34
|
+
|
35
|
+
// CSG Operations
|
36
|
+
bsp_node_t *bsp_union(bsp_node_t *a, bsp_node_t *b);
|
37
|
+
bsp_node_t *bsp_subtract(bsp_node_t *a, bsp_node_t *b);
|
38
|
+
bsp_node_t *bsp_intersect(bsp_node_t *a, bsp_node_t *b);
|
39
|
+
|
40
|
+
#endif
|
data/src/dbg.c
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
/**
|
2
|
+
*
|
3
|
+
* Copyright (c) 2010, Zed A. Shaw and Mongrel2 Project Contributors.
|
4
|
+
* All rights reserved.
|
5
|
+
*
|
6
|
+
* Redistribution and use in source and binary forms, with or without
|
7
|
+
* modification, are permitted provided that the following conditions are
|
8
|
+
* met:
|
9
|
+
*
|
10
|
+
* * Redistributions of source code must retain the above copyright
|
11
|
+
* notice, this list of conditions and the following disclaimer.
|
12
|
+
*
|
13
|
+
* * Redistributions in binary form must reproduce the above copyright
|
14
|
+
* notice, this list of conditions and the following disclaimer in the
|
15
|
+
* documentation and/or other materials provided with the distribution.
|
16
|
+
*
|
17
|
+
* * Neither the name of the Mongrel2 Project, Zed A. Shaw, nor the names
|
18
|
+
* of its contributors may be used to endorse or promote products
|
19
|
+
* derived from this software without specific prior written
|
20
|
+
* permission.
|
21
|
+
*
|
22
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
23
|
+
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
24
|
+
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
25
|
+
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
26
|
+
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
27
|
+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
28
|
+
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
29
|
+
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
30
|
+
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
31
|
+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
32
|
+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
33
|
+
*/
|
34
|
+
|
35
|
+
#include "dbg.h"
|
36
|
+
|
37
|
+
FILE *LOG_FILE = NULL;
|
38
|
+
|
39
|
+
void dbg_set_log(FILE *log_file)
|
40
|
+
{
|
41
|
+
LOG_FILE = log_file;
|
42
|
+
}
|
43
|
+
|
44
|
+
|
45
|
+
FILE *dbg_get_log()
|
46
|
+
{
|
47
|
+
return LOG_FILE != NULL ? LOG_FILE : stderr;
|
48
|
+
}
|
data/src/dbg.h
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
/**
|
2
|
+
*
|
3
|
+
* Copyright (c) 2010, Zed A. Shaw and Mongrel2 Project Contributors.
|
4
|
+
* All rights reserved.
|
5
|
+
*
|
6
|
+
* Redistribution and use in source and binary forms, with or without
|
7
|
+
* modification, are permitted provided that the following conditions are
|
8
|
+
* met:
|
9
|
+
*
|
10
|
+
* * Redistributions of source code must retain the above copyright
|
11
|
+
* notice, this list of conditions and the following disclaimer.
|
12
|
+
*
|
13
|
+
* * Redistributions in binary form must reproduce the above copyright
|
14
|
+
* notice, this list of conditions and the following disclaimer in the
|
15
|
+
* documentation and/or other materials provided with the distribution.
|
16
|
+
*
|
17
|
+
* * Neither the name of the Mongrel2 Project, Zed A. Shaw, nor the names
|
18
|
+
* of its contributors may be used to endorse or promote products
|
19
|
+
* derived from this software without specific prior written
|
20
|
+
* permission.
|
21
|
+
*
|
22
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
23
|
+
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
24
|
+
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
25
|
+
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
26
|
+
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
27
|
+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
28
|
+
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
29
|
+
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
30
|
+
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
31
|
+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
32
|
+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
33
|
+
*/
|
34
|
+
|
35
|
+
#ifndef __dbg_h__
|
36
|
+
#define __dbg_h__
|
37
|
+
|
38
|
+
#include <stdio.h>
|
39
|
+
#include <errno.h>
|
40
|
+
#include <string.h>
|
41
|
+
|
42
|
+
void dbg_set_log(FILE *log_file);
|
43
|
+
FILE *dbg_get_log();
|
44
|
+
|
45
|
+
#ifdef NDEBUG
|
46
|
+
#define debug(M, ...)
|
47
|
+
#else
|
48
|
+
#define debug(M, ...) fprintf(dbg_get_log(), "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
49
|
+
#endif
|
50
|
+
|
51
|
+
|
52
|
+
// do not try to be smart and make this go away on NDEBUG, the _debug
|
53
|
+
// here means that it just doesn't print a message, it still does the
|
54
|
+
// check. MKAY?
|
55
|
+
#define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__); errno=0; goto error; }
|
56
|
+
|
57
|
+
#define clean_errno() (errno == 0 ? "None" : strerror(errno))
|
58
|
+
|
59
|
+
#ifdef NO_LINENOS
|
60
|
+
// versions that don't feature line numbers
|
61
|
+
#define log_err(M, ...) fprintf(dbg_get_log(), "[ERROR] (errno: %s) " M "\n", clean_errno(), ##__VA_ARGS__)
|
62
|
+
#define log_warn(M, ...) fprintf(dbg_get_log(), "[WARN] (errno: %s) " M "\n", clean_errno(), ##__VA_ARGS__)
|
63
|
+
#define log_info(M, ...) fprintf(dbg_get_log(), "[INFO] " M "\n", ##__VA_ARGS__)
|
64
|
+
#else
|
65
|
+
#define log_err(M, ...) fprintf(dbg_get_log(), "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)
|
66
|
+
#define log_warn(M, ...) fprintf(dbg_get_log(), "[WARN] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)
|
67
|
+
#define log_info(M, ...) fprintf(dbg_get_log(), "[INFO] (%s:%d) " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
68
|
+
#endif
|
69
|
+
|
70
|
+
#define check(A, M, ...) if(!(A)) { log_err(M, ##__VA_ARGS__); errno=0; goto error; }
|
71
|
+
|
72
|
+
#define sentinel(M, ...) { log_err(M, ##__VA_ARGS__); errno=0; goto error; }
|
73
|
+
|
74
|
+
#define check_mem(A) check((A), "Out of memory.")
|
75
|
+
|
76
|
+
#endif
|
data/src/export.c
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
#include "export.h"
|
2
|
+
|
3
|
+
stl_object *stl_from_polys(klist_t(poly) *polygons) {
|
4
|
+
stl_object *stl = stl_alloc(NULL, polygons->size);
|
5
|
+
check_mem(stl);
|
6
|
+
|
7
|
+
kliter_t(poly) *iter = kl_begin(polygons);
|
8
|
+
stl_facet *facet = stl->facets;
|
9
|
+
poly_t *poly = NULL;
|
10
|
+
for(; iter != kl_end(polygons); iter = kl_next(iter), facet++) {
|
11
|
+
poly = kl_val(iter);
|
12
|
+
check(poly_vertex_count(poly) == 3, "Polygon is not a triangle.");
|
13
|
+
memcpy(facet->normal, poly->normal, sizeof(float3));
|
14
|
+
memcpy(facet->vertices, poly->vertices, sizeof(facet->vertices));
|
15
|
+
}
|
16
|
+
|
17
|
+
return stl;
|
18
|
+
error:
|
19
|
+
if(stl) stl_free(stl);
|
20
|
+
return NULL;
|
21
|
+
}
|
22
|
+
|
23
|
+
stl_object *bsp_to_stl(bsp_node_t *tree) {
|
24
|
+
stl_object *stl = NULL;
|
25
|
+
klist_t(poly) *polys = NULL;
|
26
|
+
|
27
|
+
polys = bsp_to_polygons(tree, 1, NULL);
|
28
|
+
check(polys != NULL, "Failed to generate polygons from bsp_node_t(%p)", tree);
|
29
|
+
check(polys->size > 0, "No polygons returned from tree(%p)", tree);
|
30
|
+
|
31
|
+
stl = stl_from_polys(polys);
|
32
|
+
check(stl != NULL, "Failed to build stl from %zd polygons", polys->size);
|
33
|
+
strcpy(stl->header, "[csgtool BSP output]");
|
34
|
+
|
35
|
+
kl_destroy(poly, polys);
|
36
|
+
return stl;
|
37
|
+
error:
|
38
|
+
if(polys) kl_destroy(poly, polys);
|
39
|
+
if(stl) stl_free(stl);
|
40
|
+
return NULL;
|
41
|
+
}
|
42
|
+
|
43
|
+
bsp_node_t *stl_to_bsp(stl_object *stl) {
|
44
|
+
bsp_node_t *tree = NULL;
|
45
|
+
klist_t(poly) *polys = kl_init(poly);
|
46
|
+
poly_t *poly = NULL;
|
47
|
+
|
48
|
+
for(int i = 0; i < stl->facet_count; i++) {
|
49
|
+
poly = poly_make_triangle(stl->facets[i].vertices[0],
|
50
|
+
stl->facets[i].vertices[1],
|
51
|
+
stl->facets[i].vertices[2]);
|
52
|
+
check_mem(polys);
|
53
|
+
*kl_pushp(poly, polys) = poly;
|
54
|
+
}
|
55
|
+
check(polys->size == stl->facet_count, "Wrong number of faces generated.");
|
56
|
+
|
57
|
+
tree = bsp_build(NULL, polys, 1);
|
58
|
+
check_mem(tree);
|
59
|
+
|
60
|
+
kl_destroy(poly, polys);
|
61
|
+
return tree;
|
62
|
+
error:
|
63
|
+
if(polys != NULL) kl_destroy(poly, polys);
|
64
|
+
if(tree != NULL) {
|
65
|
+
free_bsp_tree(tree);
|
66
|
+
}
|
67
|
+
return NULL;
|
68
|
+
}
|
data/src/export.h
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#include <string.h>
|
2
|
+
|
3
|
+
#include "dbg.h"
|
4
|
+
|
5
|
+
#include "stl.h"
|
6
|
+
#include "poly.h"
|
7
|
+
#include "bsp.h"
|
8
|
+
|
9
|
+
#ifndef __EXPORT_H
|
10
|
+
#define __EXPORT_H
|
11
|
+
|
12
|
+
stl_object *stl_from_polys(klist_t(poly) *polygons);
|
13
|
+
stl_object *bsp_to_stl(bsp_node_t *tree);
|
14
|
+
bsp_node_t *stl_to_bsp(stl_object *stl);
|
15
|
+
|
16
|
+
#endif
|
data/src/klist.h
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
/* The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2008-2009, by Attractive Chaos <attractor@live.co.uk>
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
20
|
+
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
21
|
+
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
22
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
23
|
+
SOFTWARE.
|
24
|
+
*/
|
25
|
+
|
26
|
+
#ifndef _AC_KLIST_H
|
27
|
+
#define _AC_KLIST_H
|
28
|
+
|
29
|
+
#include <stdlib.h>
|
30
|
+
|
31
|
+
#define KMEMPOOL_INIT(name, kmptype_t, kmpfree_f) \
|
32
|
+
typedef struct { \
|
33
|
+
size_t cnt, n, max; \
|
34
|
+
kmptype_t **buf; \
|
35
|
+
} kmp_##name##_t; \
|
36
|
+
static inline kmp_##name##_t *kmp_init_##name() { \
|
37
|
+
return calloc(1, sizeof(kmp_##name##_t)); \
|
38
|
+
} \
|
39
|
+
static inline void kmp_destroy_##name(kmp_##name##_t *mp) { \
|
40
|
+
size_t k; \
|
41
|
+
for (k = 0; k < mp->n; ++k) { \
|
42
|
+
kmpfree_f(mp->buf[k]); free(mp->buf[k]); \
|
43
|
+
} \
|
44
|
+
free(mp->buf); free(mp); \
|
45
|
+
} \
|
46
|
+
static inline kmptype_t *kmp_alloc_##name(kmp_##name##_t *mp) { \
|
47
|
+
++mp->cnt; \
|
48
|
+
if (mp->n == 0) return calloc(1, sizeof(kmptype_t)); \
|
49
|
+
return mp->buf[--mp->n]; \
|
50
|
+
} \
|
51
|
+
static inline void kmp_free_##name(kmp_##name##_t *mp, kmptype_t *p) { \
|
52
|
+
--mp->cnt; \
|
53
|
+
if (mp->n == mp->max) { \
|
54
|
+
mp->max = mp->max? mp->max<<1 : 16; \
|
55
|
+
mp->buf = realloc(mp->buf, sizeof(void*) * mp->max); \
|
56
|
+
} \
|
57
|
+
mp->buf[mp->n++] = p; \
|
58
|
+
}
|
59
|
+
|
60
|
+
#define kmempool_t(name) kmp_##name##_t
|
61
|
+
#define kmp_init(name) kmp_init_##name()
|
62
|
+
#define kmp_destroy(name, mp) kmp_destroy_##name(mp)
|
63
|
+
#define kmp_alloc(name, mp) kmp_alloc_##name(mp)
|
64
|
+
#define kmp_free(name, mp, p) kmp_free_##name(mp, p)
|
65
|
+
|
66
|
+
#define KLIST_INIT(name, kltype_t, kmpfree_t) \
|
67
|
+
struct __kl1_##name { \
|
68
|
+
kltype_t data; \
|
69
|
+
struct __kl1_##name *next; \
|
70
|
+
}; \
|
71
|
+
typedef struct __kl1_##name kl1_##name; \
|
72
|
+
KMEMPOOL_INIT(name, kl1_##name, kmpfree_t) \
|
73
|
+
typedef struct { \
|
74
|
+
kl1_##name *head, *tail; \
|
75
|
+
kmp_##name##_t *mp; \
|
76
|
+
size_t size; \
|
77
|
+
} kl_##name##_t; \
|
78
|
+
static inline kl_##name##_t *kl_init_##name() { \
|
79
|
+
kl_##name##_t *kl = calloc(1, sizeof(kl_##name##_t)); \
|
80
|
+
kl->mp = kmp_init(name); \
|
81
|
+
kl->head = kl->tail = kmp_alloc(name, kl->mp); \
|
82
|
+
kl->head->next = 0; \
|
83
|
+
return kl; \
|
84
|
+
} \
|
85
|
+
static inline void kl_destroy_##name(kl_##name##_t *kl) { \
|
86
|
+
kl1_##name *p; \
|
87
|
+
for (p = kl->head; p != kl->tail; p = p->next) \
|
88
|
+
kmp_free(name, kl->mp, p); \
|
89
|
+
kmp_free(name, kl->mp, p); \
|
90
|
+
kmp_destroy(name, kl->mp); \
|
91
|
+
free(kl); \
|
92
|
+
} \
|
93
|
+
static inline kltype_t *kl_pushp_##name(kl_##name##_t *kl) { \
|
94
|
+
kl1_##name *q, *p = kmp_alloc(name, kl->mp); \
|
95
|
+
q = kl->tail; p->next = 0; kl->tail->next = p; kl->tail = p; \
|
96
|
+
++kl->size; \
|
97
|
+
return &q->data; \
|
98
|
+
} \
|
99
|
+
static inline int kl_shift_##name(kl_##name##_t *kl, kltype_t *d) { \
|
100
|
+
kl1_##name *p; \
|
101
|
+
if (kl->head->next == 0) return -1; \
|
102
|
+
--kl->size; \
|
103
|
+
p = kl->head; kl->head = kl->head->next; \
|
104
|
+
if (d) *d = p->data; \
|
105
|
+
kmp_free(name, kl->mp, p); \
|
106
|
+
return 0; \
|
107
|
+
}
|
108
|
+
|
109
|
+
#define kliter_t(name) kl1_##name
|
110
|
+
#define klist_t(name) kl_##name##_t
|
111
|
+
#define kl_val(iter) ((iter)->data)
|
112
|
+
#define kl_next(iter) ((iter)->next)
|
113
|
+
#define kl_begin(kl) ((kl)->head)
|
114
|
+
#define kl_end(kl) ((kl)->tail)
|
115
|
+
|
116
|
+
#define kl_init(name) kl_init_##name()
|
117
|
+
#define kl_destroy(name, kl) kl_destroy_##name(kl)
|
118
|
+
#define kl_pushp(name, kl) kl_pushp_##name(kl)
|
119
|
+
#define kl_shift(name, kl, d) kl_shift_##name(kl, d)
|
120
|
+
|
121
|
+
#endif
|
data/src/poly.c
ADDED
@@ -0,0 +1,206 @@
|
|
1
|
+
#include <assert.h>
|
2
|
+
|
3
|
+
#include "poly.h"
|
4
|
+
|
5
|
+
poly_t *alloc_poly(void) {
|
6
|
+
poly_t *poly = malloc(sizeof(poly_t));
|
7
|
+
check_mem(poly);
|
8
|
+
poly_init(poly);
|
9
|
+
return poly;
|
10
|
+
error:
|
11
|
+
return NULL;
|
12
|
+
}
|
13
|
+
|
14
|
+
void free_poly(poly_t *p, int free_self) {
|
15
|
+
if(p == NULL) return;
|
16
|
+
if(free_self) free(p);
|
17
|
+
}
|
18
|
+
|
19
|
+
poly_t *poly_init(poly_t *poly) {
|
20
|
+
poly->vertex_count = 0;
|
21
|
+
return poly;
|
22
|
+
}
|
23
|
+
|
24
|
+
poly_t *clone_poly(poly_t *poly) {
|
25
|
+
poly_t *copy = NULL;
|
26
|
+
check_mem(copy = alloc_poly());
|
27
|
+
memcpy(copy, poly, sizeof(poly_t));
|
28
|
+
return copy;
|
29
|
+
error:
|
30
|
+
return NULL;
|
31
|
+
}
|
32
|
+
|
33
|
+
int poly_update(poly_t *poly) {
|
34
|
+
if(poly_vertex_count(poly) < 3) return -1;
|
35
|
+
|
36
|
+
float3 *a = &poly->vertices[0];
|
37
|
+
float3 *b = &poly->vertices[1];
|
38
|
+
float3 *c = &poly->vertices[2];
|
39
|
+
|
40
|
+
float3 b_a;
|
41
|
+
float3 c_a;
|
42
|
+
f3_sub(&b_a, *b, *a);
|
43
|
+
f3_sub(&c_a, *c, *a);
|
44
|
+
|
45
|
+
f3_cross(&poly->normal, b_a, c_a);
|
46
|
+
f3_normalize(&poly->normal);
|
47
|
+
|
48
|
+
poly->w = f3_dot(poly->normal, *a);
|
49
|
+
return 0;
|
50
|
+
}
|
51
|
+
|
52
|
+
int poly_vertex_count(poly_t *poly) {
|
53
|
+
return poly->vertex_count;
|
54
|
+
}
|
55
|
+
|
56
|
+
// Add a vertex to the end of the polygon vertex list
|
57
|
+
int poly_push_vertex(poly_t *poly, float3 v) {
|
58
|
+
// TODO: Don't assert, grow
|
59
|
+
assert(poly->vertex_count < POLY_MAX_VERTS);
|
60
|
+
|
61
|
+
// Dat assignment copy
|
62
|
+
poly->vertices[poly->vertex_count][0] = v[0];
|
63
|
+
poly->vertices[poly->vertex_count][1] = v[1];
|
64
|
+
poly->vertices[poly->vertex_count][2] = v[2];
|
65
|
+
|
66
|
+
// Update the poly if we can
|
67
|
+
if(++poly->vertex_count > 2) {
|
68
|
+
check(poly_update(poly) == 0, "Failed to update polygon during poly_push_vertex(%p)", poly);
|
69
|
+
}
|
70
|
+
|
71
|
+
return 0;
|
72
|
+
error:
|
73
|
+
return -1;
|
74
|
+
}
|
75
|
+
|
76
|
+
int poly_classify_vertex(poly_t *poly, float3 v) {
|
77
|
+
float side = f3_dot(poly->normal, v) - poly->w;
|
78
|
+
if(side < -EPSILON) return BACK;
|
79
|
+
if(side > EPSILON) return FRONT;
|
80
|
+
return COPLANAR;
|
81
|
+
}
|
82
|
+
|
83
|
+
int poly_classify_poly(poly_t *this, poly_t *other) {
|
84
|
+
int front, back;
|
85
|
+
int count = poly_vertex_count(other);
|
86
|
+
|
87
|
+
front = 0;
|
88
|
+
back = 0;
|
89
|
+
|
90
|
+
for(int i = 0; i < count; i++) {
|
91
|
+
switch(poly_classify_vertex(this, other->vertices[i])) {
|
92
|
+
case FRONT:
|
93
|
+
front += 1;
|
94
|
+
break;
|
95
|
+
case BACK:
|
96
|
+
back += 1;
|
97
|
+
break;
|
98
|
+
}
|
99
|
+
}
|
100
|
+
if(front > 0 && back == 0) return FRONT;
|
101
|
+
if(back > 0 && front == 0) return BACK;
|
102
|
+
if(front == 0 && back == 0) return COPLANAR;
|
103
|
+
return SPANNING;
|
104
|
+
}
|
105
|
+
|
106
|
+
int poly_split(poly_t *divider, poly_t *poly, poly_t **front, poly_t **back) {
|
107
|
+
// Create polygons if we were not passed allocated ones
|
108
|
+
if(*front == NULL) {
|
109
|
+
*front = alloc_poly();
|
110
|
+
}
|
111
|
+
if(*back == NULL) {
|
112
|
+
*back = alloc_poly();
|
113
|
+
}
|
114
|
+
|
115
|
+
// Current and next vertex
|
116
|
+
float3 v_cur = FLOAT3_INIT;
|
117
|
+
float3 v_next = FLOAT3_INIT;
|
118
|
+
// Classifications of the above
|
119
|
+
int c_cur, c_next;
|
120
|
+
// Loop indexes
|
121
|
+
int i, j;
|
122
|
+
int count = poly_vertex_count(poly);
|
123
|
+
for(i = 0; i < count; i++) {
|
124
|
+
j = (i + 1) % count;
|
125
|
+
for(int k = 0; k < 3; k++) {
|
126
|
+
v_cur[k] = poly->vertices[i][k];
|
127
|
+
v_next[k] = poly->vertices[j][k];
|
128
|
+
}
|
129
|
+
|
130
|
+
// Classify the first and next vertex
|
131
|
+
c_cur = poly_classify_vertex(divider, v_cur);
|
132
|
+
c_next = poly_classify_vertex(divider, v_next);
|
133
|
+
|
134
|
+
if(c_cur != BACK) {
|
135
|
+
poly_push_vertex(*front, v_cur);
|
136
|
+
}
|
137
|
+
if(c_cur != FRONT) {
|
138
|
+
poly_push_vertex(*back, v_cur);
|
139
|
+
}
|
140
|
+
|
141
|
+
// Interpolate a midpoint if we found a spanning edge
|
142
|
+
if((c_cur | c_next) == SPANNING) {
|
143
|
+
float3 diff = FLOAT3_INIT;
|
144
|
+
f3_sub(&diff, v_next, v_cur);
|
145
|
+
|
146
|
+
float t = divider->w;
|
147
|
+
t = t - f3_dot(divider->normal, v_cur);
|
148
|
+
t = t / f3_dot(divider->normal, diff);
|
149
|
+
|
150
|
+
float3 mid_f = {v_cur[0], v_cur[1], v_cur[2]};
|
151
|
+
f3_interpolate(&mid_f, v_cur, v_next, t);
|
152
|
+
|
153
|
+
check(poly_push_vertex(*front, mid_f) == 0,
|
154
|
+
"Failed to push midpoint to front poly(%p)", front);
|
155
|
+
check(poly_push_vertex(*back, mid_f) == 0,
|
156
|
+
"Failed to push midpoint to back poly(%p):", back);
|
157
|
+
}
|
158
|
+
}
|
159
|
+
|
160
|
+
return 0;
|
161
|
+
error:
|
162
|
+
return -1;
|
163
|
+
}
|
164
|
+
|
165
|
+
poly_t *poly_make_triangle(float3 a, float3 b, float3 c) {
|
166
|
+
poly_t *p = NULL;
|
167
|
+
check_mem(p = alloc_poly());
|
168
|
+
|
169
|
+
check(poly_push_vertex(p, a) == 0,
|
170
|
+
"Failed to add vertex a to poly(%p): (%f, %f, %f)", p, FLOAT3_FORMAT(a));
|
171
|
+
check(poly_push_vertex(p, b) == 0,
|
172
|
+
"Failed to add vertex b to poly(%p): (%f, %f, %f)", p, FLOAT3_FORMAT(b));
|
173
|
+
check(poly_push_vertex(p, c) == 0,
|
174
|
+
"Failed to add vertex c to poly(%p): (%f, %f, %f)", p, FLOAT3_FORMAT(c));
|
175
|
+
|
176
|
+
return p;
|
177
|
+
error:
|
178
|
+
if(p) free_poly(p, 1);
|
179
|
+
return NULL;
|
180
|
+
}
|
181
|
+
|
182
|
+
poly_t *poly_invert(poly_t *poly) {
|
183
|
+
f3_scale(&poly->normal, -1.0);
|
184
|
+
poly->w *= -1.0;
|
185
|
+
|
186
|
+
// We walk the list from the back to the midway point
|
187
|
+
// and flip the opposite ends to reverse the poly list.
|
188
|
+
int last = poly_vertex_count(poly) - 1;
|
189
|
+
int first = 0;
|
190
|
+
float3 temp = FLOAT3_INIT;
|
191
|
+
for(; first < last; first++, last--) {
|
192
|
+
temp[0] = poly->vertices[last][0];
|
193
|
+
temp[1] = poly->vertices[last][1];
|
194
|
+
temp[2] = poly->vertices[last][2];
|
195
|
+
|
196
|
+
poly->vertices[last][0] = poly->vertices[first][0];
|
197
|
+
poly->vertices[last][1] = poly->vertices[first][1];
|
198
|
+
poly->vertices[last][2] = poly->vertices[first][2];
|
199
|
+
|
200
|
+
poly->vertices[first][0] = temp[0];
|
201
|
+
poly->vertices[first][1] = temp[1];
|
202
|
+
poly->vertices[first][2] = temp[2];
|
203
|
+
}
|
204
|
+
|
205
|
+
return poly;
|
206
|
+
}
|