16 struct g3d_vertex *varr;
26 static int init(void);
27 static void destroy(void);
28 static void start(long trans_time);
29 static void draw(void);
30 static void draw_mesh(struct mesh *mesh);
31 static void zsort(struct mesh *m);
33 static void calc_voxel_field(void);
34 static float eval(struct metasurface *ms, float x, float y, float z);
35 static void emit_vertex(struct metasurface *ms, float x, float y, float z);
37 static struct screen scr = {
45 static float cam_theta, cam_phi = 25;
46 static float cam_dist = 10;
47 static struct mesh mmesh;
49 static struct metasurface *msurf;
52 #define VOL_SCALE 10.0f
53 #define VOX_DIST (VOL_SCALE / VOL_SZ)
54 #define VOL_HALF_SCALE (VOL_SCALE * 0.5f)
56 #define VOXEL(x, y, z) (volume[(z) * VOL_SZ * VOL_SZ + (y) * VOL_SZ + (x)])
59 static struct metaball mball[NUM_MBALLS];
63 struct screen *metaballs_screen(void)
70 if(!(volume = malloc(VOL_SZ * VOL_SZ * VOL_SZ * sizeof *volume))) {
71 fprintf(stderr, "failed to allocate %dx%dx%d voxel field\n", VOL_SZ, VOL_SZ, VOL_SZ);
75 mball[0].energy = 1.2;
76 mball[1].energy = 0.8;
77 mball[2].energy = 1.0;
79 if(!(msurf = msurf_create())) {
80 fprintf(stderr, "failed to initialize metasurf\n");
83 msurf_set_resolution(msurf, VOL_SZ, VOL_SZ, VOL_SZ);
84 msurf_set_bounds(msurf, 0, 0, 0, VOL_SCALE, VOL_SCALE, VOL_SCALE);
85 msurf_eval_func(msurf, eval);
86 msurf_set_threshold(msurf, 1.7);
87 msurf_set_inside(msurf, MSURF_GREATER);
88 msurf_vertex_func(msurf, emit_vertex);
90 mmesh.prim = G3D_TRIANGLES;
93 mmesh.vcount = mmesh.icount = 0;
98 static void destroy(void)
100 dynarr_free(mmesh.varr);
103 static void start(long trans_time)
105 g3d_matrix_mode(G3D_PROJECTION);
107 g3d_perspective(50.0, 1.3333333, 0.5, 100.0);
109 g3d_enable(G3D_CULL_FACE);
110 g3d_enable(G3D_LIGHTING);
111 g3d_enable(G3D_LIGHT0);
113 g3d_polygon_mode(G3D_GOURAUD);
116 static void update(void)
118 static int prev_mx, prev_my;
119 static unsigned int prev_bmask;
122 if((mouse_bmask ^ prev_bmask) == 0) {
123 int dx = mouse_x - prev_mx;
124 int dy = mouse_y - prev_my;
127 if(mouse_bmask & 1) {
128 cam_theta += dx * 1.0;
131 if(cam_phi < -90) cam_phi = -90;
132 if(cam_phi > 90) cam_phi = 90;
134 if(mouse_bmask & 4) {
135 cam_dist += dy * 0.5;
137 if(cam_dist < 0) cam_dist = 0;
144 prev_bmask = mouse_bmask;
148 float tsec = time_msec / 1000.0f;
149 static float phase[] = {0.0, M_PI / 3.0, M_PI * 0.8};
150 static float speed[] = {0.8, 1.4, 1.0};
151 static float scale[][3] = {{1, 2, 0.8}, {0.5, 1.6, 0.6}, {1.5, 0.7, 0.5}};
152 static float offset[][3] = {{0, 0, 0}, {0.25, 0, 0}, {-0.2, 0.15, 0.2}};
154 for(i=0; i<NUM_MBALLS; i++) {
155 float t = (tsec + phase[i]) * speed[i];
158 float x = sin(t + j * M_PI / 2.0);
159 mball[i].pos[j] = offset[i][j] + x * scale[i][j];
166 dynarr_free(mmesh.varr);
168 mmesh.varr = dynarr_alloc(0, sizeof *mmesh.varr);
169 msurf_polygonize(msurf);
172 static void draw(void)
176 memset(fb_pixels, 0, fb_width * fb_height * 2);
178 g3d_matrix_mode(G3D_MODELVIEW);
180 g3d_translate(0, 0, -cam_dist);
181 g3d_rotate(cam_phi, 1, 0, 0);
182 g3d_rotate(cam_theta, 0, 1, 0);
184 g3d_light_pos(0, -10, 10, 20);
188 g3d_mtl_diffuse(0.6, 0.6, 0.6);
192 swap_buffers(fb_pixels);
195 static void draw_mesh(struct mesh *mesh)
198 g3d_draw_indexed(mesh->prim, mesh->varr, mesh->vcount, mesh->iarr, mesh->icount);
200 g3d_draw(mesh->prim, mesh->varr, mesh->vcount);
205 struct g3d_vertex *varr;
209 static int zsort_cmp(const void *aptr, const void *bptr)
211 const int16_t *a = (const int16_t*)aptr;
212 const int16_t *b = (const int16_t*)bptr;
214 const float *m = zsort_cls.xform;
216 const struct g3d_vertex *va = zsort_cls.varr + a[0];
217 const struct g3d_vertex *vb = zsort_cls.varr + b[0];
219 float za = m[2] * va->x + m[6] * va->y + m[10] * va->z + m[14];
220 float zb = m[2] * vb->x + m[6] * vb->y + m[10] * vb->z + m[14];
222 va = zsort_cls.varr + a[2];
223 vb = zsort_cls.varr + b[2];
225 za += m[2] * va->x + m[6] * va->y + m[10] * va->z + m[14];
226 zb += m[2] * vb->x + m[6] * vb->y + m[10] * vb->z + m[14];
231 static void zsort(struct mesh *m)
233 int nfaces = m->icount / m->prim;
235 zsort_cls.varr = m->varr;
236 zsort_cls.xform = g3d_get_matrix(G3D_MODELVIEW, 0);
238 qsort(m->iarr, nfaces, m->prim * sizeof *m->iarr, zsort_cmp);
241 static void calc_voxel_field(void)
244 float *voxptr = volume;
246 for(i=0; i<VOL_SZ; i++) {
247 float z = VOL_SCALE * ((float)i / (float)VOL_SZ - 0.5);
249 for(j=0; j<VOL_SZ; j++) {
250 float y = VOL_SCALE * ((float)j / (float)VOL_SZ - 0.5);
252 for(k=0; k<VOL_SZ; k++) {
253 float x = VOL_SCALE * ((float)k / (float)VOL_SZ - 0.5);
256 for(b=0; b<NUM_MBALLS; b++) {
257 float dx = mball[b].pos[0] - x;
258 float dy = mball[b].pos[1] - y;
259 float dz = mball[b].pos[2] - z;
261 float lensq = dx * dx + dy * dy + dz * dz;
263 val += lensq == 0.0f ? 1024.0f : mball[b].energy / lensq;
273 static float eval(struct metasurface *ms, float x, float y, float z)
275 int xidx = cround64(VOL_SZ * x / VOL_SCALE);
276 int yidx = cround64(VOL_SZ * y / VOL_SCALE);
277 int zidx = cround64(VOL_SZ * z / VOL_SCALE);
279 assert(xidx >= 0 && xidx < VOL_SZ);
280 assert(yidx >= 0 && yidx < VOL_SZ);
281 assert(zidx >= 0 && zidx < VOL_SZ);
283 return VOXEL(xidx, yidx, zidx);
286 static void emit_vertex(struct metasurface *ms, float x, float y, float z)
291 v.x = x - VOL_HALF_SCALE;
292 v.y = y - VOL_HALF_SCALE;
293 v.z = z - VOL_HALF_SCALE;
294 v.r = cround64(255.0 * x / VOL_SCALE);
295 v.g = cround64(255.0 * y / VOL_SCALE);
296 v.b = cround64(255.0 * z / VOL_SCALE);
298 val = eval(ms, x, y, z);
299 v.nx = eval(ms, x + VOX_DIST, y, z) - val;
300 v.ny = eval(ms, x, y + VOX_DIST, z) - val;
301 v.nz = eval(ms, x, y, z - VOX_DIST) - val;
303 if((len = sqrt(v.nx * v.nx + v.ny * v.ny + v.nz * v.nz)) != 0.0f) {
309 mmesh.varr = dynarr_push(mmesh.varr, &v);