7 static void destroy_cell(struct frac_cell *cell);
8 static int build_cell(struct fracture *frac, int cellidx);
10 int frac_init(struct fracture *frac)
14 if(!(frac->cells = dynarr_alloc(0, sizeof *frac->cells))) {
20 void frac_destroy(struct fracture *frac)
27 num = dynarr_size(frac->cells);
28 for(i=0; i<num; i++) {
29 destroy_cell(frac->cells + i);
31 dynarr_free(frac->cells);
35 static int init_cell(struct frac_cell *cell)
37 memset(cell, 0, sizeof *cell);
38 if(!(cell->mesh = cmesh_alloc())) {
44 static void destroy_cell(struct frac_cell *cell)
48 cmesh_free(cell->mesh);
51 void frac_mesh(struct fracture *frac, const struct cmesh *m)
53 frac->mesh = (struct cmesh*)m;
56 int frac_point(struct fracture *frac, float x, float y, float z)
58 struct frac_cell cell;
59 struct frac_cell *tmp;
62 cgm_vcons(&cell.pt, x, y, z);
63 if(!(tmp = dynarr_push(frac->cells, &cell))) {
71 int frac_num_cells(struct fracture *frac)
73 return dynarr_size(frac->cells);
76 /* --- step 1: generate a bunch of points (or let the user add them manually) */
78 int frac_gen_points(struct fracture *frac, int num)
82 cgm_vec3 bbmin, bbmax, delta;
84 if(!frac || !frac->mesh) return -1;
85 if(!cmesh_poly_count(frac->mesh)) {
89 cmesh_aabbox(frac->mesh, &bbmin, &bbmax);
91 cgm_vsub(&delta, &bbmin);
93 for(i=0; i<num; i++) {
94 x = (float)rand() / RAND_MAX * delta.x + bbmin.x;
95 y = (float)rand() / RAND_MAX * delta.y + bbmin.y;
96 z = (float)rand() / RAND_MAX * delta.z + bbmin.z;
98 if(frac_point(frac, x, y, z) == -1) {
106 /* --- step 2: construct voronoi cells bounded by planes */
108 int frac_build_cells(struct fracture *frac)
112 for(i=0; i<dynarr_size(frac->cells); i++) {
113 if(build_cell(frac, i) == -1) {
121 static int build_cell(struct fracture *frac, int cellidx)
123 int i, j, num, clipres;
126 struct frac_cell *cell = frac->cells + cellidx;
127 struct poly poly, clipped, *polys, *pptr;
130 if(!(polys = dynarr_alloc(0, sizeof *polys))) {
134 cmesh_bsphere(frac->mesh, 0, &bsize);
137 num = dynarr_size(frac->cells);
138 for(i=0; i<num; i++) {
139 if(i == cellidx) continue;
140 midplane(&plane, &cell->pt, &frac->cells[i].pt);
141 plane_poly(&plane, &poly, bsize);
142 if(!(pptr = dynarr_push(polys, &poly))) {
148 num = dynarr_size(polys);
149 valid_planes = alloca(num * sizeof *valid_planes);
150 memset(valid_planes, 0xff, num * sizeof *valid_planes);
152 /* clip all planes against each other to end up with a convex cell */
153 cell->num_polys = num;
154 for(i=0; i<num; i++) {
155 for(j=0; j<num; j++) {
156 if(i == j || !valid_planes[j]) {
160 /* clip plane polygon i with plane j */
161 poly_plane(polys + j, &plane);
163 if((clipres = clip_poly(&clipped, polys + i, &plane)) < 0) {
164 /* completely clipped, mark it for removal */
167 destroy_poly(&clipped);
170 destroy_poly(polys + i);
175 if(!(cell->polys = malloc(cell->num_polys * sizeof *cell->polys))) {
179 for(i=0; i<num; i++) {
180 if(valid_planes[i]) {
181 assert(pptr - cell->polys < cell->num_polys);
184 destroy_poly(polys + i);
191 static int mesh_poly(struct poly *poly, const struct cmesh *mesh, int faceidx)
193 int i, vsz, nsz, uvsz;
194 struct vertex vert, *tmpvert;
195 const float *varr, *narr, *uvarr;
198 if(init_poly(poly) == -1) {
202 varr = cmesh_attrib_ro(mesh, CMESH_ATTR_VERTEX);
203 narr = cmesh_attrib_ro(mesh, CMESH_ATTR_NORMAL);
204 uvarr = cmesh_attrib_ro(mesh, CMESH_ATTR_TEXCOORD);
205 vsz = cmesh_attrib_nelem(mesh, CMESH_ATTR_VERTEX);
206 nsz = cmesh_attrib_nelem(mesh, CMESH_ATTR_NORMAL);
207 uvsz = cmesh_attrib_nelem(mesh, CMESH_ATTR_TEXCOORD);
210 if(cmesh_indexed(mesh)) {
211 vidx = cmesh_index_ro(mesh)[faceidx * 3 + i];
213 vidx = faceidx * 3 + i;
215 vert.pos.x = varr[vidx * vsz];
216 vert.pos.y = varr[vidx * vsz + 1];
217 vert.pos.z = varr[vidx * vsz + 2];
218 vert.norm.x = narr[vidx * nsz];
219 vert.norm.y = narr[vidx * nsz + 1];
220 vert.norm.z = narr[vidx * nsz + 2];
221 vert.uv.x = uvarr[vidx * uvsz];
222 vert.uv.y = uvarr[vidx * uvsz + 1];
224 if(!(tmpvert = dynarr_push(poly->verts, &vert))) {
228 poly->verts = tmpvert;
233 #define ADD_VERTEX(mesh, vert) \
235 cmesh_normal(mesh, (vert)->norm.x, (vert)->norm.y, (vert)->norm.z); \
236 cmesh_texcoord(mesh, (vert)->uv.x, (vert)->uv.y, 0); \
237 if(cmesh_vertex(mesh, (vert)->pos.x, (vert)->pos.y, (vert)->pos.z) == -1) { \
238 fprintf(stderr, "SKATA\n"); \
243 static int build_cell_shell(struct cmesh *mesh, const struct cmesh *orig,
244 struct frac_cell *cell)
246 int i, j, nfaces, clipres;
248 struct poly poly, clipped, wallclipped;
251 struct plane *cplanes;
253 /* array for marking wall polygons for deletion when they get clipped entirely */
254 delwall = alloca(cell->num_polys * sizeof *delwall);
255 memset(delwall, 0, cell->num_polys * sizeof *delwall);
257 /* array for pre-constructing the voronoi clipping planes */
258 cplanes = alloca(cell->num_polys * sizeof *cplanes);
259 for(i=0; i<cell->num_polys; i++) {
260 poly_plane(cell->polys + i, cplanes + i);
263 nfaces = cmesh_poly_count(orig);
264 for(i=0; i<nfaces; i++) {
265 if(mesh_poly(&poly, orig, i) == -1) {
270 for(j=0; j<cell->num_polys; j++) {
272 if((clipres = clip_poly(&clipped, &poly, cplanes + j)) < 0) {
273 destroy_poly(&clipped);
277 /* if the plane clipped the polygon, and the two polygons intersect
278 * within their bounds, also clip the cell polygon by the original
281 * TODO clipping with the polygon's plane is incorrect, and will lead
282 * to gaps in the cell walls when the surface is concave. We'll need
283 * to clip by the polygon itself, which can make the wall polygon
284 * concave, and will need to be split into multiple convex ones.
286 if(clipres == 0 && poly_poly(&poly, cell->polys + j)) {
287 poly_plane(&poly, &plane);
288 init_poly(&wallclipped);
290 if((clipres = clip_poly(&wallclipped, cell->polys + j, &plane)) < 0) {
291 /* mark for deletion */
293 } else if(clipres == 0) {
294 destroy_poly(cell->polys + j);
295 cell->polys[j] = wallclipped;
297 destroy_poly(&wallclipped);
305 if(j < cell->num_polys) {
309 vert = poly.verts + 1;
310 for(j=0; j<dynarr_size(poly.verts)-2; j++) {
311 ADD_VERTEX(mesh, poly.verts);
312 ADD_VERTEX(mesh, vert); vert++;
313 ADD_VERTEX(mesh, vert);
318 /* remove deleted wall polygons */
319 for(i=0; i<cell->num_polys; i++) {
321 struct poly tmp = cell->polys[i];
322 cell->polys[i] = cell->polys[--cell->num_polys];
327 /* add wall polygons to the mesh */
328 for(i=0; i<cell->num_polys; i++) {
329 vert = cell->polys[i].verts + 1;
330 for(j=0; j<dynarr_size(cell->polys[i].verts)-2; j++) {
331 ADD_VERTEX(mesh, cell->polys[i].verts);
332 ADD_VERTEX(mesh, vert); vert++;
333 ADD_VERTEX(mesh, vert);
340 int frac_build_shell(struct fracture *frac)
344 num_cells = dynarr_size(frac->cells);
345 for(i=0; i<num_cells; i++) {
346 if(build_cell_shell(frac->cells[i].mesh, frac->mesh, frac->cells + i) == -1) {
354 int frac_build_walls(struct fracture *frac)
359 int frac_build(struct fracture *frac)
361 if(frac_build_cells(frac) == -1) {
364 if(frac_build_shell(frac) == -1) {
367 if(frac_build_walls(frac) == -1) {