glut version: make the loading screen fullscreen if demo is going to run fullscreen
[dosdemo] / src / glut / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <ctype.h>
4 #include <assert.h>
5 #include "miniglut.h"
6 #include "demo.h"
7 #include "gfx.h"
8 #include "gfxutil.h"
9 #include "timer.h"
10 #include "audio.h"
11 #include "cfgopt.h"
12 #include "cgmath/cgmath.h"
13 #include "util.h"
14
15 static void display(void);
16 static void idle(void);
17 static void reshape(int x, int y);
18 static void keydown(unsigned char key, int x, int y);
19 static void keyup(unsigned char key, int x, int y);
20 static void skeydown(int key, int x, int y);
21 static void skeyup(int key, int x, int y);
22 static int translate_special(int skey);
23 static void mouse_button(int bn, int st, int x, int y);
24 static void mouse_motion(int x, int y);
25 static void sball_motion(int x, int y, int z);
26 static void sball_rotate(int x, int y, int z);
27 static void sball_button(int bn, int st);
28 static void recalc_sball_matrix(float *xform);
29 static unsigned int next_pow2(unsigned int x);
30 static void set_fullscreen(int fs);
31 static void set_vsync(int vsync);
32
33 int have_joy;
34 unsigned int joy_bnstate, joy_bndiff, joy_bnpress;
35
36 #define MODE(w, h)      \
37         {0, w, h, 16, w * 2, 5, 6, 5, 11, 5, 0, 0xf800, 0x7e0, 0x1f, 0xbadf00d, 2, 0}
38 static struct video_mode vmodes[] = {
39         MODE(320, 240), MODE(400, 300), MODE(512, 384), MODE(640, 480),
40         MODE(800, 600), MODE(1024, 768), MODE(1280, 960), MODE(1280, 1024),
41         MODE(1920, 1080), MODE(1600, 1200), MODE(1920, 1200)
42 };
43 static struct video_mode *cur_vmode;
44
45 static unsigned int num_pressed;
46 static unsigned char keystate[256];
47
48 static unsigned long start_time;
49 static unsigned int modkeys;
50
51 static int win_width, win_height;
52 static float win_aspect;
53 static unsigned int tex;
54
55 #ifdef __unix__
56 #include <GL/glx.h>
57 static Display *xdpy;
58 static Window xwin;
59
60 static void (*glx_swap_interval_ext)();
61 static void (*glx_swap_interval_sgi)();
62 #endif
63 #ifdef _WIN32
64 #include <windows.h>
65 static PROC wgl_swap_interval_ext;
66 #endif
67
68 static int use_sball;
69 static cgm_vec3 pos = {0, 0, 0};
70 static cgm_quat rot = {0, 0, 0, 1};
71
72
73 int main(int argc, char **argv)
74 {
75         glutInit(&argc, argv);
76
77         if(glutGet(GLUT_SCREEN_HEIGHT) <= 1024) {
78                 glutInitWindowSize(640, 480);
79         } else {
80                 glutInitWindowSize(1280, 960);
81         }
82         glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
83         glutCreateWindow("Mindlapse");
84
85         glutDisplayFunc(display);
86         glutIdleFunc(idle);
87         glutReshapeFunc(reshape);
88         glutKeyboardFunc(keydown);
89         glutKeyboardUpFunc(keyup);
90         glutSpecialFunc(skeydown);
91         glutSpecialUpFunc(skeyup);
92         glutMouseFunc(mouse_button);
93         glutMotionFunc(mouse_motion);
94         glutPassiveMotionFunc(mouse_motion);
95         glutSpaceballMotionFunc(sball_motion);
96         glutSpaceballRotateFunc(sball_rotate);
97         glutSpaceballButtonFunc(sball_button);
98
99         glutSetCursor(GLUT_CURSOR_NONE);
100
101         glEnable(GL_TEXTURE_2D);
102         glEnable(GL_CULL_FACE);
103
104
105         if(!set_video_mode(match_video_mode(FB_WIDTH, FB_HEIGHT, FB_BPP), 1)) {
106                 return 1;
107         }
108
109 #ifdef __unix__
110         xdpy = glXGetCurrentDisplay();
111         xwin = glXGetCurrentDrawable();
112
113         if(!(glx_swap_interval_ext = glXGetProcAddress((unsigned char*)"glXSwapIntervalEXT"))) {
114                 glx_swap_interval_sgi = glXGetProcAddress((unsigned char*)"glXSwapIntervalSGI");
115         }
116 #endif
117 #ifdef _WIN32
118         wgl_swap_interval_ext = wglGetProcAddress("wglSwapIntervalEXT");
119 #endif
120
121         if(au_init() == -1) {
122                 return 1;
123         }
124         time_msec = 0;
125         if(demo_init1(argc, argv) == -1) {
126                 return 1;
127         }
128
129         if(opt.fullscreen) {
130                 set_fullscreen(opt.fullscreen);
131                 reshape(glutGet(GLUT_SCREEN_WIDTH), glutGet(GLUT_SCREEN_HEIGHT));
132         } else {
133                 reshape(glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT));
134         }
135
136         if(demo_init2() == -1) {
137                 return 1;
138         }
139         atexit(demo_cleanup);
140
141         reset_timer();
142
143         glutMainLoop();
144         return 0;
145 }
146
147 void demo_quit(void)
148 {
149         exit(0);
150 }
151
152 struct video_mode *video_modes(void)
153 {
154         return vmodes;
155 }
156
157 int num_video_modes(void)
158 {
159         return sizeof vmodes / sizeof *vmodes;
160 }
161
162 struct video_mode *get_video_mode(int idx)
163 {
164         if(idx == VMODE_CURRENT) {
165                 return cur_vmode;
166         }
167         return vmodes + idx;
168 }
169
170 int match_video_mode(int xsz, int ysz, int bpp)
171 {
172         struct video_mode *vm = vmodes;
173         int i, count = num_video_modes();
174
175         for(i=0; i<count; i++) {
176                 if(vm->xsz == xsz && vm->ysz == ysz && vm->bpp == bpp) {
177                         return i;
178                 }
179                 vm++;
180         }
181         return -1;
182 }
183
184 static int tex_xsz, tex_ysz;
185 static uint32_t *convbuf;
186 static int convbuf_size;
187
188 void *set_video_mode(int idx, int nbuf)
189 {
190         struct video_mode *vm = vmodes + idx;
191
192         if(cur_vmode == vm) {
193                 return vmem;
194         }
195
196         glGenTextures(1, &tex);
197         glBindTexture(GL_TEXTURE_2D, tex);
198
199         tex_xsz = next_pow2(vm->xsz);
200         tex_ysz = next_pow2(vm->ysz);
201         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_xsz, tex_ysz, 0, GL_RGBA,
202                         GL_UNSIGNED_BYTE, 0);
203         if(opt.scaler == SCALER_LINEAR) {
204                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
205                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
206         } else {
207                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
208                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
209         }
210
211         glMatrixMode(GL_TEXTURE);
212         glLoadIdentity();
213         glScalef((float)vm->xsz / tex_xsz, (float)vm->ysz / tex_ysz, 1);
214
215         if(vm->xsz * vm->ysz > convbuf_size) {
216                 convbuf_size = vm->xsz * vm->ysz;
217                 free(convbuf);
218                 convbuf = malloc(convbuf_size * sizeof *convbuf);
219         }
220
221         if(demo_resizefb(vm->xsz, vm->ysz, vm->bpp) == -1) {
222                 fprintf(stderr, "failed to allocate virtual framebuffer\n");
223                 return 0;
224         }
225         vmem = fb_pixels;
226
227         cur_vmode = vm;
228         return vmem;
229 }
230
231 void wait_vsync(void)
232 {
233 }
234
235 void blit_frame(void *pixels, int vsync)
236 {
237         int i;
238         uint32_t *dptr = convbuf;
239         uint16_t *sptr = pixels;
240         static int prev_vsync = -1;
241
242         if(vsync != prev_vsync) {
243                 set_vsync(vsync);
244                 prev_vsync = vsync;
245         }
246
247         demo_post_draw(pixels);
248
249         for(i=0; i<FB_WIDTH * FB_HEIGHT; i++) {
250                 int r = UNPACK_R16(*sptr);
251                 int g = UNPACK_G16(*sptr);
252                 int b = UNPACK_B16(*sptr);
253                 *dptr++ = PACK_RGB32(b, g, r);
254                 sptr++;
255         }
256
257         glBindTexture(GL_TEXTURE_2D, tex);
258         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, FB_WIDTH, FB_HEIGHT, GL_RGBA,
259                         GL_UNSIGNED_BYTE, convbuf);
260
261         glMatrixMode(GL_MODELVIEW);
262         glLoadIdentity();
263         if(win_aspect >= FB_ASPECT) {
264                 glScalef(FB_ASPECT / win_aspect, 1, 1);
265         } else {
266                 glScalef(1, win_aspect / FB_ASPECT, 1);
267         }
268
269         glClear(GL_COLOR_BUFFER_BIT);
270
271         glBegin(GL_QUADS);
272         glTexCoord2f(0, 1);
273         glVertex2f(-1, -1);
274         glTexCoord2f(1, 1);
275         glVertex2f(1, -1);
276         glTexCoord2f(1, 0);
277         glVertex2f(1, 1);
278         glTexCoord2f(0, 0);
279         glVertex2f(-1, 1);
280         glEnd();
281
282         glutSwapBuffers();
283         assert(glGetError() == GL_NO_ERROR);
284 }
285
286 int kb_isdown(int key)
287 {
288         switch(key) {
289         case KB_ANY:
290                 return num_pressed;
291
292         case KB_ALT:
293                 return keystate[KB_LALT] + keystate[KB_RALT];
294
295         case KB_CTRL:
296                 return keystate[KB_LCTRL] + keystate[KB_RCTRL];
297         }
298
299         if(isalpha(key)) {
300                 key = tolower(key);
301         }
302         return keystate[key];
303 }
304
305 /* timer */
306 void init_timer(int res_hz)
307 {
308 }
309
310 void reset_timer(void)
311 {
312         start_time = glutGet(GLUT_ELAPSED_TIME);
313 }
314
315 unsigned long get_msec(void)
316 {
317         return glutGet(GLUT_ELAPSED_TIME) - start_time;
318 }
319
320 #ifdef _WIN32
321 #include <windows.h>
322
323 void sleep_msec(unsigned long msec)
324 {
325         Sleep(msec);
326 }
327
328 #else
329 #include <unistd.h>
330
331 void sleep_msec(unsigned long msec)
332 {
333         usleep(msec * 1000);
334 }
335 #endif
336
337 static void display(void)
338 {
339         recalc_sball_matrix(sball_matrix);
340
341         time_msec = get_msec();
342         demo_draw();
343 }
344
345 static void idle(void)
346 {
347         glutPostRedisplay();
348 }
349
350 static void reshape(int x, int y)
351 {
352         win_width = x;
353         win_height = y;
354         win_aspect = (float)x / (float)y;
355         glViewport(0, 0, x, y);
356 }
357
358 static void keydown(unsigned char key, int x, int y)
359 {
360         modkeys = glutGetModifiers();
361
362         if((key == '\n' || key == '\r') && (modkeys & GLUT_ACTIVE_ALT)) {
363                 opt.fullscreen ^= 1;
364                 set_fullscreen(opt.fullscreen);
365                 return;
366         }
367         keystate[key] = 1;
368         demo_keyboard(key, 1);
369 }
370
371 static void keyup(unsigned char key, int x, int y)
372 {
373         keystate[key] = 0;
374         demo_keyboard(key, 0);
375 }
376
377 static void skeydown(int key, int x, int y)
378 {
379         if(key == GLUT_KEY_F5) {
380                 opt.scaler = (opt.scaler + 1) % NUM_SCALERS;
381
382                 if(opt.scaler == SCALER_LINEAR) {
383                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
384                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
385                 } else {
386                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
387                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
388                 }
389         }
390         key = translate_special(key);
391         keystate[key] = 1;
392         demo_keyboard(key, 1);
393 }
394
395 static void skeyup(int key, int x, int y)
396 {
397         key = translate_special(key);
398         keystate[key] = 0;
399         demo_keyboard(key, 0);
400 }
401
402 static int translate_special(int skey)
403 {
404         switch(skey) {
405         case 127:
406                 return 127;
407         case GLUT_KEY_LEFT:
408                 return KB_LEFT;
409         case GLUT_KEY_RIGHT:
410                 return KB_RIGHT;
411         case GLUT_KEY_UP:
412                 return KB_UP;
413         case GLUT_KEY_DOWN:
414                 return KB_DOWN;
415         case GLUT_KEY_PAGE_UP:
416                 return KB_PGUP;
417         case GLUT_KEY_PAGE_DOWN:
418                 return KB_PGDN;
419         case GLUT_KEY_HOME:
420                 return KB_HOME;
421         case GLUT_KEY_END:
422                 return KB_END;
423         default:
424                 if(skey >= GLUT_KEY_F1 && skey <= GLUT_KEY_F12) {
425                         return KB_F1 + skey - GLUT_KEY_F1;
426                 }
427         }
428         return 0;
429 }
430
431 static void map_mouse_pos(int *xp, int *yp)
432 {
433         int x = *xp;
434         int y = *yp;
435
436         /* TODO */
437         *xp = x * FB_WIDTH / win_width;
438         *yp = y * FB_HEIGHT / win_height;
439 }
440
441 static void mouse_button(int bn, int st, int x, int y)
442 {
443         int bit;
444
445         map_mouse_pos(&x, &y);
446         mouse_x = x;
447         mouse_y = y;
448
449         switch(bn) {
450         case GLUT_LEFT_BUTTON:
451                 bit = 0;
452                 break;
453         case GLUT_RIGHT_BUTTON:
454                 bit = 1;
455                 break;
456         case GLUT_MIDDLE_BUTTON:
457                 bit = 2;
458                 break;
459         }
460
461         if(st == GLUT_DOWN) {
462                 mouse_bmask |= 1 << bit;
463         } else {
464                 mouse_bmask &= ~(1 << bit);
465         }
466 }
467
468 static void mouse_motion(int x, int y)
469 {
470         map_mouse_pos(&x, &y);
471         mouse_x = x;
472         mouse_y = y;
473 }
474
475 static void sball_motion(int x, int y, int z)
476 {
477         pos.x += x * 0.001f;
478         pos.y += y * 0.001f;
479         pos.z -= z * 0.001f;
480
481 }
482
483 static void sball_rotate(int rx, int ry, int rz)
484 {
485         if(rx | ry | rz) {
486                 float s = (float)rsqrt(rx * rx + ry * ry + rz * rz);
487                 cgm_qrotate(&rot, 0.001f / s, rx * s, ry * s, -rz * s);
488         }
489 }
490
491 static void sball_button(int bn, int st)
492 {
493         pos.x = pos.y = pos.z = 0;
494         rot.x = rot.y = rot.z = 0;
495         rot.w = 1;
496 }
497
498 static void recalc_sball_matrix(float *xform)
499 {
500         cgm_mrotation_quat(xform, &rot);
501         xform[12] = pos.x;
502         xform[13] = pos.y;
503         xform[14] = pos.z;
504 }
505
506
507 static unsigned int next_pow2(unsigned int x)
508 {
509         x--;
510         x |= x >> 1;
511         x |= x >> 2;
512         x |= x >> 4;
513         x |= x >> 8;
514         x |= x >> 16;
515         return x + 1;
516 }
517
518 static void set_fullscreen(int fs)
519 {
520         static int win_x, win_y;
521
522         if(fs) {
523                 win_x = glutGet(GLUT_WINDOW_WIDTH);
524                 win_y = glutGet(GLUT_WINDOW_HEIGHT);
525                 glutFullScreen();
526         } else {
527                 glutReshapeWindow(win_x, win_y);
528         }
529 }
530
531 #ifdef __unix__
532 static void set_vsync(int vsync)
533 {
534         vsync = vsync ? 1 : 0;
535         if(glx_swap_interval_ext) {
536                 glx_swap_interval_ext(xdpy, xwin, vsync);
537         } else if(glx_swap_interval_sgi) {
538                 glx_swap_interval_sgi(vsync);
539         }
540 }
541 #endif
542 #ifdef WIN32
543 static void set_vsync(int vsync)
544 {
545         if(wgl_swap_interval_ext) {
546                 wgl_swap_interval_ext(vsync ? 1 : 0);
547         }
548 }
549 #endif