f9d49002fe7dfc51f26718a048d4769290678733
[dosdemo] / src / demo.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <math.h>
5 #include <ctype.h>
6 #include <errno.h>
7 #include <limits.h>
8 #include "demo.h"
9 #include "screen.h"
10 #include "3dgfx.h"
11 #include "audio.h"
12 #include "cfgopt.h"
13 #include "console.h"
14 #include "tinyfps.h"
15 #include "util.h"
16
17 #define MOUSE_TIMEOUT   1200
18
19 #define GUARD_XPAD      0
20 #define GUARD_YPAD      32
21
22 int fb_width, fb_height, fb_bpp, fb_scan_size;
23 float fb_aspect;
24 long fb_size, fb_buf_size;
25 uint16_t *fb_pixels, *vmem;
26 uint16_t *fb_buf;
27
28 unsigned long time_msec;
29 int mouse_x, mouse_y;
30 unsigned int mouse_bmask;
31
32 static struct au_module *mod;
33
34 float sball_matrix[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
35
36 static unsigned long last_mouse_move;
37 static int prev_mx, prev_my, mouse_dx, mouse_dy;
38 static unsigned int bmask_diff, prev_bmask;
39
40 static unsigned long nframes;
41 static int con_active;
42
43 extern uint16_t loading_pixels[];       /* data.asm */
44
45
46 int demo_init(int argc, char **argv)
47 {
48         struct screen *scr;
49         char *env;
50
51         if(load_config("demo.cfg") == -1) {
52                 return -1;
53         }
54         if((env = getenv("START_SCR"))) {
55                 opt.start_scr = env;
56         }
57         if(parse_args(argc, argv) == -1) {
58                 return -1;
59         }
60
61         /* reuse the loading image as our back buffer.
62          * adjust fb_pixels to leave 4 pixels guard band top/bottom. We have enough
63          * space since the loading image is 8 pixels taller.
64          */
65         fb_pixels = loading_pixels + 320 * 4;
66
67         con_init();
68         initFpsFonts();
69
70         if(g3d_init() == -1) {
71                 return -1;
72         }
73         g3d_framebuffer(FB_WIDTH, FB_HEIGHT, fb_pixels);
74
75         if(opt.music) {
76                 if(!(mod = au_load_module("data/test.mod"))) {
77                         return -1;
78                 }
79         }
80
81         if(scr_init() == -1) {
82                 return -1;
83         }
84         if(opt.start_scr) {
85                 scr = scr_lookup(opt.start_scr);
86         } else {
87                 scr = scr_screen(0);
88         }
89
90         if(!scr || scr_change(scr, 4000) == -1) {
91                 fprintf(stderr, "screen %s not found\n", opt.start_scr ? opt.start_scr : "0");
92                 return -1;
93         }
94
95         /* clear the framebuffer at least once */
96         memset(fb_pixels, 0, FB_WIDTH * FB_HEIGHT * FB_BPP / CHAR_BIT);
97
98         if(opt.music) {
99                 au_play_module(mod);
100         }
101         return 0;
102 }
103
104 void demo_cleanup(void)
105 {
106         if(opt.music) {
107                 au_free_module(mod);
108         }
109         scr_shutdown();
110         g3d_destroy();
111
112         if(time_msec) {
113                 float fps = (float)nframes / ((float)time_msec / 1000.0f);
114                 printf("average framerate: %.1f\n", fps);
115         }
116 }
117
118 int demo_resizefb(int width, int height, int bpp)
119 {
120         int newsz, new_scansz;
121
122         if(!width || !height || !bpp) {
123                 free(fb_buf);
124                 fb_buf = fb_pixels = 0;
125                 fb_size = fb_buf_size = fb_scan_size = 0;
126                 fb_width = fb_height = fb_bpp = 0;
127                 return 0;
128         }
129
130         new_scansz = ((width + GUARD_XPAD * 2) * bpp + 7) / 8;
131         newsz = (height + GUARD_YPAD * 2) * new_scansz;
132
133         if(!fb_buf || newsz > fb_buf_size) {
134                 void *tmp = malloc(newsz);
135                 if(!tmp) return -1;
136
137                 free(fb_buf);
138                 fb_buf = tmp;
139                 fb_buf_size = newsz;
140         }
141
142         fb_scan_size = new_scansz;
143         fb_pixels = (uint16_t*)((char*)fb_buf + GUARD_YPAD * fb_scan_size + (GUARD_XPAD * bpp + 7) / 8);
144         fb_width = width;
145         fb_height = height;
146         fb_bpp = bpp;
147         fb_size = fb_scan_size * fb_height;
148
149         fb_aspect = (float)fb_width / (float)fb_height;
150
151         return 0;
152 }
153
154
155 void demo_draw(void)
156 {
157         if(opt.mouse) {
158                 mouse_dx = mouse_x - prev_mx;
159                 mouse_dy = mouse_y - prev_my;
160                 prev_mx = mouse_x;
161                 prev_my = mouse_y;
162                 bmask_diff = mouse_bmask ^ prev_bmask;
163                 prev_bmask = mouse_bmask;
164                 if(mouse_dx | mouse_dy) {
165                         last_mouse_move = time_msec;
166                 }
167         }
168
169         if(opt.music) {
170                 au_update();
171         }
172         scr_update();
173         scr_draw();
174
175         ++nframes;
176 }
177
178 /* called by swap_buffers just before the actual swap */
179 void demo_post_draw(void *pixels)
180 {
181         char buf[32];
182         if(opt.dbginfo) {
183                 drawFps(pixels);
184                 if(dbg_curscr_name) {
185                         cs_dputs(pixels, dbg_curscr_name_pos, 240 - 16, dbg_curscr_name);
186                 }
187         }
188
189         if(con_active) {
190                 con_draw(pixels);
191         }
192
193         if(opt.mouse && time_msec - last_mouse_move < MOUSE_TIMEOUT) {
194                 cs_mouseptr(pixels, mouse_x, mouse_y);
195         }
196 }
197
198 void cs_puts_font(cs_font_func csfont, int sz, void *fb, int x, int y, const char *str)
199 {
200         while(*str) {
201                 int c = *str++;
202
203                 if(c > ' ' && c < 128) {
204                         csfont(fb, x, y, c - ' ');
205                 }
206                 x += sz;
207         }
208 }
209
210 void change_screen(int idx)
211 {
212         printf("change screen %d\n", idx);
213         scr_change(scr_screen(idx), 4000);
214 }
215
216 void demo_keyboard(int key, int press)
217 {
218         int nscr;
219
220         if(press) {
221                 switch(key) {
222                 case 27:
223                         if(con_active) {
224                                 con_stop();
225                                 con_active = 0;
226                         } else {
227                                 demo_quit();
228                         }
229                         return;
230
231                 case 127:
232                         debug_break();
233                         return;
234
235                 case '`':
236                         con_active = !con_active;
237                         if(con_active) {
238                                 con_start();
239                         } else {
240                                 con_stop();
241                         }
242                         return;
243
244                 case '/':
245                         if(!con_active) {
246                                 con_start();
247                                 con_active = con_input('/');
248                                 return;
249                         }
250
251                 default:
252                         if(con_active) {
253                                 con_active = con_input(key);
254                                 return;
255                         }
256
257                         if(key >= '1' && key <= '9' && key <= '1' + scr_num_screens()) {
258                                 change_screen(key - '1');
259                                 return;
260                         } else if(key == '0' && scr_num_screens() >= 10) {
261                                 change_screen(9);
262                                 return;
263                         }
264                 }
265
266                 scr_keypress(key);
267         }
268 }
269
270
271 void mouse_orbit_update(float *theta, float *phi, float *dist)
272 {
273         if(mouse_bmask) {
274                 if(bmask_diff == 0) {
275
276                         if(mouse_dx | mouse_dy) {
277                                 if(mouse_bmask & MOUSE_BN_LEFT) {
278                                         float p = *phi;
279                                         *theta += mouse_dx * 1.0;
280                                         p += mouse_dy * 1.0;
281
282                                         if(p < -90) p = -90;
283                                         if(p > 90) p = 90;
284                                         *phi = p;
285                                 }
286                                 if(mouse_bmask & MOUSE_BN_RIGHT) {
287                                         *dist += mouse_dy * 0.5;
288
289                                         if(*dist < 0) *dist = 0;
290                                 }
291                         }
292                 }
293         }
294 }