clipping bugs...
[dosdemo] / src / metaball.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <math.h>
5 #include <assert.h>
6 #include "screen.h"
7 #include "demo.h"
8 #include "3dgfx.h"
9 #include "gfxutil.h"
10 #include "util.h"
11 #include "metasurf.h"
12
13 struct mesh {
14         int prim;
15         struct g3d_vertex *varr;
16         int16_t *iarr;
17         int vcount, icount;
18 };
19
20 struct metaball {
21         float energy;
22         float pos[3];
23 };
24
25 static int init(void);
26 static void destroy(void);
27 static void start(long trans_time);
28 static void draw(void);
29 static void draw_mesh(struct mesh *mesh);
30 static void zsort(struct mesh *m);
31
32 static void calc_voxel_field(void);
33
34 static struct screen scr = {
35         "metaballs",
36         init,
37         destroy,
38         start, 0,
39         draw
40 };
41
42 static float cam_theta, cam_phi = 25;
43 static float cam_dist = 10;
44 static struct mesh mmesh;
45
46 static struct metasurface *msurf;
47
48 #define VOL_SZ  32
49 #define VOL_SCALE       10.0f
50 #define VOX_DIST        (VOL_SCALE / VOL_SZ)
51 #define VOL_HALF_SCALE  (VOL_SCALE * 0.5f)
52
53 #define NUM_MBALLS      3
54 static struct metaball mball[NUM_MBALLS];
55
56 static int dbg;
57
58 struct screen *metaballs_screen(void)
59 {
60         return &scr;
61 }
62
63 static int init(void)
64 {
65         mball[0].energy = 1.2;
66         mball[1].energy = 0.8;
67         mball[2].energy = 1.0;
68
69         if(!(msurf = msurf_create())) {
70                 fprintf(stderr, "failed to initialize metasurf\n");
71                 return -1;
72         }
73         msurf_set_resolution(msurf, VOL_SZ, VOL_SZ, VOL_SZ);
74         msurf_set_bounds(msurf, -VOL_HALF_SCALE, -VOL_HALF_SCALE, -VOL_HALF_SCALE,
75                         VOL_HALF_SCALE, VOL_HALF_SCALE, VOL_HALF_SCALE);
76         msurf_set_threshold(msurf, 1.7);
77         msurf_set_inside(msurf, MSURF_GREATER);
78
79         mmesh.prim = G3D_TRIANGLES;
80         mmesh.varr = 0;
81         mmesh.iarr = 0;
82         mmesh.vcount = mmesh.icount = 0;
83
84         return 0;
85 }
86
87 static void destroy(void)
88 {
89         msurf_free(msurf);
90 }
91
92 static void start(long trans_time)
93 {
94         g3d_matrix_mode(G3D_PROJECTION);
95         g3d_load_identity();
96         g3d_perspective(50.0, 1.3333333, 0.5, 100.0);
97
98         g3d_enable(G3D_CULL_FACE);
99         g3d_enable(G3D_LIGHTING);
100         g3d_enable(G3D_LIGHT0);
101
102         g3d_polygon_mode(G3D_GOURAUD);
103 }
104
105 static void update(void)
106 {
107         static int prev_mx, prev_my;
108         static unsigned int prev_bmask;
109
110         if(mouse_bmask) {
111                 if((mouse_bmask ^ prev_bmask) == 0) {
112                         int dx = mouse_x - prev_mx;
113                         int dy = mouse_y - prev_my;
114
115                         if(dx || dy) {
116                                 if(mouse_bmask & 1) {
117                                         cam_theta += dx * 1.0;
118                                         cam_phi += dy * 1.0;
119
120                                         if(cam_phi < -90) cam_phi = -90;
121                                         if(cam_phi > 90) cam_phi = 90;
122                                 }
123                                 if(mouse_bmask & 4) {
124                                         cam_dist += dy * 0.5;
125
126                                         if(cam_dist < 0) cam_dist = 0;
127                                 }
128                         }
129                 }
130         }
131         prev_mx = mouse_x;
132         prev_my = mouse_y;
133         prev_bmask = mouse_bmask;
134
135         {
136                 int i, j;
137                 float tsec = time_msec / 1000.0f;
138                 static float phase[] = {0.0, M_PI / 3.0, M_PI * 0.8};
139                 static float speed[] = {0.8, 1.4, 1.0};
140                 static float scale[][3] = {{1, 2, 0.8}, {0.5, 1.6, 0.6}, {1.5, 0.7, 0.5}};
141                 static float offset[][3] = {{0, 0, 0}, {0.25, 0, 0}, {-0.2, 0.15, 0.2}};
142
143                 for(i=0; i<NUM_MBALLS; i++) {
144                         float t = (tsec + phase[i]) * speed[i];
145
146                         for(j=0; j<3; j++) {
147                                 float x = sin(t + j * M_PI / 2.0);
148                                 mball[i].pos[j] = offset[i][j] + x * scale[i][j];
149                         }
150                 }
151         }
152
153         calc_voxel_field();
154         msurf_polygonize(msurf);
155
156         mmesh.vcount = msurf_vertex_count(msurf);
157         mmesh.varr = msurf_vertices(msurf);
158 }
159
160 static void draw(void)
161 {
162         int i, j;
163
164         update();
165
166         memset(fb_pixels, 0, fb_width * fb_height * 2);
167
168         for(i=0; i<120; i++) {
169                 for(j=0; j<160; j++) {
170                         fb_pixels[(i + 60) * 320 + (j + 80)] = 0x1e7;
171                 }
172         }
173         g3d_viewport(80, 60, 160, 120);
174
175         g3d_matrix_mode(G3D_MODELVIEW);
176         g3d_load_identity();
177         g3d_translate(0, 0, -cam_dist);
178         g3d_rotate(cam_phi, 1, 0, 0);
179         g3d_rotate(cam_theta, 0, 1, 0);
180
181         g3d_light_pos(0, -10, 10, 20);
182
183         zsort(&mmesh);
184
185         g3d_mtl_diffuse(0.6, 0.6, 0.6);
186
187         draw_mesh(&mmesh);
188
189         g3d_viewport(0, 0, fb_width, fb_height);
190
191         swap_buffers(fb_pixels);
192 }
193
194 static void draw_mesh(struct mesh *mesh)
195 {
196         if(mesh->iarr) {
197                 g3d_draw_indexed(mesh->prim, mesh->varr, mesh->vcount, mesh->iarr, mesh->icount);
198         } else {
199                 g3d_draw(mesh->prim, mesh->varr, mesh->vcount);
200         }
201 }
202
203 static struct {
204         struct g3d_vertex *varr;
205         const float *xform;
206 } zsort_cls;
207
208 static int zsort_cmp(const void *aptr, const void *bptr)
209 {
210         const float *m = zsort_cls.xform;
211
212         const struct g3d_vertex *va = (const struct g3d_vertex*)aptr;
213         const struct g3d_vertex *vb = (const struct g3d_vertex*)bptr;
214
215         float za = m[2] * va->x + m[6] * va->y + m[10] * va->z + m[14];
216         float zb = m[2] * vb->x + m[6] * vb->y + m[10] * vb->z + m[14];
217
218         ++va;
219         ++vb;
220
221         za += m[2] * va->x + m[6] * va->y + m[10] * va->z + m[14];
222         zb += m[2] * vb->x + m[6] * vb->y + m[10] * vb->z + m[14];
223
224         return za - zb;
225 }
226
227 static void zsort(struct mesh *m)
228 {
229         int nfaces = m->vcount / m->prim;
230
231         zsort_cls.varr = m->varr;
232         zsort_cls.xform = g3d_get_matrix(G3D_MODELVIEW, 0);
233
234         qsort(m->varr, nfaces, m->prim * sizeof *m->varr, zsort_cmp);
235 }
236
237 static void calc_voxel_field(void)
238 {
239         int i, j, k, b;
240         float *voxptr;
241
242         if(!(voxptr = msurf_voxels(msurf))) {
243                 fprintf(stderr, "failed to allocate voxel field\n");
244                 abort();
245         }
246
247         for(i=0; i<VOL_SZ; i++) {
248                 float z = -VOL_HALF_SCALE + i * VOX_DIST;
249
250                 for(j=0; j<VOL_SZ; j++) {
251                         float y = -VOL_HALF_SCALE + j * VOX_DIST;
252
253                         for(k=0; k<VOL_SZ; k++) {
254                                 float x = -VOL_HALF_SCALE + k * VOX_DIST;
255
256                                 float val = 0.0f;
257                                 for(b=0; b<NUM_MBALLS; b++) {
258                                         float dx = mball[b].pos[0] - x;
259                                         float dy = mball[b].pos[1] - y;
260                                         float dz = mball[b].pos[2] - z;
261
262                                         float lensq = dx * dx + dy * dy + dz * dz;
263
264                                         val += lensq == 0.0f ? 1024.0f : mball[b].energy / lensq;
265                                 }
266
267                                 *voxptr++ = val;
268                         }
269                 }
270         }
271         ++dbg;
272 }