From 134c9e63e9a7602cd2e0a3c05557edb0c9753c74 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Wed, 19 Oct 2016 04:57:36 +0300 Subject: [PATCH] metaballs effect --- src/dynarr.c | 128 ++++++++++++++++ src/dynarr.h | 38 +++++ src/mcubes.h | 294 ++++++++++++++++++++++++++++++++++++ src/metaball.c | 296 +++++++++++++++++++++++++++++++++++++ src/metasurf.c | 451 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/metasurf.h | 79 ++++++++++ src/screen.c | 4 + 7 files changed, 1290 insertions(+) create mode 100644 src/dynarr.c create mode 100644 src/dynarr.h create mode 100644 src/mcubes.h create mode 100644 src/metaball.c create mode 100644 src/metasurf.c create mode 100644 src/metasurf.h diff --git a/src/dynarr.c b/src/dynarr.c new file mode 100644 index 0000000..f3e9c47 --- /dev/null +++ b/src/dynarr.c @@ -0,0 +1,128 @@ +/* dynarr - dynamic resizable C array data structure + * author: John Tsiombikas + * license: public domain + */ +#include +#include +#include +#include "dynarr.h" + +/* The array descriptor keeps auxilliary information needed to manipulate + * the dynamic array. It's allocated adjacent to the array buffer. + */ +struct arrdesc { + int nelem, szelem; + int max_elem; + int bufsz; /* not including the descriptor */ +}; + +#define DESC(x) ((struct arrdesc*)((char*)(x) - sizeof(struct arrdesc))) + +void *dynarr_alloc(int elem, int szelem) +{ + struct arrdesc *desc; + + if(!(desc = malloc(elem * szelem + sizeof *desc))) { + return 0; + } + desc->nelem = desc->max_elem = elem; + desc->szelem = szelem; + desc->bufsz = elem * szelem; + return (char*)desc + sizeof *desc; +} + +void dynarr_free(void *da) +{ + if(da) { + free(DESC(da)); + } +} + +void *dynarr_resize(void *da, int elem) +{ + int newsz; + void *tmp; + struct arrdesc *desc; + + if(!da) return 0; + desc = DESC(da); + + newsz = desc->szelem * elem; + + if(!(tmp = realloc(desc, newsz + sizeof *desc))) { + return 0; + } + desc = tmp; + + desc->nelem = desc->max_elem = elem; + desc->bufsz = newsz; + return (char*)desc + sizeof *desc; +} + +int dynarr_empty(void *da) +{ + return DESC(da)->nelem ? 0 : 1; +} + +int dynarr_size(void *da) +{ + return DESC(da)->nelem; +} + + +/* stack semantics */ +void *dynarr_push(void *da, void *item) +{ + struct arrdesc *desc; + int nelem; + + desc = DESC(da); + nelem = desc->nelem; + + if(nelem >= desc->max_elem) { + /* need to resize */ + struct arrdesc *tmp; + int newsz = desc->max_elem ? desc->max_elem * 2 : 1; + + if(!(tmp = dynarr_resize(da, newsz))) { + fprintf(stderr, "failed to resize\n"); + return da; + } + da = tmp; + desc = DESC(da); + desc->nelem = nelem; + } + + if(item) { + memcpy((char*)da + desc->nelem++ * desc->szelem, item, desc->szelem); + } + return da; +} + +void *dynarr_pop(void *da) +{ + struct arrdesc *desc; + int nelem; + + desc = DESC(da); + nelem = desc->nelem; + + if(!nelem) return da; + + if(nelem <= desc->max_elem / 3) { + /* reclaim space */ + struct arrdesc *tmp; + int newsz = desc->max_elem / 2; + + if(!(tmp = dynarr_resize(da, newsz))) { + fprintf(stderr, "failed to resize\n"); + return da; + } + da = tmp; + desc = DESC(da); + desc->nelem = nelem; + } + desc->nelem--; + + return da; +} diff --git a/src/dynarr.h b/src/dynarr.h new file mode 100644 index 0000000..e528305 --- /dev/null +++ b/src/dynarr.h @@ -0,0 +1,38 @@ +/* dynarr - dynamic resizable C array data structure + * author: John Tsiombikas + * license: public domain + */ +#ifndef DYNARR_H_ +#define DYNARR_H_ + +void *dynarr_alloc(int elem, int szelem); +void dynarr_free(void *da); +void *dynarr_resize(void *da, int elem); + +int dynarr_empty(void *da); +int dynarr_size(void *da); + +/* stack semantics */ +void *dynarr_push(void *da, void *item); +void *dynarr_pop(void *da); + + +/* usage example: + * ------------- + * int *arr = dynarr_alloc(0, sizeof *arr); + * + * int x = 10; + * arr = dynarr_push(arr, &x); + * x = 5; + * arr = dynarr_push(arr, &x); + * x = 42; + * arr = dynarr_push(arr, &x); + * + * for(i=0; i +#include +#include +#include +#include +#include "screen.h" +#include "demo.h" +#include "3dgfx.h" +#include "gfxutil.h" +#include "util.h" +#include "metasurf.h" +#include "dynarr.h" + +struct mesh { + int prim; + struct g3d_vertex *varr; + int16_t *iarr; + int vcount, icount; +}; + +struct metaball { + float energy; + float pos[3]; +}; + +static int init(void); +static void destroy(void); +static void start(long trans_time); +static void draw(void); +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", + init, + destroy, + start, 0, + draw +}; + +static float cam_theta, cam_phi = 25; +static float cam_dist = 3; +static struct mesh mmesh; + +static struct metasurface *msurf; + +#define VOL_SZ 32 +#define VOL_SCALE 10.0f +#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]; + + +struct screen *metaballs_screen(void) +{ + return &scr; +} + +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; + + if(!(msurf = msurf_create())) { + fprintf(stderr, "failed to initialize metasurf\n"); + 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_threshold(msurf, 0.5); + msurf_set_inside(msurf, MSURF_GREATER); + msurf_vertex_func(msurf, emit_vertex); + + mmesh.prim = G3D_TRIANGLES; + mmesh.varr = 0; + mmesh.iarr = 0; + mmesh.vcount = mmesh.icount = 0; + + return 0; +} + +static void destroy(void) +{ + dynarr_free(mmesh.varr); +} + +static void start(long trans_time) +{ + g3d_matrix_mode(G3D_PROJECTION); + g3d_load_identity(); + g3d_perspective(50.0, 1.3333333, 0.5, 100.0); + + g3d_enable(G3D_CULL_FACE); + g3d_enable(G3D_LIGHTING); + g3d_enable(G3D_LIGHT0); + + g3d_polygon_mode(G3D_WIRE); +} + +static void update(void) +{ + static int prev_mx, prev_my; + static unsigned int prev_bmask; + + if(mouse_bmask) { + if((mouse_bmask ^ prev_bmask) == 0) { + int dx = mouse_x - prev_mx; + int dy = mouse_y - prev_my; + + if(dx || dy) { + if(mouse_bmask & 1) { + cam_theta += dx * 1.0; + cam_phi += dy * 1.0; + + if(cam_phi < -90) cam_phi = -90; + if(cam_phi > 90) cam_phi = 90; + } + if(mouse_bmask & 4) { + cam_dist += dy * 0.5; + + if(cam_dist < 0) cam_dist = 0; + } + } + } + } + prev_mx = mouse_x; + prev_my = mouse_y; + prev_bmask = mouse_bmask; + + { + int i, j; + float tsec = time_msec / 1000.0f; + static float phase[] = {0.0, M_PI / 3.0, M_PI * 0.8}; + static float speed[] = {0.8, 1.4, 1.0}; + static float scale[][3] = {{1, 2, 0.8}, {0.5, 1.6, 0.6}, {1.5, 0.7, 0.5}}; + static float offset[][3] = {{0, 0, 0}, {0.25, 0, 0}, {-0.2, 0.15, 0.2}}; + + for(i=0; iiarr) { + g3d_draw_indexed(mesh->prim, mesh->varr, mesh->vcount, mesh->iarr, mesh->icount); + } else { + g3d_draw(mesh->prim, mesh->varr, mesh->vcount); + } +} + +static struct { + struct g3d_vertex *varr; + const float *xform; +} zsort_cls; + +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]; + + 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]; + + 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]; + + return za - zb; +} + +static void zsort(struct mesh *m) +{ + int nfaces = m->icount / 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); +} + +static void calc_voxel_field(void) +{ + int i, j, k, b; + float *voxptr = volume; + + for(i=0; i= 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; + + 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); + + mmesh.varr = dynarr_push(mmesh.varr, &v); + assert(mmesh.varr); + ++mmesh.vcount; +} diff --git a/src/metasurf.c b/src/metasurf.c new file mode 100644 index 0000000..85aae1c --- /dev/null +++ b/src/metasurf.c @@ -0,0 +1,451 @@ +/* +metasurf - a library for implicit surface polygonization +Copyright (C) 2011-2015 John Tsiombikas + +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 . +*/ +#include +#include +#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]; + 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; + + vec3 vbuf[3]; + int nverts; +}; + +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 + + +struct metasurface *msurf_create(void) +{ + struct metasurface *ms; + + if(!(ms = malloc(sizeof *ms))) { + return 0; + } + if(msurf_init(ms) == -1) { + free(ms); + } + return ms; +} + +void msurf_free(struct metasurface *ms) +{ + free(ms); +} + +static int msurf_init(struct metasurface *ms) +{ + 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->dx = ms->dy = ms->dz = 0.001; + ms->flip = 0; + + return 0; +} + +void msurf_set_user_data(struct metasurface *ms, void *udata) +{ + ms->udata = udata; +} + +void *msurf_get_user_data(struct metasurface *ms) +{ + return ms->udata; +} + +void msurf_set_inside(struct metasurface *ms, int inside) +{ + switch(inside) { + case MSURF_GREATER: + ms->flip = 0; + break; + + case MSURF_LESS: + ms->flip = 1; + break; + + default: + fprintf(stderr, "msurf_inside expects MSURF_GREATER or MSURF_LESS\n"); + } +} + +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; +} + +void msurf_set_bounds(struct metasurface *ms, float xmin, float ymin, float zmin, float xmax, float ymax, float zmax) +{ + ms->min[0] = xmin; + ms->min[1] = ymin; + ms->min[2] = zmin; + ms->max[0] = xmax; + ms->max[1] = ymax; + ms->max[2] = zmax; +} + +void msurf_get_bounds(struct metasurface *ms, float *xmin, float *ymin, float *zmin, float *xmax, float *ymax, float *zmax) +{ + *xmin = ms->min[0]; + *ymin = ms->min[1]; + *zmin = ms->min[2]; + *xmax = ms->max[0]; + *ymax = ms->max[1]; + *zmax = ms->max[2]; +} + +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; +} + +void msurf_get_resolution(struct metasurface *ms, int *xres, int *yres, int *zres) +{ + *xres = ms->res[0]; + *yres = ms->res[1]; + *zres = ms->res[2]; +} + +void msurf_set_threshold(struct metasurface *ms, float thres) +{ + ms->thres = thres; +} + +float msurf_get_threshold(struct metasurface *ms) +{ + return ms->thres; +} + + +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; + } + + 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; ires[0] - 1; i++) { + pos[1] = ms->min[1]; + for(j=0; jres[1] - 1; j++) { + + pos[2] = ms->min[2]; + for(k=0; kres[2] - 1; k++) { + + process_cell(ms, pos, delta); + + pos[2] += delta[2]; + } + pos[1] += delta[1]; + } + pos[0] += delta[0]; + } + return 0; +} + + +static void process_cell(struct metasurface *ms, vec3 pos, vec3 sz) +{ + 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 +} + + +/* ---- marching cubes implementation ---- */ +#ifdef USE_MCUBES + +static unsigned int mc_bitcode(float *val, float thres); + +static void process_cube(struct metasurface *ms, vec3 *pos, float *val) +{ + 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; + } + + if(mc_edge_table[code] == 0) { + return; + } + + for(i=0; i<12; i++) { + if(mc_edge_table[code] & (1 << i)) { + int p0 = pidx[i][0]; + int p1 = pidx[i][1]; + + float t = (ms->thres - val[p0]) / (val[p1] - val[p0]); + 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; + } + } + + 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; + } + ms->normal(ms, dfdx, dfdy, dfdz); + } + + /* TODO multithreadied polygon emmit */ + ms->vertex(ms, v[0], v[1], v[2]); + } + } +} + +static unsigned int mc_bitcode(float *val, float thres) +{ + unsigned int i, res = 0; + + for(i=0; i<8; i++) { + if(val[i] > thres) { + res |= 1 << i; + } + } + 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 */ diff --git a/src/metasurf.h b/src/metasurf.h new file mode 100644 index 0000000..7cdd074 --- /dev/null +++ b/src/metasurf.h @@ -0,0 +1,79 @@ +/* +metasurf - a library for implicit surface polygonization +Copyright (C) 2011-2015 John Tsiombikas + +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 . +*/ + +#ifndef METASURF_H_ +#define METASURF_H_ + +#define MSURF_GREATER 1 +#define MSURF_LESS 0 + +struct metasurface; + +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); + +#ifdef __cplusplus +extern "C" { +#endif + +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); + +/* 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 + */ +void msurf_set_bounds(struct metasurface *ms, float xmin, float ymin, float zmin, float xmax, float ymax, float zmax); +void msurf_get_bounds(struct metasurface *ms, float *xmin, float *ymin, float *zmin, float *xmax, float *ymax, float *zmax); + +/* resolution of the 3D evaluation grid, the bigger, the better, the slower + * (default: 40, 40, 40) + */ +void msurf_set_resolution(struct metasurface *ms, int xres, int yres, int zres); +void msurf_get_resolution(struct metasurface *ms, int *xres, int *yres, int *zres); + +/* isosurface threshold value (default: 0) */ +void msurf_set_threshold(struct metasurface *ms, float thres); +float msurf_get_threshold(struct metasurface *ms); + + +/* finally call this to perform the polygonization */ +int msurf_polygonize(struct metasurface *ms); + + +#ifdef __cplusplus +} +#endif + +#endif /* METASURF_H_ */ diff --git a/src/screen.c b/src/screen.c index 9aae073..2b551f4 100644 --- a/src/screen.c +++ b/src/screen.c @@ -12,6 +12,7 @@ struct screen *polytest_screen(void); struct screen *plasma_screen(void); struct screen *bump_screen(void); struct screen *thunder_screen(void); +struct screen *metaballs_screen(void); #define NUM_SCR 32 static struct screen *scr[NUM_SCR]; @@ -45,6 +46,9 @@ int scr_init(void) if (!(scr[idx++] = thunder_screen())) { return -1; } + if(!(scr[idx++] = metaballs_screen())) { + return -1; + } num_screens = idx; assert(num_screens <= NUM_SCR); -- 1.7.10.4