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