size-optimized marching cube tables COM went from 68420->53252
[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 #include "metaobj.h"
12
13 #define BBOX_XSZ                16
14 #define BBOX_YSZ                15
15 #define BBOX_ZSZ                10
16 #define VOX_RES                 30
17
18 #define BBOX_HXSZ               (BBOX_XSZ / 2.0f)
19 #define BBOX_HYSZ               (BBOX_YSZ / 2.0f)
20 #define BBOX_HZSZ               (BBOX_ZSZ / 2.0f)
21 #define VOX_XRES                (VOX_RES * BBOX_XSZ / BBOX_ZSZ)
22 #define VOX_YRES                (VOX_RES * BBOX_YSZ / BBOX_ZSZ)
23 #define VOX_ZRES                VOX_RES
24 #define VOX_XSTEP               (BBOX_XSZ / (float)VOX_XRES)
25 #define VOX_YSTEP               (BBOX_YSZ / (float)VOX_YRES)
26 #define VOX_ZSTEP               (BBOX_ZSZ / (float)VOX_ZRES)
27
28 #define VBUF_MAX_TRIS   256
29 #define VBUF_SIZE               (VBUF_MAX_TRIS * 3)
30
31 static struct g3d_vertex *vbuf;
32 static struct metasurface *msurf;
33 static struct mobject **mobj;
34
35 #define NUM_OBJ         2
36 static int num_mobj, cur_obj;
37 static int grabbed;
38
39 static int mousebn[3];
40 static int mousex, mousey;
41 static float cam_theta, cam_phi;
42
43
44 static void update(float tsec);
45 static void draw_metaballs(void);
46
47
48 int game_init(void)
49 {
50         init_colormgr();
51
52         g3d_init();
53         g3d_framebuffer(FB_WIDTH, FB_HEIGHT, framebuf);
54         g3d_viewport(0, 0, FB_WIDTH, FB_HEIGHT);
55
56         g3d_clear_color(0, 0, 0);
57
58         g3d_matrix_mode(G3D_PROJECTION);
59         g3d_load_identity();
60         g3d_perspective(60.0f, 1.33333, 0.5, 500.0);
61
62         g3d_enable(G3D_CULL_FACE);
63         g3d_enable(G3D_DEPTH_TEST);
64         g3d_enable(G3D_LIGHTING);
65         g3d_enable(G3D_LIGHT0);
66         g3d_light_ambient(0.2);
67
68         g3d_polygon_mode(G3D_GOURAUD);
69
70         if(!(msurf = msurf_create())) {
71                 return -1;
72         }
73         msurf_set_threshold(msurf, 8);
74         msurf_set_inside(msurf, MSURF_GREATER);
75         msurf_set_bounds(msurf, -BBOX_HXSZ, -BBOX_HYSZ, -BBOX_HZSZ, BBOX_HXSZ, BBOX_HYSZ, BBOX_HZSZ);
76         msurf_set_resolution(msurf, VOX_XRES, VOX_YRES, VOX_ZRES);
77         msurf_enable(msurf, MSURF_NORMALIZE);
78
79         vbuf = malloc_nf(VBUF_SIZE * sizeof *vbuf);
80
81         num_mobj = NUM_OBJ;
82         mobj = malloc(num_mobj * sizeof *mobj);
83         mobj[0] = metaobj_sgi();
84         mobj[1] = metaobj_sflake();
85         cur_obj = 1;
86         return 0;
87 }
88
89 void game_shutdown(void)
90 {
91 }
92
93 static void update(float tsec)
94 {
95         int i, j, k;
96         float energy;
97         cgm_vec3 pos;
98         float *vox = msurf_voxels(msurf);
99
100         mobj[cur_obj]->update(mobj[cur_obj], tsec);
101
102         for(i=0; i<VOX_ZRES; i++) {
103                 pos.z = -BBOX_HZSZ + i * VOX_ZSTEP;
104                 for(j=0; j<VOX_YRES; j++) {
105                         pos.y = -BBOX_HYSZ + j * VOX_YSTEP;
106                         for(k=0; k<VOX_XRES; k++) {
107                                 pos.x = -BBOX_HXSZ + k * VOX_XSTEP;
108
109                                 /* initialize with the vertical distance for the pool */
110                                 energy = 5.0 / (pos.y + BBOX_HYSZ);
111                                 energy += 5.0 / (pos.x + BBOX_HXSZ);
112                                 energy += 5.0 / (BBOX_HXSZ - pos.x);
113
114                                 energy += mobj[cur_obj]->eval(mobj[cur_obj], &pos);
115
116                                 *vox++ = energy;
117                         }
118                 }
119         }
120
121         msurf_polygonize(msurf);
122 }
123
124 void game_draw(void)
125 {
126         unsigned long msec = game_getmsec();
127         float tsec = (float)msec / 1000.0f;
128
129         update(tsec);
130
131         g3d_clear(G3D_COLOR_BUFFER_BIT | G3D_DEPTH_BUFFER_BIT);
132
133         g3d_matrix_mode(G3D_MODELVIEW);
134         g3d_load_identity();
135         g3d_translate(0, 1, -14);
136         g3d_rotate(cam_phi, 1, 0, 0);
137         g3d_rotate(cam_theta, 0, 1, 0);
138
139         draw_metaballs();
140
141         game_swap_buffers();
142 }
143
144 static void draw_metaballs(void)
145 {
146         int i, nverts, vbuf_count;
147         float *varr, *narr;
148         struct g3d_vertex *vbptr;
149         static int nfrm;
150
151         nverts = msurf_vertex_count(msurf);
152         varr = msurf_vertices(msurf);
153         narr = msurf_normals(msurf);
154
155         vbptr = vbuf;
156         for(i=0; i<nverts; i++) {
157                 vbuf_count = vbptr - vbuf;
158                 if(vbuf_count >= VBUF_SIZE) {
159                         g3d_draw(G3D_TRIANGLES, vbuf, vbuf_count);
160                         vbptr = vbuf;
161                 }
162                 vbptr->x = varr[0];
163                 vbptr->y = varr[1];
164                 vbptr->z = varr[2];
165                 vbptr->w = 1.0f;
166                 vbptr->nx = narr[0];
167                 vbptr->ny = narr[1];
168                 vbptr->nz = narr[2];
169                 vbptr->w = 1.0f;
170                 vbptr->l = 255;
171                 vbptr++;
172                 varr += 3;
173                 narr += 3;
174         }
175
176         if(vbptr > vbuf) {
177                 g3d_draw(G3D_TRIANGLES, vbuf, vbptr - vbuf);
178         }
179
180         nfrm++;
181 }
182
183 void game_keyboard(int key, int press)
184 {
185         if(key == 27) game_quit();
186 }
187
188 void game_mouse(int bn, int press, int x, int y)
189 {
190         mousebn[bn] = press;
191         mousex = x;
192         mousey = y;
193
194         if(bn == 0) {
195                 if(press && !grabbed) {
196                         grabbed = 1;
197                 } else if(!press && grabbed) {
198                         grabbed = 0;
199                 }
200         }
201 }
202
203 void game_motion(int x, int y)
204 {
205         int dx = x - mousex;
206         int dy = y - mousey;
207         mousex = x;
208         mousey = y;
209
210         if((dx | dy) == 0) return;
211
212         if(mousebn[0]) {
213                 if(grabbed) {
214                         mobj[cur_obj]->pos.x += dx * 0.1;
215                         mobj[cur_obj]->pos.y -= dy * 0.1;
216                 }
217         }
218         if(mousebn[2]) {
219                 cam_theta += (float)dx * (0.6f * 1.333333333f);
220                 cam_phi += (float)dy * 0.6f;
221                 if(cam_phi < -90) cam_phi = -90;
222                 if(cam_phi > 90) cam_phi = 90;
223         }
224 }