working on the cyberspace part
[dosdemo] / src / scr / cybersun.c
1 #include <stdio.h>
2 #include <math.h>
3 #include <assert.h>
4 #include "demo.h"
5 #include "3dgfx.h"
6 #include "screen.h"
7 #include "gfxutil.h"
8 #include "mesh.h"
9 #include "image.h"
10 #include "util.h"
11 #include "cgmath/cgmath.h"
12
13 #define TM_RIPPLE_START         1.0f
14 #define TM_RIPPLE_TRANS_LEN     3.0f
15
16 #define VFOV    50.0f
17 #define HFOV    (VFOV * 1.333333f)
18
19 static int init(void);
20 static void destroy(void);
21 static void start(long trans_time);
22 static void draw(void);
23 static void draw_mountains(void);
24
25 static struct screen scr = {
26         "cybersun",
27         init,
28         destroy,
29         start,
30         0,
31         draw
32 };
33
34 static float cam_theta = 0, cam_phi = 0;
35 static float cam_dist = 0;
36
37 static struct g3d_mesh gmesh;
38 #define GMESH_GRIDSZ    25
39 #define GMESH_SIZE              128
40 static struct image gtex;
41
42 static struct image mounttex;
43
44 static long part_start;
45
46
47 struct screen *cybersun_screen(void)
48 {
49         return &scr;
50 }
51
52 static int init(void)
53 {
54         int i, j;
55
56         if(gen_plane_mesh(&gmesh, GMESH_SIZE, GMESH_SIZE, GMESH_GRIDSZ, GMESH_GRIDSZ) == -1) {
57                 return -1;
58         }
59         for(i=0; i<gmesh.vcount; i++) {
60                 gmesh.varr[i].u *= GMESH_GRIDSZ;
61                 gmesh.varr[i].v *= GMESH_GRIDSZ;
62         }
63         if(load_image(&gtex, "data/pgrid.png") == -1) {
64                 return -1;
65         }
66         if(load_image(&mounttex, "data/cybmount.png") == -1) {
67                 return -1;
68         }
69         assert(mounttex.width == 512);
70         assert(mounttex.height == 64);
71
72         return 0;
73 }
74
75 static void destroy(void)
76 {
77         destroy_mesh(&gmesh);
78         destroy_image(&gtex);
79         destroy_image(&mounttex);
80 }
81
82 static void start(long trans_time)
83 {
84         g3d_matrix_mode(G3D_PROJECTION);
85         g3d_load_identity();
86         g3d_perspective(VFOV, 1.3333333, 0.5, 500.0);
87
88         g3d_enable(G3D_CULL_FACE);
89
90         g3d_clear_color(85, 70, 136);
91
92         part_start = time_msec;
93 }
94
95 static void update(void)
96 {
97         int i, j;
98         float t = (time_msec - part_start) / 1000.0f;
99         struct g3d_vertex *vptr;
100
101         float ampl = cgm_smoothstep(TM_RIPPLE_START, TM_RIPPLE_START + TM_RIPPLE_TRANS_LEN, t);
102
103         mouse_orbit_update(&cam_theta, &cam_phi, &cam_dist);
104
105         /* update mesh */
106         vptr = gmesh.varr;
107         for(i=0; i<GMESH_GRIDSZ + 1; i++) {
108                 for(j=0; j<GMESH_GRIDSZ + 1; j++) {
109                         float u = (float)j / GMESH_GRIDSZ - 0.5f;
110                         float v = (float)i / GMESH_GRIDSZ - 0.5f;
111                         float x = u * 32.0f;
112                         float y = v * 32.0f;
113                         float r = sqrt(x * x + y * y);
114
115                         vptr->z = sin(x * 0.5 + t) + cos(x * 0.8f) * 0.5f;
116                         vptr->z += cos(y * 0.5 + t);
117                         vptr->z += sin(r + t) * 0.5f;
118                         vptr->z *= r * 0.1f > 1.0f ? 1.0f : r * 0.1f;
119                         vptr->z *= ampl;
120                         vptr++;
121                 }
122         }
123 }
124
125 static void draw(void)
126 {
127         int i;
128
129         update();
130
131         g3d_matrix_mode(G3D_MODELVIEW);
132         g3d_load_identity();
133         g3d_translate(0, -2, -cam_dist);
134         g3d_rotate(cam_phi, 1, 0, 0);
135         g3d_rotate(cam_theta, 0, 1, 0);
136         if(opt.sball) {
137                 g3d_mult_matrix(sball_matrix);
138         }
139
140         g3d_clear(G3D_COLOR_BUFFER_BIT | G3D_DEPTH_BUFFER_BIT);
141         draw_mountains();
142
143         g3d_set_texture(gtex.width, gtex.height, gtex.pixels);
144         g3d_enable(G3D_TEXTURE_2D);
145         g3d_enable(G3D_DEPTH_TEST);
146
147         g3d_push_matrix();
148         g3d_rotate(-90, 1, 0, 0);
149         draw_mesh(&gmesh);
150         g3d_pop_matrix();
151
152         g3d_disable(G3D_DEPTH_TEST);
153         g3d_disable(G3D_TEXTURE_2D);
154
155         swap_buffers(fb_pixels);
156 }
157
158 /* XXX all the sptr calculations assume mounttex.width == 512 */
159 static void draw_mountains(void)
160 {
161         int i, j, y;
162         int32_t x, xstart, xend, dx;
163         uint16_t *dptr, *sptr;
164
165         xstart = cround64(cam_theta * (256.0 * 512.0 / 90.0));  /* 24.8 fixed point, 512 width */
166         xend = cround64((cam_theta + HFOV) * (256.0 * 512.0 / 90.0));
167         dx = (xend - xstart) / FB_WIDTH;
168         x = xstart;
169
170         y = cround64(-cam_phi * (FB_HEIGHT / 45.0)) + (FB_HEIGHT / 2 - 64);
171
172         dptr = fb_pixels + y * FB_WIDTH;
173
174         for(i=0; i<FB_WIDTH; i++) {
175                 sptr = mounttex.pixels + ((x >> 8) & 0x1ff);
176
177                 for(j=0; j<64; j++) {
178                         if(j + y >= FB_HEIGHT) break;
179                         if(j + y >= 0) {
180                                 int32_t col = sptr[j << 9];
181                                 if(col != 0x7e0) {
182                                         dptr[j * FB_WIDTH] = col;
183                                 }
184                         }
185                 }
186                 dptr++;
187
188                 x += dx;
189         }
190
191         y += 64;
192         if(y < 0) {
193                 memset(fb_pixels, 0, FB_WIDTH * FB_HEIGHT * 2);
194         } else {
195                 if(y < FB_HEIGHT) {
196                         dptr = fb_pixels + y * FB_WIDTH;
197                         memset(dptr, 0, (FB_HEIGHT - y) * FB_WIDTH * 2);
198                 }
199         }
200 }