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