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