over the line
[metatoy] / src / game.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <math.h>
4 #include "game.h"
5 #include "colormgr.h"
6 #include "3dgfx.h"
7 #include "mesh.h"
8 #include "metasurf.h"
9 #include "util.h"
10 #include "cgmath/cgmath.h"
11
12 #define BBOX_SIZE               10.0f
13 #define BBOX_HEIGHT             15.0f
14 #define BBOX_HSZ                (BBOX_SIZE / 2.0f)
15 #define BBOX_HH                 (BBOX_HEIGHT / 2.0f)
16 #define VOX_RES                 30
17 #define VOX_YRES                (VOX_RES * BBOX_HEIGHT / BBOX_SIZE)
18 #define VOX_STEP                (BBOX_SIZE / (float)VOX_RES)
19 #define VOX_YSTEP               (BBOX_HEIGHT / (float)VOX_YRES)
20
21 #define VBUF_MAX_TRIS   256
22 #define VBUF_SIZE               (VBUF_MAX_TRIS * 3)
23
24 struct mball {
25         float energy;
26         cgm_vec3 pos;
27 };
28
29 struct mcapsule {
30         float energy;
31         cgm_vec3 end[2];
32         float len;
33 };
34
35 static struct g3d_mesh mesh;
36 static struct g3d_vertex *vbuf;
37 static struct metasurface *msurf;
38 static struct mball *balls;
39 static int num_balls;
40 static struct mcapsule *caps;
41 static int num_caps;
42
43 static void update(float tsec);
44 static void draw_metaballs(void);
45 static float capsule_distsq(struct mcapsule *c, cgm_vec3 *pos);
46
47 static cgm_vec3 sgiv[] = {
48         {2.794170, 4.254175, 2.738066},
49         {2.794170, 4.254174, -4.358471},
50         {-2.173414, 4.254174, -4.358471},
51         {-2.173414, -2.842363, -4.358470},
52         {4.923134, -2.842363, -4.358471},
53         {4.923134, 2.125212, -4.358471},
54         {4.923134, 2.125212, 2.738066},
55         {4.923134, -4.971326, 2.738067},
56         {4.923134, -4.971326, -2.229511},
57         {-2.173413, -4.971326, -2.229511},
58         {-2.173413, -4.971325, 4.867042},
59         {2.794170, -4.971325, 4.867042},
60         {2.794170, 2.125213, 4.867042},
61         {-4.302382, 2.125213, 4.867042},
62         {-4.302383, -2.842362, 4.867042},
63         {-4.302382, -2.842363, -2.229511},
64         {-4.302382, 4.254175, -2.229512},
65         {-4.302383, 4.254175, 2.738066}
66 };
67
68 int game_init(void)
69 {
70         int i;
71         float mat[16];
72
73         init_colormgr();
74
75         g3d_init();
76         g3d_framebuffer(FB_WIDTH, FB_HEIGHT, framebuf);
77         g3d_viewport(0, 0, FB_WIDTH, FB_HEIGHT);
78
79         g3d_clear_color(0, 0, 0);
80
81         g3d_matrix_mode(G3D_PROJECTION);
82         g3d_load_identity();
83         g3d_perspective(60.0f, 1.33333, 0.5, 500.0);
84
85         g3d_enable(G3D_CULL_FACE);
86         g3d_enable(G3D_DEPTH_TEST);
87         g3d_enable(G3D_LIGHTING);
88         g3d_enable(G3D_LIGHT0);
89
90         g3d_polygon_mode(G3D_GOURAUD);
91
92         gen_torus_mesh(&mesh, 2.0, 0.7, 24, 12);
93
94         if(!(msurf = msurf_create())) {
95                 return -1;
96         }
97         msurf_set_threshold(msurf, 8);
98         msurf_set_inside(msurf, MSURF_GREATER);
99         msurf_set_bounds(msurf, -BBOX_HSZ, -BBOX_HH, -BBOX_HSZ, BBOX_HSZ, BBOX_HH, BBOX_HSZ);
100         msurf_set_resolution(msurf, VOX_RES, VOX_YRES, VOX_RES);
101         msurf_enable(msurf, MSURF_NORMALIZE);
102
103         vbuf = malloc_nf(VBUF_SIZE * sizeof *vbuf);
104
105         num_balls = 0;
106         balls = calloc_nf(num_balls, sizeof *balls);
107         num_caps = sizeof sgiv / sizeof *sgiv;
108         caps = calloc_nf(num_caps, sizeof *caps);
109
110         for(i=0; i<num_balls; i++) {
111                 balls[i].energy = 5;
112         }
113
114         cgm_midentity(mat);
115         cgm_mtranslate(mat, 0, -BBOX_HH / 2, 0);
116         cgm_mrotate_y(mat, -M_PI / 4.0f);
117         cgm_mrotate_x(mat, M_PI / 4.0f);
118
119         for(i=0; i<num_caps; i++) {
120                 caps[i].energy = 1;
121                 caps[i].end[0] = sgiv[i];
122                 cgm_vscale(caps[i].end, 0.6);
123                 caps[i].end[1] = sgiv[(i + 1) % num_caps];
124                 cgm_vscale(caps[i].end + 1, 0.6);
125
126                 cgm_vmul_m4v3(caps[i].end, mat);
127                 cgm_vmul_m4v3(caps[i].end + 1, mat);
128         }
129         return 0;
130 }
131
132 void game_shutdown(void)
133 {
134 }
135
136 static void update(float tsec)
137 {
138         int i, j, k, n;
139         float dsq, energy;
140         cgm_vec3 pos;
141         float *vox = msurf_voxels(msurf);
142
143         for(i=0; i<num_balls; i++) {
144                 balls[i].pos.y = sin(tsec) * BBOX_HH;
145         }
146
147         float y = sin(tsec) * BBOX_HH / 80.0f;
148         for(i=0; i<num_caps; i++) {
149                 caps[i].end[0].y += y;
150                 caps[i].end[1].y += y;
151                 caps[i].len = cgm_vdist(caps[i].end, caps[i].end + 1);
152         }
153
154         for(i=0; i<VOX_RES; i++) {
155                 pos.z = -BBOX_HSZ + i * VOX_STEP;
156                 for(j=0; j<VOX_YRES; j++) {
157                         pos.y = -BBOX_HH + j * VOX_YSTEP;
158                         for(k=0; k<VOX_RES; k++) {
159                                 pos.x = -BBOX_HSZ + k * VOX_STEP;
160
161                                 /* initialize with the vertical distance for the pool */
162                                 energy = 5.0 / (pos.y + BBOX_HH * 0.98);
163
164                                 /* add the contribution of the balls */
165                                 for(n=0; n<num_balls; n++) {
166                                         dsq = cgm_vdist_sq(&balls[n].pos, &pos);
167                                         energy += balls[n].energy / dsq;
168                                 }
169
170                                 /* add the contribution of the capsules */
171                                 for(n=0; n<num_caps; n++) {
172                                         dsq = capsule_distsq(caps + n, &pos);
173                                         energy += caps[n].energy / dsq;
174                                 }
175
176                                 *vox++ = energy;
177                         }
178                 }
179         }
180
181         msurf_polygonize(msurf);
182 }
183
184 void game_draw(void)
185 {
186         unsigned long msec = game_getmsec();
187         float tsec = (float)msec / 1000.0f;
188
189         update(tsec);
190
191         g3d_clear(G3D_COLOR_BUFFER_BIT | G3D_DEPTH_BUFFER_BIT);
192
193         g3d_matrix_mode(G3D_MODELVIEW);
194         g3d_load_identity();
195         g3d_translate(0, 1, -15);
196         /*g3d_rotate(tsec * 50.0f, 1, 0, 0);
197         g3d_rotate(tsec * 30.0f, 0, 0, 1);
198
199         draw_mesh(&mesh);*/
200         draw_metaballs();
201
202         game_swap_buffers();
203 }
204
205 static void draw_metaballs(void)
206 {
207         int i, nverts, vbuf_count;
208         float *varr, *narr;
209         struct g3d_vertex *vbptr;
210         static int nfrm;
211
212         nverts = msurf_vertex_count(msurf);
213         varr = msurf_vertices(msurf);
214         narr = msurf_normals(msurf);
215
216         vbptr = vbuf;
217         for(i=0; i<nverts; i++) {
218                 vbuf_count = vbptr - vbuf;
219                 if(vbuf_count >= VBUF_SIZE) {
220                         g3d_draw(G3D_TRIANGLES, vbuf, vbuf_count);
221                         vbptr = vbuf;
222                 }
223                 vbptr->x = varr[0];
224                 vbptr->y = varr[1];
225                 vbptr->z = varr[2];
226                 vbptr->w = 1.0f;
227                 vbptr->nx = narr[0];
228                 vbptr->ny = narr[1];
229                 vbptr->nz = narr[2];
230                 vbptr->w = 1.0f;
231                 vbptr->l = 255;
232                 vbptr++;
233                 varr += 3;
234                 narr += 3;
235         }
236
237         if(vbptr > vbuf) {
238                 g3d_draw(G3D_TRIANGLES, vbuf, vbptr - vbuf);
239         }
240
241         nfrm++;
242 }
243
244 void game_keyboard(int key, int press)
245 {
246         if(key == 27) game_quit();
247 }
248
249 void game_mouse(int bn, int press, int x, int y)
250 {
251 }
252
253 void game_motion(int x, int y)
254 {
255 }
256
257 static float capsule_distsq(struct mcapsule *c, cgm_vec3 *pos)
258 {
259         float t;
260         cgm_vec3 pp, dir, pdir;
261
262         dir = c->end[1]; cgm_vsub(&dir, c->end);
263         if(c->len != 0.0f) {
264                 float s = 1.0f / c->len;
265                 dir.x *= s;
266                 dir.y *= s;
267                 dir.z *= s;
268         }
269         pdir = *pos; cgm_vsub(&pdir, c->end);
270         t = cgm_vdot(&dir, &pdir);
271
272         if(t < 0.0f) {
273                 return cgm_vdist_sq(c->end, pos);
274         }
275         if(t > c->len) {
276                 return cgm_vdist_sq(c->end + 1, pos);
277         }
278
279         pp = c->end[0];
280         cgm_vadd_scaled(&pp, &dir, t);
281         return cgm_vdist_sq(&pp, pos);
282 }