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