csg 0.0.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.
- 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/poly.h
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
#include <strings.h>
|
2
|
+
#include "dbg.h"
|
3
|
+
#include "klist.h"
|
4
|
+
#include "vector.h"
|
5
|
+
|
6
|
+
#ifndef __POLY_H
|
7
|
+
#define __POLY_H
|
8
|
+
|
9
|
+
#define EPSILON 1e-5
|
10
|
+
#define COPLANAR 0
|
11
|
+
#define FRONT 1
|
12
|
+
#define BACK 2
|
13
|
+
#define SPANNING 3
|
14
|
+
|
15
|
+
#define POLY_MAX_VERTS 40
|
16
|
+
|
17
|
+
typedef struct s_poly {
|
18
|
+
float3 vertices[POLY_MAX_VERTS];
|
19
|
+
int vertex_count;
|
20
|
+
|
21
|
+
float3 normal;
|
22
|
+
float w;
|
23
|
+
} poly_t;
|
24
|
+
|
25
|
+
poly_t *alloc_poly(void);
|
26
|
+
poly_t *poly_make_triangle(float3 a, float3 b, float3 c);
|
27
|
+
poly_t *clone_poly(poly_t *poly);
|
28
|
+
void free_poly(poly_t *p, int free_self);
|
29
|
+
|
30
|
+
poly_t *poly_init(poly_t *poly);
|
31
|
+
int poly_update(poly_t *poly);
|
32
|
+
poly_t *poly_invert(poly_t *poly);
|
33
|
+
|
34
|
+
int poly_vertex_count(poly_t *poly);
|
35
|
+
int poly_push_vertex(poly_t *poly, float3 v);
|
36
|
+
|
37
|
+
int poly_classify_vertex(poly_t *poly, float3 v);
|
38
|
+
int poly_classify_poly(poly_t *this, poly_t *other);
|
39
|
+
|
40
|
+
int poly_split(poly_t *divider, poly_t *poly, poly_t **front, poly_t **back);
|
41
|
+
|
42
|
+
#define mp_poly_free(x) free_poly(kl_val(x), 1)
|
43
|
+
KLIST_INIT(poly, poly_t*, mp_poly_free)
|
44
|
+
|
45
|
+
#endif
|
data/src/stl.c
ADDED
@@ -0,0 +1,333 @@
|
|
1
|
+
#include <ctype.h>
|
2
|
+
#include <fcntl.h>
|
3
|
+
#include <stdio.h>
|
4
|
+
#include <stdlib.h>
|
5
|
+
#include <math.h>
|
6
|
+
|
7
|
+
#include "dbg.h"
|
8
|
+
|
9
|
+
#include "stl.h"
|
10
|
+
|
11
|
+
void stl_free(stl_object *obj) {
|
12
|
+
if(obj == NULL) return;
|
13
|
+
if(obj->facets) free(obj->facets);
|
14
|
+
free(obj);
|
15
|
+
}
|
16
|
+
|
17
|
+
stl_object *stl_alloc(char *header, uint32_t n_facets) {
|
18
|
+
stl_object *obj = (stl_object*)calloc(1, sizeof(stl_object));
|
19
|
+
check_mem(obj);
|
20
|
+
|
21
|
+
if(header != NULL) {
|
22
|
+
memcpy(obj->header, header, sizeof(obj->header));
|
23
|
+
}
|
24
|
+
|
25
|
+
obj->facet_count = n_facets;
|
26
|
+
if(n_facets > 0) {
|
27
|
+
obj->facets = (stl_facet*)calloc(n_facets, sizeof(stl_facet));
|
28
|
+
check_mem(obj->facets);
|
29
|
+
}
|
30
|
+
|
31
|
+
return obj;
|
32
|
+
error:
|
33
|
+
exit(-1);
|
34
|
+
}
|
35
|
+
|
36
|
+
void v3_cross(float3 *result, float3 v1, float3 v2, int normalize) {
|
37
|
+
float3 v1_x_v2 = {
|
38
|
+
v1[1]*v2[2] - v1[2]*v2[1],
|
39
|
+
v1[2]*v2[0] - v1[0]*v2[2],
|
40
|
+
v1[0]*v2[1] - v1[1]*v2[0]
|
41
|
+
};
|
42
|
+
if(normalize) {
|
43
|
+
float mag = sqrt(v1_x_v2[0]*v1_x_v2[0] + v1_x_v2[1]*v1_x_v2[1] + v1_x_v2[2]*v1_x_v2[2]);
|
44
|
+
v1_x_v2[0] /= mag;
|
45
|
+
v1_x_v2[1] /= mag;
|
46
|
+
v1_x_v2[2] /= mag;
|
47
|
+
}
|
48
|
+
memcpy(result, &v1_x_v2, sizeof(float3));
|
49
|
+
}
|
50
|
+
|
51
|
+
void stl_facet_update_normal(stl_facet *facet) {
|
52
|
+
float3 *fvs = facet->vertices;
|
53
|
+
float3 v1 = {fvs[0][0] - fvs[1][0], fvs[0][1] - fvs[1][1], fvs[0][2] - fvs[1][2]};
|
54
|
+
float3 v2 = {fvs[0][0] - fvs[2][0], fvs[0][1] - fvs[2][1], fvs[0][2] - fvs[2][2]};
|
55
|
+
v3_cross(&facet->normal, v1, v2, 1);
|
56
|
+
}
|
57
|
+
|
58
|
+
stl_facet *stl_read_facet(int fd) {
|
59
|
+
int rc = -1;
|
60
|
+
stl_facet *facet = (stl_facet*)calloc(1, sizeof(stl_facet));
|
61
|
+
check_mem(facet);
|
62
|
+
|
63
|
+
rc = read(fd, &facet->normal, sizeof(facet->normal));
|
64
|
+
check(rc == sizeof(facet->normal), "Failed to read normal. Read %d expected %zu", rc, sizeof(facet->normal));
|
65
|
+
rc = read(fd, &facet->vertices, sizeof(facet->vertices));
|
66
|
+
check(rc == sizeof(facet->vertices), "Failed to read triangle vertecies. Read %d expected %zu", rc, sizeof(facet->vertices));
|
67
|
+
rc = read(fd, &facet->attr, sizeof(facet->attr));
|
68
|
+
check(rc == sizeof(facet->attr), "Failed to read attr bytes. Read %d expect %zu", rc, sizeof(facet->attr));
|
69
|
+
|
70
|
+
return facet;
|
71
|
+
error:
|
72
|
+
exit(-1);
|
73
|
+
}
|
74
|
+
|
75
|
+
/*
|
76
|
+
* Allocate, read, and return a anull terminated string from `fd'.
|
77
|
+
* Return NULL in caes of error
|
78
|
+
*/
|
79
|
+
char* read_line(int fd, int downcase, int trim) {
|
80
|
+
const size_t max_line = 100;
|
81
|
+
char *buffer = calloc(max_line + 1, sizeof(char));
|
82
|
+
int rc = -1;
|
83
|
+
check_mem(buffer);
|
84
|
+
|
85
|
+
rc = read(fd, buffer, max_line);
|
86
|
+
check(rc != -1, "Failed to read.");
|
87
|
+
|
88
|
+
char *ret = NULL;
|
89
|
+
while((ret = strchr(buffer, '\r'))) {
|
90
|
+
*ret = ' ';
|
91
|
+
}
|
92
|
+
|
93
|
+
char *newline = strchr(buffer, '\n');
|
94
|
+
if(newline != NULL) *newline = '\0';
|
95
|
+
|
96
|
+
if((strlen(buffer) == 0) && (rc == 0)) goto eof;
|
97
|
+
|
98
|
+
rc = lseek(fd, -(rc - strlen(buffer) - 1), SEEK_CUR);
|
99
|
+
check(rc != -1, "Failed to seek.");
|
100
|
+
|
101
|
+
if(trim) {
|
102
|
+
char *new = NULL;
|
103
|
+
int start = 0;
|
104
|
+
int end = strlen(buffer) ;
|
105
|
+
while(isspace(buffer[start++]));
|
106
|
+
while(isspace(buffer[--end]));
|
107
|
+
if(start > 0) start--;
|
108
|
+
buffer[++end] = '\0';
|
109
|
+
check_mem((new = calloc(strlen(buffer + start) + 1, 1)));
|
110
|
+
memcpy(new, buffer + start, end - start);
|
111
|
+
free(buffer);
|
112
|
+
buffer = new;
|
113
|
+
}
|
114
|
+
|
115
|
+
if(downcase) {
|
116
|
+
for(int i = 0; i < strlen(buffer); i++) {
|
117
|
+
buffer[i] = tolower(buffer[i]);
|
118
|
+
}
|
119
|
+
}
|
120
|
+
|
121
|
+
|
122
|
+
return buffer;
|
123
|
+
eof:
|
124
|
+
error:
|
125
|
+
if(buffer) free(buffer);
|
126
|
+
return NULL;
|
127
|
+
}
|
128
|
+
|
129
|
+
stl_facet *stl_read_text_facet(const char *declaration, int fd) {
|
130
|
+
stl_facet *facet = (stl_facet*)calloc(1, sizeof(stl_facet));
|
131
|
+
int rc = -1;
|
132
|
+
char *line = NULL;
|
133
|
+
|
134
|
+
check_mem(facet);
|
135
|
+
rc = sscanf(declaration, "facet normal %f %f %f", &facet->normal[0], &facet->normal[1], &facet->normal[2]);
|
136
|
+
check(rc == 3, "stl_Read_text_facet(%s): Normal line malformed", declaration);
|
137
|
+
|
138
|
+
check((line = read_line(fd, 1, 1)), "Malformed facet, no line follows valid normal declaration");
|
139
|
+
check(strcmp(line, "outer loop") == 0, "Malformed facet, no loop declaration following valid normal.");
|
140
|
+
|
141
|
+
for(int i = 0; i < 3; i++) {
|
142
|
+
check((line = read_line(fd, 1, 1)), "Failed to read vertex %d", i);
|
143
|
+
rc = sscanf(line, "vertex %f %f %f", &facet->vertices[i][0], &facet->vertices[i][1], &facet->vertices[i][2]);
|
144
|
+
check(rc == 3, "Vertex declaration [%s] did not contain (x, y, z) point.", line);
|
145
|
+
|
146
|
+
free(line);
|
147
|
+
line = NULL;
|
148
|
+
}
|
149
|
+
|
150
|
+
check((line = read_line(fd, 1, 1)), "No line following vertex declarations.");
|
151
|
+
check(strcmp(line, "endloop") == 0, "Vertex declarations not followed by 'endloop'. Got: '%s'", line);
|
152
|
+
free(line);
|
153
|
+
check((line = read_line(fd, 1, 1)), "No line following endloop.");
|
154
|
+
check(strcmp(line, "endfacet") == 0, "endloop not followed by 'endfacet'");
|
155
|
+
free(line);
|
156
|
+
line = NULL;
|
157
|
+
|
158
|
+
return facet;
|
159
|
+
error:
|
160
|
+
if(line) free(line);
|
161
|
+
if(facet) free(facet);
|
162
|
+
return NULL;
|
163
|
+
}
|
164
|
+
|
165
|
+
stl_object *stl_read_text_object(int fd) {
|
166
|
+
stl_object *obj = NULL;
|
167
|
+
char *line = read_line(fd, 0, 1);
|
168
|
+
klist_t(stl_facet) *facets = kl_init(stl_facet);
|
169
|
+
|
170
|
+
check(line != NULL, "Failed to read STL/ASCII header.");
|
171
|
+
check((obj = stl_alloc(NULL, 0)), "Failed to allocated new STL object.");
|
172
|
+
snprintf(obj->header, sizeof(obj->header), "[STL/ASCII]: '%s'", line);
|
173
|
+
log_info("Header: [%s]", obj->header);
|
174
|
+
free(line);
|
175
|
+
|
176
|
+
size_t lines = 0;
|
177
|
+
while((line = read_line(fd, 1, 1))) {
|
178
|
+
lines++;
|
179
|
+
if(strncmp(line, "facet", strlen("facet")) == 0) {
|
180
|
+
stl_facet *facet = stl_read_text_facet(line, fd);
|
181
|
+
check(facet != NULL, "Failed to read facet on line %zd", lines);
|
182
|
+
*kl_pushp(stl_facet, facets) = facet;
|
183
|
+
}
|
184
|
+
else if(strncmp(line, "endsolid", strlen("endfacet")) == 0) {
|
185
|
+
check(facets->size > 0, "No facets loaded.");
|
186
|
+
log_info("ASCII solid ended. Loaded %zd facets", facets->size);
|
187
|
+
|
188
|
+
obj->facet_count = facets->size;
|
189
|
+
obj->facets = calloc(facets->size, sizeof(stl_facet));
|
190
|
+
check_mem(obj->facets);
|
191
|
+
|
192
|
+
stl_facet *facet = NULL;
|
193
|
+
for(int i = 0; kl_shift(stl_facet, facets, &facet) != -1; i++) {
|
194
|
+
obj->facets[i] = *facet;
|
195
|
+
}
|
196
|
+
}
|
197
|
+
else {
|
198
|
+
sentinel("Unexpected line[%zd]: '%s'", lines, line);
|
199
|
+
}
|
200
|
+
free(line);
|
201
|
+
}
|
202
|
+
|
203
|
+
kl_destroy(stl_facet, facets);
|
204
|
+
return obj;
|
205
|
+
error:
|
206
|
+
kl_destroy(stl_facet, facets);
|
207
|
+
return NULL;
|
208
|
+
}
|
209
|
+
|
210
|
+
stl_object *stl_read_object(int fd) {
|
211
|
+
int rc = -1;
|
212
|
+
char header[80] = {0};
|
213
|
+
uint32_t n_tris = 0;
|
214
|
+
stl_object *obj = NULL;
|
215
|
+
|
216
|
+
// Read the header
|
217
|
+
rc = read(fd, header, sizeof(header));
|
218
|
+
check(rc == sizeof(header), "Unable to read STL header. Got %d bytes.", rc);
|
219
|
+
|
220
|
+
// Triangle count
|
221
|
+
rc = read(fd, &n_tris, sizeof(n_tris));
|
222
|
+
check(rc == sizeof(n_tris), "Failed to read facet count.");
|
223
|
+
check(n_tris > 0, "Facet count cannot be zero.");
|
224
|
+
|
225
|
+
obj = stl_alloc(header, n_tris);
|
226
|
+
|
227
|
+
for(uint32_t i = 0; i < obj->facet_count; i++) {
|
228
|
+
stl_facet *facet = stl_read_facet(fd);
|
229
|
+
memcpy(&obj->facets[i], facet, sizeof(stl_facet));
|
230
|
+
free(facet);
|
231
|
+
}
|
232
|
+
|
233
|
+
return obj;
|
234
|
+
error:
|
235
|
+
if(obj) stl_free(obj);
|
236
|
+
return NULL;
|
237
|
+
}
|
238
|
+
|
239
|
+
stl_object *stl_read_file(char *path, int recompute_normals) {
|
240
|
+
stl_reader* reader = NULL;
|
241
|
+
stl_object *obj = NULL;
|
242
|
+
int fd = -1;
|
243
|
+
|
244
|
+
check((reader = stl_detect_reader(path)), "Unable to find reader for format of %s", path);
|
245
|
+
check((fd = open(path, O_RDONLY)) != -1, "Unable to open '%s'", path);
|
246
|
+
|
247
|
+
obj = reader(fd);
|
248
|
+
|
249
|
+
char buffer[10];
|
250
|
+
int rc = read(fd, buffer, sizeof(buffer));
|
251
|
+
check(rc == 0, "File did not end when expected, assuming failure.");
|
252
|
+
close(fd);
|
253
|
+
|
254
|
+
if(recompute_normals) {
|
255
|
+
for(int i = 0; i < obj->facet_count; i++) {
|
256
|
+
stl_facet_update_normal(&obj->facets[i]);
|
257
|
+
}
|
258
|
+
}
|
259
|
+
|
260
|
+
return obj;
|
261
|
+
error:
|
262
|
+
if(fd != -1) close(fd);
|
263
|
+
if(obj) stl_free(obj);
|
264
|
+
return NULL;
|
265
|
+
}
|
266
|
+
|
267
|
+
int stl_write_file(stl_object *obj, char *path) {
|
268
|
+
int rc = -1;
|
269
|
+
int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0755);
|
270
|
+
check(fd != -1, "Failed to open '%s' for write", path);
|
271
|
+
|
272
|
+
rc = stl_write_object(obj, fd);
|
273
|
+
|
274
|
+
close(fd);
|
275
|
+
return rc;
|
276
|
+
error:
|
277
|
+
if(fd != -1) close(fd);
|
278
|
+
return -1;
|
279
|
+
}
|
280
|
+
|
281
|
+
int stl_write_object(stl_object *obj, int fd) {
|
282
|
+
int rc = -1;
|
283
|
+
|
284
|
+
rc = write(fd, obj->header, sizeof(obj->header));
|
285
|
+
check(rc == sizeof(obj->header), "Failed to write object header");
|
286
|
+
|
287
|
+
rc = write(fd, &obj->facet_count, sizeof(obj->facet_count));
|
288
|
+
check(rc == sizeof(obj->facet_count), "Failed to write face count");
|
289
|
+
|
290
|
+
for(uint32_t i = 0; i < obj->facet_count; i++) {
|
291
|
+
rc = stl_write_facet(&obj->facets[i], fd);
|
292
|
+
check(rc == 0, "Failed to write facet %d", i);
|
293
|
+
}
|
294
|
+
|
295
|
+
return 0;
|
296
|
+
error:
|
297
|
+
return -1;
|
298
|
+
}
|
299
|
+
|
300
|
+
int stl_write_facet(stl_facet *facet, int fd) {
|
301
|
+
// Pre-computed size since sizeof(struct) falls to padding problems for IO
|
302
|
+
const size_t facet_size = sizeof(facet->normal) + sizeof(facet->vertices) + sizeof(facet->attr);
|
303
|
+
int rc = -1;
|
304
|
+
|
305
|
+
rc = write(fd, facet, facet_size);
|
306
|
+
check(rc == facet_size, "Failed to write facet struct");
|
307
|
+
|
308
|
+
return 0;
|
309
|
+
error:
|
310
|
+
return -1;
|
311
|
+
}
|
312
|
+
|
313
|
+
stl_reader* stl_detect_reader(char *path) {
|
314
|
+
stl_reader* reader = stl_read_text_object;
|
315
|
+
static const int upto = 100;
|
316
|
+
char c = '\0';
|
317
|
+
int rc = -1;
|
318
|
+
int fd = open(path, O_RDONLY);
|
319
|
+
check(fd != -1, "Failed to open %s for format detection.", path);
|
320
|
+
for(int i = 0; i < upto; i++) {
|
321
|
+
check((rc = read(fd, &c, 1)) == 1, "Failed to read byte %d for reader detection of %s", i, path);
|
322
|
+
if(!isprint(c) && !isspace(c)) {
|
323
|
+
reader = stl_read_object;
|
324
|
+
break;
|
325
|
+
}
|
326
|
+
}
|
327
|
+
|
328
|
+
if(fd != -1) close(fd);
|
329
|
+
return reader;
|
330
|
+
error:
|
331
|
+
if(fd != -1) close(fd);
|
332
|
+
return NULL;
|
333
|
+
}
|
data/src/stl.h
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
#include <unistd.h>
|
2
|
+
#include <stdint.h>
|
3
|
+
#include <math.h>
|
4
|
+
|
5
|
+
#include "klist.h"
|
6
|
+
#include "vector.h"
|
7
|
+
|
8
|
+
#ifndef __STL_H
|
9
|
+
#define __STL_H
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
// File format structs
|
14
|
+
typedef struct s_stl_facet {
|
15
|
+
float3 normal;
|
16
|
+
float3 vertices[3];
|
17
|
+
uint16_t attr;
|
18
|
+
} stl_facet;
|
19
|
+
|
20
|
+
typedef struct s_stl_object {
|
21
|
+
char header[80];
|
22
|
+
uint32_t facet_count;
|
23
|
+
stl_facet *facets;
|
24
|
+
} stl_object;
|
25
|
+
|
26
|
+
|
27
|
+
// Alloc/Free
|
28
|
+
void stl_free(stl_object *obj);
|
29
|
+
stl_object *stl_alloc(char *header, uint32_t n_facets);
|
30
|
+
|
31
|
+
// Operations
|
32
|
+
void stl_facet_update_normal(stl_facet *facet);
|
33
|
+
|
34
|
+
// Signatures of file readers
|
35
|
+
typedef stl_object* (stl_reader)(int fd);
|
36
|
+
|
37
|
+
// File reader factory and dispatcher
|
38
|
+
stl_reader* stl_detect_reader(char *path);
|
39
|
+
stl_object *stl_read_file(char *path, int recompute_normals);
|
40
|
+
|
41
|
+
// Binary file readers
|
42
|
+
stl_facet *stl_read_facet(int fd);
|
43
|
+
stl_object *stl_read_object(int fd);
|
44
|
+
|
45
|
+
// Text file readers
|
46
|
+
stl_facet *stl_read_text_facet(const char *declaration, int fd);
|
47
|
+
stl_object *stl_read_text_object(int fd);
|
48
|
+
|
49
|
+
// Binary file writers
|
50
|
+
int stl_write_file(stl_object *obj, char *path);
|
51
|
+
int stl_write_object(stl_object *obj, int fd);
|
52
|
+
int stl_write_facet(stl_facet *facet, int fd);
|
53
|
+
|
54
|
+
// Composite wrappers
|
55
|
+
#define mp_stl_free(x) stl_free(kl_val(x))
|
56
|
+
KLIST_INIT(stl_object, stl_object*, mp_stl_free)
|
57
|
+
#define mp_std_free(x) free(kl_val(x))
|
58
|
+
KLIST_INIT(stl_facet, stl_facet*, mp_std_free)
|
59
|
+
|
60
|
+
#endif
|
data/src/vector.c
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
#include "vector.h"
|
2
|
+
|
3
|
+
float3 *clone_f3(float3 f) {
|
4
|
+
float3 *clone = malloc(sizeof(float3));
|
5
|
+
if(clone) {
|
6
|
+
(*clone)[0] = f[0];
|
7
|
+
(*clone)[1] = f[1];
|
8
|
+
(*clone)[2] = f[2];
|
9
|
+
}
|
10
|
+
return clone;
|
11
|
+
}
|
12
|
+
|
13
|
+
float3 *f3_normalize(float3 *v) {
|
14
|
+
float mag = sqrt((*v)[0] * (*v)[0] +
|
15
|
+
(*v)[1] * (*v)[1] +
|
16
|
+
(*v)[2] * (*v)[2]);
|
17
|
+
(*v)[0] /= mag;
|
18
|
+
(*v)[1] /= mag;
|
19
|
+
(*v)[2] /= mag;
|
20
|
+
return v;
|
21
|
+
}
|
22
|
+
|
23
|
+
float3 *f3_scale(float3 *v, float c) {
|
24
|
+
(*v)[0] *= c;
|
25
|
+
(*v)[1] *= c;
|
26
|
+
(*v)[2] *= c;
|
27
|
+
return v;
|
28
|
+
}
|
29
|
+
|
30
|
+
float f3_dot(float3 v1, float3 v2) {
|
31
|
+
return (v1[0] * v2[0] +
|
32
|
+
v1[1] * v2[1] +
|
33
|
+
v1[2] * v2[2]);
|
34
|
+
}
|
35
|
+
|
36
|
+
float3 *f3_cross(float3 *result, float3 v1, float3 v2) {
|
37
|
+
(*result)[0] = v1[1]*v2[2] - v1[2]*v2[1];
|
38
|
+
(*result)[1] = v1[2]*v2[0] - v1[0]*v2[2];
|
39
|
+
(*result)[2] = v1[0]*v2[1] - v1[1]*v2[0];
|
40
|
+
return result;
|
41
|
+
}
|
42
|
+
|
43
|
+
float3 *f3_sub(float3 *result, float3 v1, float3 v2) {
|
44
|
+
(*result)[0] = v1[0] - v2[0];
|
45
|
+
(*result)[1] = v1[1] - v2[1];
|
46
|
+
(*result)[2] = v1[2] - v2[2];
|
47
|
+
return result;
|
48
|
+
}
|
49
|
+
|
50
|
+
float3 *f3_interpolate(float3 *result, float3 start, float3 v, float alpha) {
|
51
|
+
for(int i = 0; i < 3; i++) {
|
52
|
+
(*result)[i] += (v[i] - start[i]) * alpha;
|
53
|
+
}
|
54
|
+
return result;
|
55
|
+
}
|