reorganized the source code
[dosdemo] / src / scr / 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 #include "mesh.h"
13
14 struct metaball {
15         float energy;
16         float pos[3];
17 };
18
19 static int init(void);
20 static void destroy(void);
21 static void start(long trans_time);
22 static void draw(void);
23
24 static void calc_voxel_field(void);
25
26 static struct screen scr = {
27         "metaballs",
28         init,
29         destroy,
30         start, 0,
31         draw
32 };
33
34 static float cam_theta, cam_phi = 25;
35 static float cam_dist = 10;
36 static struct g3d_mesh mmesh;
37
38 static struct metasurface *msurf;
39
40 #define VOL_SZ  32
41 #define VOL_SCALE       10.0f
42 #define VOX_DIST        (VOL_SCALE / VOL_SZ)
43 #define VOL_HALF_SCALE  (VOL_SCALE * 0.5f)
44
45 #define NUM_MBALLS      3
46 static struct metaball mball[NUM_MBALLS];
47
48 static int dbg;
49
50 struct screen *metaballs_screen(void)
51 {
52         return &scr;
53 }
54
55 static int init(void)
56 {
57         mball[0].energy = 1.2;
58         mball[1].energy = 0.8;
59         mball[2].energy = 1.0;
60
61         if(!(msurf = msurf_create())) {
62                 fprintf(stderr, "failed to initialize metasurf\n");
63                 return -1;
64         }
65         msurf_set_resolution(msurf, VOL_SZ, VOL_SZ, VOL_SZ);
66         msurf_set_bounds(msurf, -VOL_HALF_SCALE, -VOL_HALF_SCALE, -VOL_HALF_SCALE,
67                         VOL_HALF_SCALE, VOL_HALF_SCALE, VOL_HALF_SCALE);
68         msurf_set_threshold(msurf, 1.7);
69         msurf_set_inside(msurf, MSURF_GREATER);
70
71         mmesh.prim = G3D_TRIANGLES;
72         mmesh.varr = 0;
73         mmesh.iarr = 0;
74         mmesh.vcount = mmesh.icount = 0;
75
76         return 0;
77 }
78
79 static void destroy(void)
80 {
81         msurf_free(msurf);
82 }
83
84 static void start(long trans_time)
85 {
86         g3d_matrix_mode(G3D_PROJECTION);
87         g3d_load_identity();
88         g3d_perspective(50.0, 1.3333333, 0.5, 100.0);
89
90         g3d_enable(G3D_CULL_FACE);
91         g3d_enable(G3D_LIGHTING);
92         g3d_enable(G3D_LIGHT0);
93
94         g3d_polygon_mode(G3D_GOURAUD);
95 }
96
97 static void update(void)
98 {
99         int i, j;
100         float tsec = time_msec / 1000.0f;
101         static float phase[] = {0.0, M_PI / 3.0, M_PI * 0.8};
102         static float speed[] = {0.8, 1.4, 1.0};
103         static float scale[][3] = {{1, 2, 0.8}, {0.5, 1.6, 0.6}, {1.5, 0.7, 0.5}};
104         static float offset[][3] = {{0, 0, 0}, {0.25, 0, 0}, {-0.2, 0.15, 0.2}};
105
106         mouse_orbit_update(&cam_theta, &cam_phi, &cam_dist);
107
108         for(i=0; i<NUM_MBALLS; i++) {
109                 float t = (tsec + phase[i]) * speed[i];
110
111                 for(j=0; j<3; j++) {
112                         float x = sin(t + j * M_PI / 2.0);
113                         mball[i].pos[j] = offset[i][j] + x * scale[i][j];
114                 }
115         }
116
117         calc_voxel_field();
118         msurf_polygonize(msurf);
119
120         mmesh.vcount = msurf_vertex_count(msurf);
121         mmesh.varr = msurf_vertices(msurf);
122 }
123
124 static void draw(void)
125 {
126         int i, j;
127
128         update();
129
130         memset(fb_pixels, 0, fb_width * fb_height * 2);
131
132         for(i=0; i<120; i++) {
133                 for(j=0; j<160; j++) {
134                         fb_pixels[(i + 60) * 320 + (j + 80)] = 0x1e7;
135                 }
136         }
137         g3d_viewport(80, 60, 160, 120);
138
139         g3d_matrix_mode(G3D_MODELVIEW);
140         g3d_load_identity();
141         g3d_translate(0, 0, -cam_dist);
142         g3d_rotate(cam_phi, 1, 0, 0);
143         g3d_rotate(cam_theta, 0, 1, 0);
144
145         g3d_light_pos(0, -10, 10, 20);
146
147         zsort_mesh(&mmesh);
148
149         g3d_mtl_diffuse(0.6, 0.6, 0.6);
150
151         draw_mesh(&mmesh);
152
153         g3d_viewport(0, 0, fb_width, fb_height);
154
155         swap_buffers(fb_pixels);
156 }
157
158 static void calc_voxel_field(void)
159 {
160         int i, j, k, b;
161         float *voxptr;
162
163         if(!(voxptr = msurf_voxels(msurf))) {
164                 fprintf(stderr, "failed to allocate voxel field\n");
165                 abort();
166         }
167
168         for(i=0; i<VOL_SZ; i++) {
169                 float z = -VOL_HALF_SCALE + i * VOX_DIST;
170
171                 for(j=0; j<VOL_SZ; j++) {
172                         float y = -VOL_HALF_SCALE + j * VOX_DIST;
173
174                         for(k=0; k<VOL_SZ; k++) {
175                                 float x = -VOL_HALF_SCALE + k * VOX_DIST;
176
177                                 float val = 0.0f;
178                                 for(b=0; b<NUM_MBALLS; b++) {
179                                         float dx = mball[b].pos[0] - x;
180                                         float dy = mball[b].pos[1] - y;
181                                         float dz = mball[b].pos[2] - z;
182
183                                         float lensq = dx * dx + dy * dy + dz * dz;
184
185                                         val += lensq == 0.0f ? 1024.0f : mball[b].energy / lensq;
186                                 }
187
188                                 *voxptr++ = val;
189                         }
190                 }
191         }
192         ++dbg;
193 }