X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Ffrac.c;h=4263c6573e466b4879793c7b79a6c08f303fab30;hb=59a8deae3d561aa3797a6bf25c76803fe098cdf0;hp=071b5c23542fb8a7e1695b210bc0f25517c6ca62;hpb=34e07fdc87e289e9ce574df7755e5e781136c20b;p=meshfrac diff --git a/src/frac.c b/src/frac.c index 071b5c2..4263c65 100644 --- a/src/frac.c +++ b/src/frac.c @@ -1,5 +1,6 @@ #include #include +#include #include "frac.h" #include "dynarr.h" @@ -31,12 +32,20 @@ void frac_destroy(struct fracture *frac) } } +static int init_cell(struct frac_cell *cell) +{ + memset(cell, 0, sizeof *cell); + if(!(cell->mesh = cmesh_alloc())) { + return -1; + } + return 0; +} + static void destroy_cell(struct frac_cell *cell) { if(!cell) return; - + free(cell->polys); cmesh_free(cell->mesh); - dynarr_free(cell->planes); } void frac_mesh(struct fracture *frac, const struct cmesh *m) @@ -49,17 +58,10 @@ int frac_point(struct fracture *frac, float x, float y, float z) struct frac_cell cell; struct frac_cell *tmp; + init_cell(&cell); cgm_vcons(&cell.pt, x, y, z); - if(!(cell.mesh = cmesh_alloc())) { - return -1; - } - if(!(cell.planes = dynarr_alloc(0, sizeof *cell.planes))) { - cmesh_free(cell.mesh); - return -1; - } if(!(tmp = dynarr_push(frac->cells, &cell))) { - cmesh_free(cell.mesh); - dynarr_free(cell.planes); + destroy_cell(&cell); return -1; } frac->cells = tmp; @@ -113,39 +115,251 @@ int frac_build_cells(struct fracture *frac) } } - return -1; + return 0; } static int build_cell(struct fracture *frac, int cellidx) { - int i, j, num; - struct plane plane, *pptr; + int i, j, num, clipres; + int *valid_planes; + struct plane plane; struct frac_cell *cell = frac->cells + cellidx; + struct poly poly, clipped, *polys, *pptr; + float bsize; + + if(!(polys = dynarr_alloc(0, sizeof *polys))) { + return -1; + } + + cmesh_bsphere(frac->mesh, 0, &bsize); + bsize *= 8; num = dynarr_size(frac->cells); for(i=0; ipt, &frac->cells[i].pt); - if(!(pptr = dynarr_push(cell->planes, &plane))) { - return -1; + midplane(&plane, &frac->cells[i].pt, &cell->pt, frac->cell_gap); + if(plane_sdist(&plane, &cell->pt) > 0.0f) { + plane_poly(&plane, &poly, bsize); + if(!(pptr = dynarr_push(polys, &poly))) { + return -1; + } + polys = pptr; } - cell->planes = pptr; } + num = dynarr_size(polys); + valid_planes = alloca(num * sizeof *valid_planes); + memset(valid_planes, 0xff, num * sizeof *valid_planes); + /* clip all planes against each other to end up with a convex cell */ - num = dynarr_size(cell->planes); + cell->num_polys = num; for(i=0; inum_polys--; + destroy_poly(&clipped); + break; + } + destroy_poly(polys + i); + polys[i] = clipped; } } + + if(!(cell->polys = malloc(cell->num_polys * sizeof *cell->polys))) { + return -1; + } + pptr = cell->polys; + for(i=0; ipolys < cell->num_polys); + *pptr++ = polys[i]; + } else { + destroy_poly(polys + i); + } + } + dynarr_free(polys); + return 0; +} + +static int mesh_poly(struct poly *poly, const struct cmesh *mesh, int faceidx) +{ + int i, vsz, nsz, uvsz; + struct vertex *tmpvert, vert = {0}; + const float *varr, *narr, *uvarr; + unsigned int vidx; + + if(init_poly(poly) == -1) { + return -1; + } + + varr = cmesh_attrib_ro(mesh, CMESH_ATTR_VERTEX); + narr = cmesh_attrib_ro(mesh, CMESH_ATTR_NORMAL); + uvarr = cmesh_attrib_ro(mesh, CMESH_ATTR_TEXCOORD); + vsz = cmesh_attrib_nelem(mesh, CMESH_ATTR_VERTEX); + nsz = cmesh_attrib_nelem(mesh, CMESH_ATTR_NORMAL); + uvsz = cmesh_attrib_nelem(mesh, CMESH_ATTR_TEXCOORD); + + for(i=0; i<3; i++) { + if(cmesh_indexed(mesh)) { + vidx = cmesh_index_ro(mesh)[faceidx * 3 + i]; + } else { + vidx = faceidx * 3 + i; + } + vert.pos.x = varr[vidx * vsz]; + vert.pos.y = varr[vidx * vsz + 1]; + vert.pos.z = varr[vidx * vsz + 2]; + if(narr) { + vert.norm.x = narr[vidx * nsz]; + vert.norm.y = narr[vidx * nsz + 1]; + vert.norm.z = narr[vidx * nsz + 2]; + } + if(uvarr) { + vert.uv.x = uvarr[vidx * uvsz]; + vert.uv.y = uvarr[vidx * uvsz + 1]; + } + + if(!(tmpvert = dynarr_push(poly->verts, &vert))) { + destroy_poly(poly); + return -1; + } + poly->verts = tmpvert; + } + return 0; +} + +#define ADD_VERTEX(mesh, vert) \ + do { \ + cmesh_normal(mesh, (vert)->norm.x, (vert)->norm.y, (vert)->norm.z); \ + cmesh_texcoord(mesh, (vert)->uv.x, (vert)->uv.y, 0); \ + if(cmesh_vertex(mesh, (vert)->pos.x, (vert)->pos.y, (vert)->pos.z) == -1) { \ + fprintf(stderr, "SKATA\n"); \ + abort(); \ + } \ + } while(0) + +static int build_cell_shell(struct cmesh *mesh, const struct cmesh *orig, + struct frac_cell *cell) +{ + int i, j, nfaces, clipres; + struct plane plane; + struct poly poly, clipped, wallclipped; + struct vertex *vert; + int *delwall; + struct plane *cplanes; + + /* array for marking wall polygons for deletion when they get clipped entirely */ + delwall = alloca(cell->num_polys * sizeof *delwall); + memset(delwall, 0, cell->num_polys * sizeof *delwall); + + /* array for pre-constructing the voronoi clipping planes */ + cplanes = alloca(cell->num_polys * sizeof *cplanes); + for(i=0; inum_polys; i++) { + poly_plane(cell->polys + i, cplanes + i); + /* flip the plane normal towards the inside of the cell, to clip everything + * outside the cell + */ + cgm_vcons(&cplanes[i].norm, -cplanes[i].norm.x, -cplanes[i].norm.y, -cplanes[i].norm.z); + } + + nfaces = cmesh_poly_count(orig); + for(i=0; inum_polys; j++) { + init_poly(&clipped); + if((clipres = clip_poly(&clipped, &poly, cplanes + j)) < 0) { + destroy_poly(&clipped); + break; + } + + /* if the plane clipped the polygon, and the two polygons intersect + * within their bounds, also clip the cell polygon by the original + * mesh polygon. + * + * TODO clipping with the polygon's plane is incorrect, and will lead + * to gaps in the cell walls when the surface is concave. We'll need + * to clip by the polygon itself, which can make the wall polygon + * concave, and will need to be split into multiple convex ones. + */ + if(clipres == 0 && poly_poly(&poly, cell->polys + j)) { + poly_plane(&poly, &plane); + init_poly(&wallclipped); + + if((clipres = clip_poly(&wallclipped, cell->polys + j, &plane)) < 0) { + /* mark for deletion */ + delwall[j] = 1; + destroy_poly(&wallclipped); + } else if(clipres == 0) { + destroy_poly(cell->polys + j); + cell->polys[j] = wallclipped; + } else { + destroy_poly(&wallclipped); + } + } + + destroy_poly(&poly); + poly = clipped; + } + + if(j < cell->num_polys) { + continue; + } + + vert = poly.verts + 1; + for(j=0; jnum_polys; i++) { + if(delwall[i]) { + struct poly tmp = cell->polys[i]; + cell->polys[i] = cell->polys[--cell->num_polys]; + destroy_poly(&tmp); + } + } + + /* add wall polygons to the mesh */ + for(i=0; inum_polys; i++) { + vert = cell->polys[i].verts + 1; + for(j=0; jpolys[i].verts)-2; j++) { + ADD_VERTEX(mesh, cell->polys[i].verts); + ADD_VERTEX(mesh, vert); vert++; + ADD_VERTEX(mesh, vert); + } + } + + return 0; } int frac_build_shell(struct fracture *frac) { - return -1; + int i, num_cells; + + num_cells = dynarr_size(frac->cells); + for(i=0; icells[i].mesh, frac->mesh, frac->cells + i) == -1) { + return -1; + } + } + + return 0; } int frac_build_walls(struct fracture *frac)