optimized the metaballs slightly 3fps -> 5fps and fixed the zsorting bug
authorJohn Tsiombikas <nuclear@member.fsf.org>
Thu, 1 Feb 2018 01:01:22 +0000 (03:01 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Thu, 1 Feb 2018 01:01:22 +0000 (03:01 +0200)
libs/imago/GNUmakefile
src/metaball.c
src/metasurf.c
src/metasurf.h

index beba77c..c9154c2 100644 (file)
@@ -12,4 +12,4 @@ $(alib): $(obj)
 
 .PHONY: clean
 clean:
-       rm -f $(obj) $(bin)
+       rm -f $(obj) $(alib)
index 052607d..ac0563c 100644 (file)
@@ -9,7 +9,6 @@
 #include "gfxutil.h"
 #include "util.h"
 #include "metasurf.h"
-#include "dynarr.h"
 
 struct mesh {
        int prim;
@@ -31,8 +30,6 @@ static void draw_mesh(struct mesh *mesh);
 static void zsort(struct mesh *m);
 
 static void calc_voxel_field(void);
-static float eval(struct metasurface *ms, float x, float y, float z);
-static void emit_vertex(struct metasurface *ms, float x, float y, float z);
 
 static struct screen scr = {
        "metaballs",
@@ -52,8 +49,6 @@ static struct metasurface *msurf;
 #define VOL_SCALE      10.0f
 #define VOX_DIST       (VOL_SCALE / VOL_SZ)
 #define VOL_HALF_SCALE (VOL_SCALE * 0.5f)
-static float *volume;
-#define VOXEL(x, y, z) (volume[(z) * VOL_SZ * VOL_SZ + (y) * VOL_SZ + (x)])
 
 #define NUM_MBALLS     3
 static struct metaball mball[NUM_MBALLS];
@@ -67,11 +62,6 @@ struct screen *metaballs_screen(void)
 
 static int init(void)
 {
-       if(!(volume = malloc(VOL_SZ * VOL_SZ * VOL_SZ * sizeof *volume))) {
-               fprintf(stderr, "failed to allocate %dx%dx%d voxel field\n", VOL_SZ, VOL_SZ, VOL_SZ);
-               return -1;
-       }
-
        mball[0].energy = 1.2;
        mball[1].energy = 0.8;
        mball[2].energy = 1.0;
@@ -81,11 +71,10 @@ static int init(void)
                return -1;
        }
        msurf_set_resolution(msurf, VOL_SZ, VOL_SZ, VOL_SZ);
-       msurf_set_bounds(msurf, 0, 0, 0, VOL_SCALE, VOL_SCALE, VOL_SCALE);
-       msurf_eval_func(msurf, eval);
+       msurf_set_bounds(msurf, -VOL_HALF_SCALE, -VOL_HALF_SCALE, -VOL_HALF_SCALE,
+                       VOL_HALF_SCALE, VOL_HALF_SCALE, VOL_HALF_SCALE);
        msurf_set_threshold(msurf, 1.7);
        msurf_set_inside(msurf, MSURF_GREATER);
-       msurf_vertex_func(msurf, emit_vertex);
 
        mmesh.prim = G3D_TRIANGLES;
        mmesh.varr = 0;
@@ -97,7 +86,7 @@ static int init(void)
 
 static void destroy(void)
 {
-       dynarr_free(mmesh.varr);
+       msurf_free(msurf);
 }
 
 static void start(long trans_time)
@@ -162,11 +151,10 @@ static void update(void)
        }
 
        calc_voxel_field();
-
-       dynarr_free(mmesh.varr);
-       mmesh.vcount = 0;
-       mmesh.varr = dynarr_alloc(0, sizeof *mmesh.varr);
        msurf_polygonize(msurf);
+
+       mmesh.vcount = msurf_vertex_count(msurf);
+       mmesh.varr = msurf_vertices(msurf);
 }
 
 static void draw(void)
@@ -208,19 +196,16 @@ static struct {
 
 static int zsort_cmp(const void *aptr, const void *bptr)
 {
-       const int16_t *a = (const int16_t*)aptr;
-       const int16_t *b = (const int16_t*)bptr;
-
        const float *m = zsort_cls.xform;
 
-       const struct g3d_vertex *va = zsort_cls.varr + a[0];
-       const struct g3d_vertex *vb = zsort_cls.varr + b[0];
+       const struct g3d_vertex *va = (const struct g3d_vertex*)aptr;
+       const struct g3d_vertex *vb = (const struct g3d_vertex*)bptr;
 
        float za = m[2] * va->x + m[6] * va->y + m[10] * va->z + m[14];
        float zb = m[2] * vb->x + m[6] * vb->y + m[10] * vb->z + m[14];
 
-       va = zsort_cls.varr + a[2];
-       vb = zsort_cls.varr + b[2];
+       ++va;
+       ++vb;
 
        za += m[2] * va->x + m[6] * va->y + m[10] * va->z + m[14];
        zb += m[2] * vb->x + m[6] * vb->y + m[10] * vb->z + m[14];
@@ -230,27 +215,32 @@ static int zsort_cmp(const void *aptr, const void *bptr)
 
 static void zsort(struct mesh *m)
 {
-       int nfaces = m->icount / m->prim;
+       int nfaces = m->vcount / m->prim;
 
        zsort_cls.varr = m->varr;
        zsort_cls.xform = g3d_get_matrix(G3D_MODELVIEW, 0);
 
-       qsort(m->iarr, nfaces, m->prim * sizeof *m->iarr, zsort_cmp);
+       qsort(m->varr, nfaces, m->prim * sizeof *m->varr, zsort_cmp);
 }
 
 static void calc_voxel_field(void)
 {
        int i, j, k, b;
-       float *voxptr = volume;
+       float *voxptr;
+
+       if(!(voxptr = msurf_voxels(msurf))) {
+               fprintf(stderr, "failed to allocate voxel field\n");
+               abort();
+       }
 
        for(i=0; i<VOL_SZ; i++) {
-               float z = VOL_SCALE * ((float)i / (float)VOL_SZ - 0.5);
+               float z = -VOL_HALF_SCALE + i * VOX_DIST;
 
                for(j=0; j<VOL_SZ; j++) {
-                       float y = VOL_SCALE * ((float)j / (float)VOL_SZ - 0.5);
+                       float y = -VOL_HALF_SCALE + j * VOX_DIST;
 
                        for(k=0; k<VOL_SZ; k++) {
-                               float x = VOL_SCALE * ((float)k / (float)VOL_SZ - 0.5);
+                               float x = -VOL_HALF_SCALE + k * VOX_DIST;
 
                                float val = 0.0f;
                                for(b=0; b<NUM_MBALLS; b++) {
@@ -269,46 +259,3 @@ static void calc_voxel_field(void)
        }
        ++dbg;
 }
-
-static float eval(struct metasurface *ms, float x, float y, float z)
-{
-       int xidx = cround64(VOL_SZ * x / VOL_SCALE);
-       int yidx = cround64(VOL_SZ * y / VOL_SCALE);
-       int zidx = cround64(VOL_SZ * z / VOL_SCALE);
-
-       assert(xidx >= 0 && xidx < VOL_SZ);
-       assert(yidx >= 0 && yidx < VOL_SZ);
-       assert(zidx >= 0 && zidx < VOL_SZ);
-
-       return VOXEL(xidx, yidx, zidx);
-}
-
-static void emit_vertex(struct metasurface *ms, float x, float y, float z)
-{
-       struct g3d_vertex v;
-       float val, len;
-
-       v.x = x - VOL_HALF_SCALE;
-       v.y = y - VOL_HALF_SCALE;
-       v.z = z - VOL_HALF_SCALE;
-       v.r = cround64(255.0 * x / VOL_SCALE);
-       v.g = cround64(255.0 * y / VOL_SCALE);
-       v.b = cround64(255.0 * z / VOL_SCALE);
-
-       val = eval(ms, x, y, z);
-       v.nx = eval(ms, x + VOX_DIST, y, z) - val;
-       v.ny = eval(ms, x, y + VOX_DIST, z) - val;
-       v.nz = eval(ms, x, y, z - VOX_DIST) - val;
-
-       if((len = sqrt(v.nx * v.nx + v.ny * v.ny + v.nz * v.nz)) != 0.0f) {
-               v.nx /= len;
-               v.ny /= len;
-               v.nz /= len;
-       }
-
-       mmesh.varr = dynarr_push(mmesh.varr, &v);
-       assert(mmesh.varr);
-       ++mmesh.vcount;
-}
-
-
index 85aae1c..d7f1c86 100644 (file)
@@ -1,59 +1,27 @@
-/*
-metasurf - a library for implicit surface polygonization
-Copyright (C) 2011-2015  John Tsiombikas <nuclear@member.fsf.org>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
 #include <stdio.h>
 #include <stdlib.h>
+#include <math.h>
 #include "metasurf.h"
 #include "mcubes.h"
 
-#undef USE_MTETRA
-#define USE_MCUBES
-
-#if (defined(USE_MTETRA) && defined(USE_MCUBES)) || (!defined(USE_MTETRA) && !defined(USE_MCUBES))
-#error "pick either USE_MTETRA or USE_MCUBES, not both..."
-#endif
-
 typedef float vec3[3];
 
 struct metasurface {
        vec3 min, max;
-       int res[3];
+       int res[3], newres[3];
        float thres;
 
-       msurf_eval_func_t eval;
-       msurf_vertex_func_t vertex;
-       msurf_normal_func_t normal;
-       void *udata;
-
        float dx, dy, dz;
-       int flip;
+       unsigned int flags;
+
+       float *voxels;
 
-       vec3 vbuf[3];
-       int nverts;
+       int varr_size, varr_alloc_size;
+       struct g3d_vertex *varr;
 };
 
 static int msurf_init(struct metasurface *ms);
-static void process_cell(struct metasurface *ms, vec3 pos, vec3 sz);
-#ifdef USE_MTETRA
-static void process_tetra(struct metasurface *ms, int *idx, vec3 *pos, float *val);
-#endif
-#ifdef USE_MCUBES
-static void process_cube(struct metasurface *ms, vec3 *pos, float *val);
-#endif
+static void process_cell(struct metasurface *ms, int xcell, int ycell, int zcell, vec3 pos, vec3 sz);
 
 
 struct metasurface *msurf_create(void)
@@ -71,46 +39,55 @@ struct metasurface *msurf_create(void)
 
 void msurf_free(struct metasurface *ms)
 {
-       free(ms);
+       if(ms) {
+               free(ms->voxels);
+               free(ms->varr);
+               free(ms);
+       }
 }
 
 static int msurf_init(struct metasurface *ms)
 {
+       ms->voxels = 0;
        ms->thres = 0.0;
-       ms->eval = 0;
-       ms->vertex = 0;
-       ms->normal = 0;
-       ms->udata = 0;
        ms->min[0] = ms->min[1] = ms->min[2] = -1.0;
        ms->max[0] = ms->max[1] = ms->max[2] = 1.0;
-       ms->res[0] = ms->res[1] = ms->res[2] = 40;
-       ms->nverts = 0;
+       ms->res[0] = ms->res[1] = ms->res[2] = 0;
+       ms->newres[0] = ms->newres[1] = ms->newres[2] = 40;
+
+       ms->varr_alloc_size = ms->varr_size = 0;
+       ms->varr = 0;
 
        ms->dx = ms->dy = ms->dz = 0.001;
-       ms->flip = 0;
+       ms->flags = 0;
 
        return 0;
 }
 
-void msurf_set_user_data(struct metasurface *ms, void *udata)
+void msurf_enable(struct metasurface *ms, unsigned int opt)
 {
-       ms->udata = udata;
+       ms->flags |= opt;
 }
 
-void *msurf_get_user_data(struct metasurface *ms)
+void msurf_disable(struct metasurface *ms, unsigned int opt)
 {
-       return ms->udata;
+       ms->flags &= ~opt;
+}
+
+int msurf_is_enabled(struct metasurface *ms, unsigned int opt)
+{
+       return ms->flags & opt;
 }
 
 void msurf_set_inside(struct metasurface *ms, int inside)
 {
        switch(inside) {
        case MSURF_GREATER:
-               ms->flip = 0;
+               msurf_enable(ms, MSURF_FLIP);
                break;
 
        case MSURF_LESS:
-               ms->flip = 1;
+               msurf_disable(ms, MSURF_FLIP);
                break;
 
        default:
@@ -120,22 +97,7 @@ void msurf_set_inside(struct metasurface *ms, int inside)
 
 int msurf_get_inside(struct metasurface *ms)
 {
-       return ms->flip ? MSURF_LESS : MSURF_GREATER;
-}
-
-void msurf_eval_func(struct metasurface *ms, msurf_eval_func_t func)
-{
-       ms->eval = func;
-}
-
-void msurf_vertex_func(struct metasurface *ms, msurf_vertex_func_t func)
-{
-       ms->vertex = func;
-}
-
-void msurf_normal_func(struct metasurface *ms, msurf_normal_func_t func)
-{
-       ms->normal = func;
+       return msurf_is_enabled(ms, MSURF_FLIP) ? MSURF_LESS : MSURF_GREATER;
 }
 
 void msurf_set_bounds(struct metasurface *ms, float xmin, float ymin, float zmin, float xmax, float ymax, float zmax)
@@ -160,9 +122,9 @@ void msurf_get_bounds(struct metasurface *ms, float *xmin, float *ymin, float *z
 
 void msurf_set_resolution(struct metasurface *ms, int xres, int yres, int zres)
 {
-       ms->res[0] = xres;
-       ms->res[1] = yres;
-       ms->res[2] = zres;
+       ms->newres[0] = xres;
+       ms->newres[1] = yres;
+       ms->newres[2] = zres;
 }
 
 void msurf_get_resolution(struct metasurface *ms, int *xres, int *yres, int *zres)
@@ -183,112 +145,145 @@ float msurf_get_threshold(struct metasurface *ms)
 }
 
 
+float *msurf_voxels(struct metasurface *ms)
+{
+       if(ms->res[0] != ms->newres[0] || ms->res[1] != ms->newres[1] || ms->res[2] != ms->newres[2]) {
+               int count;
+               ms->res[0] = ms->newres[0];
+               ms->res[1] = ms->newres[1];
+               ms->res[2] = ms->newres[2];
+               count = ms->res[0] * ms->res[1] * ms->res[2];
+               free(ms->voxels);
+               if(!(ms->voxels = malloc(count * sizeof *ms->voxels))) {
+                       return 0;
+               }
+       }
+       return ms->voxels;
+}
+
+float *msurf_slice(struct metasurface *ms, int idx)
+{
+       float *vox = msurf_voxels(ms);
+       if(!vox) return 0;
+
+       return vox + ms->res[0] * ms->res[1] * idx;
+}
+
 int msurf_polygonize(struct metasurface *ms)
 {
        int i, j, k;
        vec3 pos, delta;
 
-       if(!ms->eval || !ms->vertex) {
-               fprintf(stderr, "you need to set eval and vertex callbacks before calling msurf_polygonize\n");
-               return -1;
-       }
+       if(!ms->voxels) return -1;
+
+       ms->varr_size = 0;
 
        for(i=0; i<3; i++) {
                delta[i] = (ms->max[i] - ms->min[i]) / (float)ms->res[i];
        }
 
-       pos[0] = ms->min[0];
        for(i=0; i<ms->res[0] - 1; i++) {
-               pos[1] = ms->min[1];
                for(j=0; j<ms->res[1] - 1; j++) {
-
-                       pos[2] = ms->min[2];
                        for(k=0; k<ms->res[2] - 1; k++) {
 
-                               process_cell(ms, pos, delta);
+                               pos[0] = ms->min[0] + i * delta[0];
+                               pos[1] = ms->min[1] + j * delta[1];
+                               pos[2] = ms->min[2] + k * delta[2];
 
-                               pos[2] += delta[2];
+                               process_cell(ms, i, j, k, pos, delta);
                        }
-                       pos[1] += delta[1];
                }
-               pos[0] += delta[0];
        }
        return 0;
 }
 
-
-static void process_cell(struct metasurface *ms, vec3 pos, vec3 sz)
+int msurf_vertex_count(struct metasurface *ms)
 {
-       int i;
-       vec3 p[8];
-       float val[8];
-
-#ifdef USE_MTETRA
-       static int tetra[][4] = {
-               {0, 2, 3, 7},
-               {0, 2, 6, 7},
-               {0, 4, 6, 7},
-               {0, 6, 1, 2},
-               {0, 6, 1, 4},
-               {5, 6, 1, 4}
-       };
-#endif
-
-       static const float offs[][3] = {
-               {0.0f, 0.0f, 0.0f},
-               {1.0f, 0.0f, 0.0f},
-               {1.0f, 1.0f, 0.0f},
-               {0.0f, 1.0f, 0.0f},
-               {0.0f, 0.0f, 1.0f},
-               {1.0f, 0.0f, 1.0f},
-               {1.0f, 1.0f, 1.0f},
-               {0.0f, 1.0f, 1.0f}
-       };
-
-       for(i=0; i<8; i++) {
-               p[i][0] = pos[0] + sz[0] * offs[i][2];
-               p[i][1] = pos[1] + sz[1] * offs[i][1];
-               p[i][2] = pos[2] + sz[2] * offs[i][0];
-
-               val[i] = ms->eval(ms, p[i][0], p[i][1], p[i][2]);
-       }
-
-#ifdef USE_MTETRA
-       for(i=0; i<6; i++) {
-               process_tetra(ms, tetra[i], p, val);
-       }
-#endif
-#ifdef USE_MCUBES
-       process_cube(ms, p, val);
-#endif
+       return ms->varr_size;
 }
 
-
-/* ---- marching cubes implementation ---- */
-#ifdef USE_MCUBES
+struct g3d_vertex *msurf_vertices(struct metasurface *ms)
+{
+       return ms->varr;
+}
 
 static unsigned int mc_bitcode(float *val, float thres);
 
-static void process_cube(struct metasurface *ms, vec3 *pos, float *val)
+static void process_cell(struct metasurface *ms, int xcell, int ycell, int zcell, vec3 cellpos, vec3 cellsz)
 {
+       int i, j, slice_size;
+       vec3 pos[8];
+       float dfdx[8], dfdy[8], dfdz[8];
+       vec3 vert[12], norm[12];
+       float val[8];
+       float *cellptr;
+       unsigned int code;
+
+       static const int offs[][3] = {
+               {0, 0, 0},
+               {1, 0, 0},
+               {1, 1, 0},
+               {0, 1, 0},
+               {0, 0, 1},
+               {1, 0, 1},
+               {1, 1, 1},
+               {0, 1, 1}
+       };
+
        static const int pidx[12][2] = {
                {0, 1}, {1, 2}, {2, 3}, {3, 0}, {4, 5}, {5, 6},
                {6, 7}, {7, 4}, {0, 4}, {1, 5}, {2, 6}, {3, 7}
        };
-       int i, j;
-       vec3 vert[12];
-       unsigned int code = mc_bitcode(val, ms->thres);
 
-       if(ms->flip) {
-               code = ~code & 0xff;
+       slice_size = ms->res[0] * ms->res[1];
+       cellptr = ms->voxels + slice_size * zcell + ms->res[0] * ycell + xcell;
+
+#define GRIDOFFS(x, y, z)      ((z) * slice_size + (y) * ms->res[0] + (x))
+
+       for(i=0; i<8; i++) {
+               val[i] = cellptr[GRIDOFFS(offs[i][0], offs[i][1], offs[i][2])];
        }
 
+       code = mc_bitcode(val, ms->thres);
+       if(ms->flags & MSURF_FLIP) {
+               code = ~code & 0xff;
+       }
        if(mc_edge_table[code] == 0) {
                return;
        }
 
+       /* calculate normals at the 8 corners */
+       for(i=0; i<8; i++) {
+               float *ptr = cellptr + GRIDOFFS(offs[i][0], offs[i][1], offs[i][2]);
+
+               if(xcell < ms->res[0] - 1) {
+                       dfdx[i] = ptr[GRIDOFFS(1, 0, 0)] - *ptr;
+               } else {
+                       dfdx[i] = *ptr - ptr[GRIDOFFS(-1, 0, 0)];
+               }
+               if(ycell < ms->res[1] - 1) {
+                       dfdy[i] = ptr[GRIDOFFS(0, 1, 0)] - *ptr;
+               } else {
+                       dfdy[i] = *ptr - ptr[GRIDOFFS(0, -1, 0)];
+               }
+               if(zcell < ms->res[2] - 1) {
+                       dfdz[i] = ptr[GRIDOFFS(0, 0, 1)] - *ptr;
+               } else {
+                       dfdz[i] = *ptr - ptr[GRIDOFFS(0, 0, -1)];
+               }
+       }
+
+       /* calculate the world-space position of each corner */
+       for(i=0; i<8; i++) {
+               pos[i][0] = cellpos[0] + cellsz[0] * offs[i][0];
+               pos[i][1] = cellpos[1] + cellsz[1] * offs[i][1];
+               pos[i][2] = cellpos[2] + cellsz[2] * offs[i][2];
+       }
+
+       /* generate up to a max of 12 vertices per cube. interpolate positions and normals for each one */
        for(i=0; i<12; i++) {
                if(mc_edge_table[code] & (1 << i)) {
+                       float nx, ny, nz;
                        int p0 = pidx[i][0];
                        int p1 = pidx[i][1];
 
@@ -296,29 +291,61 @@ static void process_cube(struct metasurface *ms, vec3 *pos, float *val)
                        vert[i][0] = pos[p0][0] + (pos[p1][0] - pos[p0][0]) * t;
                        vert[i][1] = pos[p0][1] + (pos[p1][1] - pos[p0][1]) * t;
                        vert[i][2] = pos[p0][2] + (pos[p1][2] - pos[p0][2]) * t;
+
+                       nx = dfdx[p0] + (dfdx[p1] - dfdx[p0]) * t;
+                       ny = dfdy[p0] + (dfdy[p1] - dfdy[p0]) * t;
+                       nz = dfdz[p0] + (dfdz[p1] - dfdz[p0]) * t;
+
+                       if(ms->flags & MSURF_FLIP) {
+                               nx = -nx;
+                               ny = -ny;
+                               nz = -nz;
+                       }
+
+                       if(ms->flags & MSURF_NORMALIZE) {
+                               float len = sqrt(nx * nx + ny * ny + nz * nz);
+                               if(len != 0.0) {
+                                       float s = 1.0f / len;
+                                       nx *= s;
+                                       ny *= s;
+                                       nz *= s;
+                               }
+                       }
+
+                       norm[i][0] = nx;
+                       norm[i][1] = ny;
+                       norm[i][2] = nz;
                }
        }
 
+       /* for each triangle of the cube add the appropriate vertices to the vertex buffer */
        for(i=0; mc_tri_table[code][i] != -1; i+=3) {
                for(j=0; j<3; j++) {
-                       float *v = vert[mc_tri_table[code][i + j]];
-
-                       if(ms->normal) {
-                               float dfdx, dfdy, dfdz;
-                               dfdx = ms->eval(ms, v[0] - ms->dx, v[1], v[2]) - ms->eval(ms, v[0] + ms->dx, v[1], v[2]);
-                               dfdy = ms->eval(ms, v[0], v[1] - ms->dy, v[2]) - ms->eval(ms, v[0], v[1] + ms->dy, v[2]);
-                               dfdz = ms->eval(ms, v[0], v[1], v[2] - ms->dz) - ms->eval(ms, v[0], v[1], v[2] + ms->dz);
-
-                               if(ms->flip) {
-                                       dfdx = -dfdx;
-                                       dfdy = -dfdy;
-                                       dfdz = -dfdz;
+                       int idx = mc_tri_table[code][i + j];
+                       float *v = vert[idx];
+                       float *n = norm[idx];
+                       struct g3d_vertex *vdest;
+
+                       if(ms->varr_size >= ms->varr_alloc_size) {
+                               int newsz = ms->varr_alloc_size ? ms->varr_alloc_size * 2 : 1024;
+                               struct g3d_vertex *new_varr;
+
+                               if(!(new_varr = realloc(ms->varr, newsz * sizeof *new_varr))) {
+                                       fprintf(stderr, "msurf_polygonize: failed to grow vertex buffers to %d elements\n", newsz);
+                                       return;
                                }
-                               ms->normal(ms, dfdx, dfdy, dfdz);
+                               ms->varr = new_varr;
+                               ms->varr_alloc_size = newsz;
                        }
 
-                       /* TODO multithreadied polygon emmit */
-                       ms->vertex(ms, v[0], v[1], v[2]);
+                       vdest = ms->varr + ms->varr_size++;
+                       vdest->x = v[0];
+                       vdest->y = v[1];
+                       vdest->z = v[2];
+                       vdest->w = 1.0f;
+                       vdest->nx = n[0];
+                       vdest->ny = n[1];
+                       vdest->nz = n[2];
                }
        }
 }
@@ -334,118 +361,3 @@ static unsigned int mc_bitcode(float *val, float thres)
        }
        return res;
 }
-#endif /* USE_MCUBES */
-
-
-/* ---- marching tetrahedra implementation (incomplete) ---- */
-#ifdef USE_MTETRA
-
-static unsigned int mt_bitcode(float v0, float v1, float v2, float v3, float thres);
-static void emmit(struct metasurface *ms, float v0, float v1, vec3 p0, vec3 p1, int rev)
-
-
-#define REVBIT(x)      ((x) & 8)
-#define INV(x)         (~(x) & 0xf)
-#define EDGE(a, b)     emmit(ms, val[idx[a]], val[idx[b]], pos[idx[a]], pos[idx[b]], REVBIT(code))
-static void process_tetra(struct metasurface *ms, int *idx, vec3 *pos, float *val)
-{
-       unsigned int code = mt_bitcode(val[idx[0]], val[idx[1]], val[idx[2]], val[idx[3]], ms->thres);
-
-       switch(code) {
-       case 1:
-       case INV(1):
-               EDGE(0, 1);
-               EDGE(0, 2);
-               EDGE(0, 3);
-               break;
-
-       case 2:
-       case INV(2):
-               EDGE(1, 0);
-               EDGE(1, 3);
-               EDGE(1, 2);
-               break;
-
-       case 3:
-       case INV(3):
-               EDGE(0, 3);
-               EDGE(0, 2);
-               EDGE(1, 3);
-
-               EDGE(1, 3);
-               EDGE(1, 2);
-               EDGE(0, 2);
-               break;
-
-       case 4:
-       case INV(4):
-               EDGE(2, 0);
-               EDGE(2, 1);
-               EDGE(2, 3);
-               break;
-
-       case 5:
-       case INV(5):
-               EDGE(0, 1);
-               EDGE(2, 3);
-               EDGE(0, 3);
-
-               EDGE(0, 1);
-               EDGE(1, 2);
-               EDGE(2, 3);
-               break;
-
-       case 6:
-       case INV(6):
-               EDGE(0, 1);
-               EDGE(1, 3);
-               EDGE(2, 3);
-
-               EDGE(0, 1);
-               EDGE(0, 2);
-               EDGE(2, 3);
-               break;
-
-       case 7:
-       case INV(7):
-               EDGE(3, 0);
-               EDGE(3, 2);
-               EDGE(3, 1);
-               break;
-
-       default:
-               break;  /* cases 0 and 15 */
-       }
-}
-
-#define BIT(i) ((v##i > thres) ? (1 << i) : 0)
-static unsigned int mt_bitcode(float v0, float v1, float v2, float v3, float thres)
-{
-       return BIT(0) | BIT(1) | BIT(2) | BIT(3);
-}
-
-static void emmit(struct metasurface *ms, float v0, float v1, vec3 p0, vec3 p1, int rev)
-{
-       int i;
-       float t = (ms->thres - v0) / (v1 - v0);
-
-       vec3 p;
-       for(i=0; i<3; i++) {
-               p[i] = p0[i] + (p1[i] - p0[i]) * t;
-       }
-       ms->vertex(ms, p[0], p[1], p[2]);
-
-       /*for(i=0; i<3; i++) {
-               ms->vbuf[ms->nverts][i] = p0[i] + (p1[i] - p0[i]) * t;
-       }
-
-       if(++ms->nverts >= 3) {
-               ms->nverts = 0;
-
-               for(i=0; i<3; i++) {
-                       int idx = rev ? (2 - i) : i;
-                       ms->vertex(ms, ms->vbuf[idx][0], ms->vbuf[idx][1], ms->vbuf[idx][2]);
-               }
-       }*/
-}
-#endif /* USE_MTETRA */
index 7cdd074..81fe92a 100644 (file)
@@ -1,32 +1,15 @@
-/*
-metasurf - a library for implicit surface polygonization
-Copyright (C) 2011-2015  John Tsiombikas <nuclear@member.fsf.org>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
 #ifndef METASURF_H_
 #define METASURF_H_
 
+#include "3dgfx.h"
+
 #define MSURF_GREATER  1
 #define MSURF_LESS             0
 
-struct metasurface;
+#define MSURF_FLIP                     1
+#define MSURF_NORMALIZE                2
 
-typedef float (*msurf_eval_func_t)(struct metasurface *ms, float, float, float);
-typedef void (*msurf_vertex_func_t)(struct metasurface *ms, float, float, float);
-typedef void (*msurf_normal_func_t)(struct metasurface *ms, float, float, float);
+struct metasurface;
 
 #ifdef __cplusplus
 extern "C" {
@@ -35,22 +18,14 @@ extern "C" {
 struct metasurface *msurf_create(void);
 void msurf_free(struct metasurface *ms);
 
-void msurf_set_user_data(struct metasurface *ms, void *udata);
-void *msurf_get_user_data(struct metasurface *ms);
+void msurf_enable(struct metasurface *ms, unsigned int opt);
+void msurf_disable(struct metasurface *ms, unsigned int opt);
+int msurf_is_enabled(struct metasurface *ms, unsigned int opt);
 
 /* which is inside above or below the threshold */
 void msurf_set_inside(struct metasurface *ms, int inside);
 int msurf_get_inside(struct metasurface *ms);
 
-/* set a scalar field evaluator function */
-void msurf_eval_func(struct metasurface *ms, msurf_eval_func_t func);
-
-/* set a generated vertex callback function */
-void msurf_vertex_func(struct metasurface *ms, msurf_vertex_func_t func);
-
-/* set a generated surface normal callback function (unused yet) */
-void msurf_normal_func(struct metasurface *ms, msurf_normal_func_t func);
-
 /* set the bounding box (default: -1, -1, -1, 1, 1, 1)
  * keep this as tight as possible to avoid wasting grid resolution
  */
@@ -67,10 +42,15 @@ void msurf_get_resolution(struct metasurface *ms, int *xres, int *yres, int *zre
 void msurf_set_threshold(struct metasurface *ms, float thres);
 float msurf_get_threshold(struct metasurface *ms);
 
+/* get pointer to the scalar field */
+float *msurf_voxels(struct metasurface *ms);
+float *msurf_slice(struct metasurface *ms, int idx);
 
 /* finally call this to perform the polygonization */
 int msurf_polygonize(struct metasurface *ms);
 
+int msurf_vertex_count(struct metasurface *ms);
+struct g3d_vertex *msurf_vertices(struct metasurface *ms);
 
 #ifdef __cplusplus
 }