GLUT on fbdev driver. Sean D'Epagnier
[mesa.git] / src / glut / fbdev / glut_fbdev.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5
4 * Copyright (C) 1995-2006 Brian Paul
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the Free
18 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 /*
22 * Library for glut using mesa fbdev driver
23 *
24 * Written by Sean D'Epagnier (c) 2006
25 */
26
27 #include <assert.h>
28 #include <errno.h>
29 #include <signal.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <termios.h>
36 #include <inttypes.h>
37
38 #include <sys/ioctl.h>
39 #include <sys/mman.h>
40 #include <sys/types.h>
41 #include <sys/time.h>
42 #include <sys/poll.h>
43 #include <sys/types.h>
44 #include <sys/kd.h>
45
46 #include <linux/fb.h>
47 #include <linux/keyboard.h>
48 #include <linux/vt.h>
49
50 #include <GL/gl.h>
51 #include <GL/glfbdev.h>
52 #include <GL/glut.h>
53
54 #include <math.h>
55
56 #include "../../mesa/main/config.h"
57
58 #define MULTIHEAD /* enable multihead hacks,
59 it allows the program to continue drawing
60 without reading input when a second fbdev
61 has keyboard focus it can cause
62 screen corruption that requires C-l to fix */
63
64 #define FBMODES "/etc/fb.modes"
65
66 #define HAVE_GPM
67
68 #ifdef HAVE_GPM
69 #include <gpm.h>
70 static int GpmMouse;
71 #endif
72
73 #define MOUSEDEV "/dev/gpmdata"
74
75 static int CurrentVT;
76 static int ConsoleFD = - 1;
77
78 /* save settings to restore on exit */
79 static int OldKDMode = -1;
80 static int OldMode;
81 struct vt_mode OldVTMode;
82 struct termios OldTermios;
83
84 static struct fb_fix_screeninfo FixedInfo;
85 static struct fb_var_screeninfo VarInfo, OrigVarInfo;
86 struct fb_cmap ColorMap;
87
88 static int DesiredDepth = 0;
89
90 static int FrameBufferFD = -1;
91 static caddr_t FrameBuffer = (caddr_t) -1;
92 static caddr_t BackBuffer = NULL;
93 static int DisplayMode;
94
95 static int AccumSize = 16; /* per channel size of accumulation buffer */
96 static int DepthSize = DEFAULT_SOFTWARE_DEPTH_BITS;
97 static int StencilSize = STENCIL_BITS;
98
99 #define MENU_FONT_WIDTH 9
100 #define MENU_FONT_HEIGHT 15
101 #define MENU_FONT GLUT_BITMAP_9_BY_15
102 #define SUBMENU_OFFSET 20
103
104 static int AttachedMenus[3];
105 static int ActiveMenu;
106 static int SelectedMenu;
107 static int CurrentMenu;
108 static int NumMenus = 1;
109
110 static struct {
111 int NumItems;
112 int x, y;
113 int width;
114 int selected;
115 struct {
116 int value;
117 int submenu;
118 char *name;
119 } *Items;
120 void (*func)(int);
121 } *Menus = NULL;
122
123 struct GlutTimer {
124 int time;
125 void (*func)(int);
126 int value;
127 struct GlutTimer *next;
128 };
129
130 struct GlutTimer *GlutTimers = NULL;
131
132 static struct timeval StartTime;
133
134 static int KeyboardModifiers;
135 static int KeyboardLedState;
136
137 static int MouseFD;
138 static int NumMouseButtons;
139 static int MouseX;
140 static int MouseY;
141 static double MouseSpeed = 0;
142 static int CurrentCursor = GLUT_CURSOR_LEFT_ARROW;
143 /* only display the mouse if there is a registered callback for it */
144 static int MouseEnabled = 0;
145
146 /* per window data */
147 static GLFBDevContextPtr Context;
148 static GLFBDevBufferPtr Buffer;
149 static GLFBDevVisualPtr Visual;
150 static void (*DisplayFunc)(void) = NULL;
151 static void (*ReshapeFunc)(int width, int height) = NULL;
152 static void (*KeyboardFunc)(unsigned char key, int x, int y) = NULL;
153 static void (*MouseFunc)(int key, int state, int x, int y) = NULL;
154 static void (*MotionFunc)(int x, int y) = NULL;
155 static void (*PassiveMotionFunc)(int x, int y) = NULL;
156 static void (*VisibilityFunc)(int state) = NULL;
157 static void (*SpecialFunc)(int key, int x, int y) = NULL;
158 static void (*IdleFunc)(void) = NULL;
159 static void (*MenuStatusFunc)(int state, int x, int y) = NULL;
160 static void (*MenuStateFunc)(int state) = NULL;
161
162 static int Redisplay;
163 static int Visible;
164 static int VisibleSwitch;
165 static int Active;
166 /* we have to poll to see if we are visible
167 on a framebuffer that is not active */
168 static int VisiblePoll;
169 static int FramebufferIndex;
170
171 static int RequiredWidth;
172 static int RequiredHeight;
173 static int InitialWidthHint;
174 static int InitialHeightHint;
175
176 static char exiterror[256];
177
178 /* --------- Initialization ------------*/
179 /* test if the active console is attached to the same framebuffer */
180 static void TestVisible(void) {
181 struct fb_con2fbmap confb;
182 struct vt_stat st;
183 int ret;
184 ioctl(ConsoleFD, VT_GETSTATE, &st);
185 confb.console = st.v_active;
186
187 ret = ioctl(FrameBufferFD, FBIOGET_CON2FBMAP, &confb);
188
189 if(ret == -1 || confb.framebuffer == FramebufferIndex) {
190 VisibleSwitch = 1;
191 Visible = 0;
192 VisiblePoll = 0;
193 }
194 }
195
196 static void VTSwitchHandler(int sig)
197 {
198 struct vt_stat st;
199 switch(sig) {
200 case SIGUSR1:
201 ioctl(ConsoleFD, VT_RELDISP, 1);
202 Active = 0;
203 #ifdef MULTIHEAD
204 VisiblePoll = 1;
205 TestVisible();
206 #else
207 VisibleSwitch = 1;
208 Visible = 0;
209 #endif
210 break;
211 case SIGUSR2:
212 ioctl(ConsoleFD, VT_GETSTATE, &st);
213 if(st.v_active)
214 ioctl(ConsoleFD, VT_RELDISP, VT_ACKACQ);
215
216 /* this is a hack to turn the cursor off */
217 ioctl(FrameBufferFD, FBIOPUT_VSCREENINFO, &VarInfo);
218
219 /* restore color map */
220 if(DisplayMode & GLUT_INDEX) {
221 ColorMap.start = 0;
222 ColorMap.len = 256;
223
224 if (ioctl(FrameBufferFD, FBIOPUTCMAP, (void *) &ColorMap) < 0)
225 fprintf(stderr, "ioctl(FBIOPUTCMAP) failed!\n");
226 }
227
228 Active = 1;
229 Visible = 1;
230 VisibleSwitch = 1;
231
232 Redisplay = 1;
233
234 break;
235 }
236 }
237
238 static void Cleanup(void)
239 {
240 if(ConsoleFD >= 0)
241 if (tcsetattr(0, TCSANOW, &OldTermios) < 0)
242 fprintf(stderr, "tcsetattr failed\n");
243
244 if(ConsoleFD > 0) {
245 /* restore keyboard state */
246 if (ioctl(ConsoleFD, VT_SETMODE, &OldVTMode) < 0)
247 fprintf(stderr, "Failed to set vtmode\n");
248
249 if (ioctl(ConsoleFD, KDSKBMODE, OldKDMode) < 0)
250 fprintf(stderr, "ioctl KDSKBMODE failed!\n");
251
252 if(ioctl(ConsoleFD, KDSETMODE, OldMode) < 0)
253 fprintf(stderr, "ioctl KDSETMODE failed!\n");
254
255 close(ConsoleFD);
256 }
257
258 /* close mouse */
259 #ifdef HAVE_GPM
260 if(GpmMouse) {
261 if(NumMouseButtons)
262 Gpm_Close();
263 } else
264 #endif
265 if(MouseFD >= 0)
266 close(MouseFD);
267
268 glFBDevMakeCurrent( NULL, NULL, NULL);
269
270 glFBDevDestroyContext(Context);
271 glFBDevDestroyBuffer(Buffer);
272 glFBDevDestroyVisual(Visual);
273
274 struct vt_mode VT;
275
276 /* restore original variable screen info */
277 if(FrameBufferFD != -1) {
278 if (ioctl(FrameBufferFD, FBIOPUT_VSCREENINFO, &OrigVarInfo))
279 fprintf(stderr, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
280 strerror(errno));
281
282 munmap(FrameBuffer, FixedInfo.smem_len);
283 close(FrameBufferFD);
284 }
285
286 /* free allocated back buffer */
287 if(DisplayMode & GLUT_DOUBLE)
288 free(BackBuffer);
289
290 /* free menu items */
291 int i, j;
292
293 for(i = 1; i<NumMenus; i++) {
294 for(i = 1; i<Menus[i].NumItems; i++)
295 free(Menus[i].Items[j].name);
296 free(Menus[i].Items);
297 }
298 free(Menus);
299
300 if(exiterror[0])
301 fprintf(stderr, "[glfbdev glut] %s", exiterror);
302 }
303
304 static void CrashHandler(int sig)
305 {
306 sprintf(exiterror, "Caught signal %d, cleaning up\n", sig);
307 exit(0);
308 }
309
310 static void InitializeVT(int usestdin)
311 {
312 /* terminos settings for straight-through mode */
313 if (tcgetattr(0, &OldTermios) < 0) {
314 sprintf(exiterror, "tcgetattr failed\n");
315 exit(0);
316 }
317
318 struct termios tio = OldTermios;
319
320 tio.c_lflag &= ~(ICANON | ECHO | ISIG);
321 tio.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON);
322 tio.c_iflag |= IGNBRK;
323 tio.c_cc[VMIN] = 0;
324 tio.c_cc[VTIME] = 0;
325
326 if (tcsetattr(0, TCSANOW, &tio) < 0) {
327 sprintf(exiterror, "tcsetattr failed\n");
328 exit(0);
329 }
330
331 if(fcntl(0, F_SETFL, O_NONBLOCK) < 0) {
332 sprintf(exiterror, "Failed to set keyboard to non-blocking\n");
333 exit(0);
334 }
335
336 Active = 1;
337
338 if(usestdin) {
339 ConsoleFD = 0;
340 return;
341 }
342
343 /* detect the current vt if it was not specified */
344 if(CurrentVT == 0) {
345 int fd = open("/dev/tty", O_RDWR | O_NDELAY, 0);
346 struct vt_stat st;
347 if(fd == -1) {
348 sprintf(exiterror, "Failed to open /dev/tty\n");
349 exit(0);
350 }
351 if(ioctl(fd, VT_GETSTATE, &st) == -1) {
352 fprintf(stderr, "Could not detect current vt, specify with -vt\n");
353 fprintf(stderr, "Defaulting to stdin input\n");
354 ConsoleFD = 0;
355 close(fd);
356 return;
357 } else
358 CurrentVT = st.v_active;
359
360 close(fd);
361 }
362
363 /* open the console tty */
364 char console[128];
365 sprintf(console, "/dev/tty%d", CurrentVT);
366 ConsoleFD = open(console, O_RDWR | O_NDELAY, 0);
367 if (ConsoleFD < 0) {
368 sprintf(exiterror, "error couldn't open %s,"
369 " defaulting to stdin \n", console);
370 ConsoleFD = 0;
371 return;
372 }
373
374 signal(SIGUSR1, VTSwitchHandler);
375 signal(SIGUSR2, VTSwitchHandler);
376
377 struct vt_mode vt;
378
379 if (ioctl(ConsoleFD, VT_GETMODE, &OldVTMode) < 0) {
380 sprintf(exiterror,"Failed to grab %s, defaulting to stdin\n", console);
381 close(ConsoleFD);
382 ConsoleFD = 0;
383 return;
384 }
385
386 vt = OldVTMode;
387
388 vt.mode = VT_PROCESS;
389 vt.waitv = 0;
390 vt.relsig = SIGUSR1;
391 vt.acqsig = SIGUSR2;
392 if (ioctl(ConsoleFD, VT_SETMODE, &vt) < 0) {
393 sprintf(exiterror, "error: ioctl(VT_SETMODE) failed: %s\n",
394 strerror(errno));
395 close(ConsoleFD);
396 ConsoleFD = 0;
397 exit(1);
398 }
399
400 if (ioctl(ConsoleFD, KDGKBMODE, &OldKDMode) < 0) {
401 fprintf(stderr, "warning: ioctl KDGKBMODE failed!\n");
402 OldKDMode = K_XLATE;
403 }
404
405 if(ioctl(ConsoleFD, KDGETMODE, &OldMode) < 0)
406 sprintf(exiterror, "Warning: Failed to get terminal mode\n");
407
408 #ifdef HAVE_GPM
409 if(!GpmMouse)
410 #endif
411 if(ioctl(ConsoleFD, KDSETMODE, KD_GRAPHICS) < 0)
412 sprintf(exiterror,"Warning: Failed to set terminal to graphics\n");
413
414
415 if (ioctl(ConsoleFD, KDSKBMODE, K_MEDIUMRAW) < 0) {
416 sprintf(exiterror, "ioctl KDSKBMODE failed!\n");
417 tcsetattr(0, TCSANOW, &OldTermios);
418 exit(0);
419 }
420
421 if( ioctl(ConsoleFD, KDGKBLED, &KeyboardLedState) < 0) {
422 sprintf(exiterror, "ioctl KDGKBLED failed!\n");
423 exit(0);
424 }
425 }
426
427 static void InitializeMouse(void)
428 {
429 #ifdef HAVE_GPM
430 if(GpmMouse) {
431 Gpm_Connect conn;
432 int c;
433 conn.eventMask = ~0; /* Want to know about all the events */
434 conn.defaultMask = 0; /* don't handle anything by default */
435 conn.minMod = 0; /* want everything */
436 conn.maxMod = ~0; /* all modifiers included */
437 if(Gpm_Open(&conn, 0) == -1) {
438 fprintf(stderr, "Cannot open gpmctl. Continuing without Mouse\n");
439 return;
440 }
441
442 if(!MouseSpeed)
443 MouseSpeed = 5;
444 } else
445 #endif
446 {
447 const char *mousedev = getenv("MOUSE");
448 if(!mousedev)
449 mousedev = MOUSEDEV;
450 if((MouseFD = open(mousedev, O_RDONLY)) < 0) {
451 fprintf(stderr,"Cannot open %s.\n"
452 "Continuing without Mouse\n", MOUSEDEV);
453 return;
454 }
455
456 if(!MouseSpeed)
457 MouseSpeed = 1;
458 }
459
460 NumMouseButtons = 3;
461 }
462
463 static void removeArgs(int *argcp, char **argv, int num)
464 {
465 int i;
466 for (i = 0; argv[i+num]; i++)
467 argv[i] = argv[i+num];
468
469 argv[i] = NULL;
470 *argcp -= num;
471 }
472
473 #define REQPARAM(PARAM) \
474 if (i >= *argcp - 1) { \
475 fprintf(stderr, PARAM" requires a parameter\n"); \
476 exit(0); \
477 }
478
479 void glutInit (int *argcp, char **argv)
480 {
481 int i;
482 int nomouse = 0;
483 int nokeyboard = 0;
484 int usestdin = 0;
485
486 /* parse out args */
487 for (i = 1; i < *argcp;) {
488 if (!strcmp(argv[i], "-geometry")) {
489 REQPARAM("geometry");
490 if(sscanf(argv[i+1], "%dx%d", &RequiredWidth,
491 &RequiredHeight) != 2) {
492 fprintf(stderr,"Please specify geometry as widthxheight\n");
493 exit(0);
494 }
495 removeArgs(argcp, &argv[i], 2);
496 } else
497 if (!strcmp(argv[i], "-bpp")) {
498 REQPARAM("bpp");
499 if(sscanf(argv[i+1], "%d", &DesiredDepth) != 1) {
500 fprintf(stderr, "Please specify a parameter for bpp\n");
501 exit(0);
502 }
503
504 removeArgs(argcp, &argv[i], 2);
505 } else
506 if (!strcmp(argv[i], "-vt")) {
507 REQPARAM("vt");
508 if(sscanf(argv[i+1], "%d", &CurrentVT) != 1) {
509 fprintf(stderr, "Please specify a parameter for vt\n");
510 exit(0);
511 }
512 removeArgs(argcp, &argv[i], 2);
513 } else
514 if (!strcmp(argv[i], "-mousespeed")) {
515 REQPARAM("mousespeed");
516 if(sscanf(argv[i+1], "%lf", &MouseSpeed) != 1) {
517 fprintf(stderr, "Please specify a mouse speed, eg: 2.5\n");
518 exit(0);
519 }
520 removeArgs(argcp, &argv[i], 2);
521 } else
522 if (!strcmp(argv[i], "-nomouse")) {
523 nomouse = 1;
524 removeArgs(argcp, &argv[i], 1);
525 } else
526 if (!strcmp(argv[i], "-nokeyboard")) {
527 nokeyboard = 1;
528 removeArgs(argcp, &argv[i], 1);
529 } else
530 if (!strcmp(argv[i], "-stdin")) {
531 usestdin = 1;
532 removeArgs(argcp, &argv[i], 1);
533 } else
534 if (!strcmp(argv[i], "-gpmmouse")) {
535 #ifdef HAVE_GPM
536 GpmMouse = 1;
537 #else
538 fprintf(stderr, "gpm support was not compiled\n");
539 exit(0);
540 #endif
541 removeArgs(argcp, &argv[i], 1);
542 } else
543 if (!strcmp(argv[i], "--")) {
544 removeArgs(argcp, &argv[i], 1);
545 break;
546 } else
547 i++;
548 }
549
550 gettimeofday(&StartTime, 0);
551 atexit(Cleanup);
552
553 signal(SIGSEGV, CrashHandler);
554 signal(SIGINT, CrashHandler);
555 signal(SIGTERM, CrashHandler);
556
557 if(nomouse == 0)
558 InitializeMouse();
559 if(nokeyboard == 0)
560 InitializeVT(usestdin);
561 }
562
563 void glutInitDisplayMode (unsigned int mode)
564 {
565 DisplayMode = mode;
566 }
567
568 void glutInitWindowPosition (int x, int y)
569 {
570 }
571
572 void glutInitWindowSize (int width, int height)
573 {
574 InitialWidthHint = width;
575 InitialHeightHint = height;
576 }
577
578 /* --------- Mouse Rendering ------------*/
579 #include "cursors.h"
580 static int LastMouseX;
581 static int LastMouseY;
582 static unsigned char *MouseBuffer;
583
584 static void EraseCursor(void)
585 {
586 int off = LastMouseY * FixedInfo.line_length
587 + LastMouseX * VarInfo.bits_per_pixel / 8;
588 int stride = CURSOR_WIDTH * VarInfo.bits_per_pixel / 8;
589 int i;
590
591 unsigned char *src = MouseBuffer;
592
593 for(i = 0; i<CURSOR_HEIGHT; i++) {
594 memcpy(BackBuffer + off, src, stride);
595 src += stride;
596 off += FixedInfo.line_length;
597 }
598 }
599
600 static void SaveCursor(int x, int y)
601 {
602 if(x < 0)
603 LastMouseX = 0;
604 else
605 if(x > (int)VarInfo.xres - CURSOR_WIDTH)
606 LastMouseX = VarInfo.xres - CURSOR_WIDTH;
607 else
608 LastMouseX = x;
609
610 if(y < 0)
611 LastMouseY = 0;
612 else
613 if(y > (int)VarInfo.yres - CURSOR_HEIGHT)
614 LastMouseY = VarInfo.yres - CURSOR_HEIGHT;
615 else
616 LastMouseY = y;
617
618 int off = LastMouseY * FixedInfo.line_length
619 + LastMouseX * VarInfo.bits_per_pixel / 8;
620 int stride = CURSOR_WIDTH * VarInfo.bits_per_pixel / 8;
621 int i;
622 unsigned char *src = MouseBuffer;
623 for(i = 0; i<CURSOR_HEIGHT; i++) {
624 memcpy(src, BackBuffer + off, stride);
625 src += stride;
626 off += FixedInfo.line_length;
627 }
628 }
629
630 static void DrawCursor(void)
631 {
632 if(CurrentCursor < 0 || CurrentCursor >= NUM_CURSORS)
633 return;
634
635 int px = MouseX - CursorsXOffset[CurrentCursor];
636 int py = MouseY - CursorsYOffset[CurrentCursor];
637
638 SaveCursor(px, py);
639
640 int xoff = 0;
641 if(px < 0)
642 xoff = -px;
643
644 int xlen = CURSOR_WIDTH;
645 if(px + CURSOR_WIDTH > VarInfo.xres)
646 xlen = VarInfo.xres - px;
647
648 int yoff = 0;
649 if(py < 0)
650 yoff = -py;
651
652 int ylen = CURSOR_HEIGHT;
653 if(py + CURSOR_HEIGHT > VarInfo.yres)
654 ylen = VarInfo.yres - py;
655
656 int bypp = VarInfo.bits_per_pixel / 8;
657
658 unsigned char *c = BackBuffer + FixedInfo.line_length * (py + yoff)
659 + (px + xoff) * bypp;
660
661 unsigned char *d = Cursors[CurrentCursor] + (CURSOR_WIDTH * yoff + xoff)*4;
662 int i, j;
663
664 int dstride = (CURSOR_WIDTH - xlen + xoff) * 4;
665 int cstride = FixedInfo.line_length - bypp * (xlen - xoff);
666
667 switch(bypp) {
668 case 1: /* no support for 8bpp mouse yet */
669 break;
670 case 2:
671 {
672 uint16_t *e = (void*)c;
673 cstride /= 2;
674 for(i = yoff; i < ylen; i++) {
675 for(j = xoff; j < xlen; j++) {
676 e[0] = ((((d[0] + (((int)(((e[0] >> 8) & 0xf8)
677 | ((c[0] >> 11) & 0x7)) * d[3]) >> 8)) & 0xf8) << 8)
678 | (((d[1] + (((int)(((e[0] >> 3) & 0xfc)
679 | ((e[0] >> 5) & 0x3)) * d[3]) >> 8)) & 0xfc) << 3)
680 | ((d[2] + (((int)(((e[0] << 3) & 0xf8)
681 | (e[0] & 0x7)) * d[3]) >> 8)) >> 3));
682
683 e++;
684 d+=4;
685 }
686 d += dstride;
687 e += cstride;
688 }
689 }
690 break;
691 case 3:
692 case 4:
693 for(i = yoff; i < ylen; i++) {
694 for(j = xoff; j < xlen; j++) {
695 c[0] = d[0] + (((int)c[0] * d[3]) >> 8);
696 c[1] = d[1] + (((int)c[1] * d[3]) >> 8);
697 c[2] = d[2] + (((int)c[2] * d[3]) >> 8);
698
699 c+=bypp;
700 d+=4;
701 }
702 d += dstride;
703 c += cstride;
704 } break;
705 }
706 }
707
708 #define MIN(x, y) x < y ? x : y
709 static void SwapCursor(void)
710 {
711 int px = MouseX - CursorsXOffset[CurrentCursor];
712 int py = MouseY - CursorsYOffset[CurrentCursor];
713
714 int minx = MIN(px, LastMouseX);
715 int sizex = abs(px - LastMouseX);
716
717 int miny = MIN(py, LastMouseY);
718 int sizey = abs(py - LastMouseY);
719
720 DrawCursor();
721 /* now update the portion of the screen that has changed */
722
723 if(DisplayMode & GLUT_DOUBLE && (sizex || sizey)) {
724 if(minx < 0)
725 minx = 0;
726 if(miny < 0)
727 miny = 0;
728
729 if(minx + sizex > VarInfo.xres)
730 sizex = VarInfo.xres - minx;
731 if(miny + sizey > VarInfo.yres)
732 sizey = VarInfo.yres - miny;
733 int off = FixedInfo.line_length * miny
734 + minx * VarInfo.bits_per_pixel / 8;
735 int stride = (sizex + CURSOR_WIDTH) * VarInfo.bits_per_pixel / 8;
736 int i;
737 for(i = 0; i< sizey + CURSOR_HEIGHT; i++) {
738 memcpy(FrameBuffer+off, BackBuffer+off, stride);
739 off += FixedInfo.line_length;
740 }
741 }
742 }
743
744 /* --------- Menu Rendering ------------*/
745 static double MenuProjection[16];
746 static double MenuModelview[16];
747
748 static void InitMenuMatrices(void)
749 {
750 glMatrixMode(GL_PROJECTION);
751 glLoadIdentity();
752 gluOrtho2D(0.0,VarInfo.xres,VarInfo.yres,0.0);
753 glMatrixMode(GL_MODELVIEW);
754 glLoadIdentity();
755 glViewport(0,0,VarInfo.xres,VarInfo.yres);
756 glGetDoublev(GL_PROJECTION_MATRIX, MenuProjection);
757 glGetDoublev(GL_MODELVIEW_MATRIX, MenuModelview);
758 }
759
760 static int DrawMenu(int menu, int x, int *y)
761 {
762 int i;
763 int ret = 1;
764 for(i=0; i < Menus[menu].NumItems; i++) {
765 char *s = Menus[menu].Items[i].name;
766 int a =0;
767 if(MouseY >= *y && MouseY < *y + MENU_FONT_HEIGHT &&
768 MouseX >= x && MouseX < x + Menus[menu].width) {
769 a = 1;
770 SelectedMenu = menu;
771 ret = 0;
772 Menus[menu].selected = i;
773 glColor3f(1,0,0);
774 } else
775 glColor3f(0,0,1);
776
777 *y += MENU_FONT_HEIGHT;
778 glRasterPos2i(x, *y);
779 for(; *s; s++)
780 glutBitmapCharacter(MENU_FONT, *s);
781
782 if(Menus[menu].selected == i)
783 if(Menus[menu].Items[i].submenu)
784 if(DrawMenu(Menus[menu].Items[i].submenu, x
785 + SUBMENU_OFFSET, y)) {
786 if(!a)
787 Menus[menu].selected = -1;
788 } else
789 ret = 0;
790 }
791 return ret;
792 }
793
794 static void DrawMenus(void)
795 {
796 /* save old settings */
797 glPushAttrib(-1);
798
799 glMatrixMode(GL_MODELVIEW);
800 glPushMatrix();
801 glLoadMatrixd(MenuModelview);
802 glMatrixMode(GL_PROJECTION);
803 glPushMatrix();
804 glLoadMatrixd(MenuProjection);
805
806 glDisable(GL_DEPTH_TEST);
807 glDisable(GL_ALPHA_TEST);
808 glDisable(GL_LIGHTING);
809 glDisable(GL_FOG);
810 glDisable(GL_TEXTURE_2D);
811 // glEnable(GL_LOGIC_OP);
812 //glEnable(GL_COLOR_LOGIC_OP);
813 // glLogicOp(GL_XOR);
814
815 int x = Menus[ActiveMenu].x;
816 int y = Menus[ActiveMenu].y;
817
818 if(DrawMenu(ActiveMenu, x, &y))
819 Menus[ActiveMenu].selected = -1;
820
821 /* restore settings */
822
823 glPopMatrix();
824 glMatrixMode(GL_MODELVIEW);
825 glPopMatrix();
826
827 glPopAttrib();
828 }
829
830 /* --------- Event Processing ------------*/
831 #define MODIFIER(mod) \
832 KeyboardModifiers = release ? KeyboardModifiers & ~mod \
833 : KeyboardModifiers | mod;
834
835 #define READKEY read(ConsoleFD, &code, 1)
836
837 static void LedModifier(int led, int release)
838 {
839 static int releaseflag = K_CAPS | K_NUM;
840 if(release)
841 releaseflag |= led;
842 else
843 if(releaseflag & led) {
844 KeyboardLedState ^= led;
845 releaseflag &= ~led;
846 }
847 ioctl(ConsoleFD, KDSKBLED, KeyboardLedState);
848 ioctl(ConsoleFD, KDSETLED, 0x80);
849 }
850
851 static int ReadKey(void)
852 {
853 int x;
854 unsigned char code;
855 int specialkey = 0;
856 if(READKEY == 0)
857 return 0;
858
859 if(code == 0)
860 return 0;
861
862 /* stdin input escape code based */
863 if(ConsoleFD == 0) {
864 KeyboardModifiers = 0;
865 altset:
866 if(code == 27 && READKEY == 1) {
867 switch(code) {
868 case 79: /* function key */
869 READKEY;
870 if(code == 50) {
871 READKEY;
872 shiftfunc:
873 KeyboardModifiers |= GLUT_ACTIVE_SHIFT;
874 specialkey = GLUT_KEY_F1 + code - 53;
875 READKEY;
876 } else {
877 READKEY;
878 specialkey = GLUT_KEY_F1 + code - 80;
879 }
880 break;
881 case 91:
882 READKEY;
883 switch(code) {
884 case 68:
885 specialkey = GLUT_KEY_LEFT; break;
886 case 65:
887 specialkey = GLUT_KEY_UP; break;
888 case 67:
889 specialkey = GLUT_KEY_RIGHT; break;
890 case 66:
891 specialkey = GLUT_KEY_DOWN; break;
892 case 53:
893 specialkey = GLUT_KEY_PAGE_UP; READKEY; break;
894 case 54:
895 specialkey = GLUT_KEY_PAGE_DOWN; READKEY; break;
896 case 49:
897 specialkey = GLUT_KEY_HOME; READKEY; break;
898 case 52:
899 specialkey = GLUT_KEY_END; READKEY; break;
900 case 50:
901 READKEY;
902 if(code != 126)
903 goto shiftfunc;
904 specialkey = GLUT_KEY_INSERT;
905 break;
906 case 51:
907 code = '\b'; goto stdkey;
908 case 91:
909 READKEY;
910 specialkey = GLUT_KEY_F1 + code - 65;
911 break;
912 default:
913 return 0;
914 }
915 break;
916 default:
917 KeyboardModifiers |= GLUT_ACTIVE_ALT;
918 goto altset;
919 }
920 }
921 stdkey:
922 if(specialkey) {
923 if(SpecialFunc)
924 SpecialFunc(specialkey, MouseX, MouseY);
925 } else {
926 if(code >= 1 && code <= 26) {
927 KeyboardModifiers |= GLUT_ACTIVE_CTRL;
928 code += 'a' - 1;
929 }
930 if((code >= 43 && code <= 34) || (code == 60)
931 || (code >= 62 && code <= 90) || (code == 94)
932 || (code == 95) || (code >= 123 && code <= 126))
933 KeyboardModifiers |= GLUT_ACTIVE_SHIFT;
934
935 if(KeyboardFunc)
936 KeyboardFunc(code, MouseX, MouseY);
937 }
938 return 1;
939 }
940
941 /* linux kbd reading */
942 struct kbentry entry;
943 entry.kb_table = 0;
944 if(KeyboardModifiers & GLUT_ACTIVE_SHIFT)
945 entry.kb_table |= K_SHIFTTAB;
946
947 int release = code & 0x80;
948 code &= 0x7F;
949
950 entry.kb_index = code;
951
952 if (ioctl(ConsoleFD, KDGKBENT, &entry) < 0) {
953 sprintf(exiterror, "ioctl(KDGKBENT) failed.\n");
954 exit(0);
955 }
956
957 int labelval = entry.kb_value;
958
959 switch(labelval) {
960 case K_SHIFT:
961 case K_SHIFTL:
962 MODIFIER(GLUT_ACTIVE_SHIFT);
963 return 0;
964 case K_CTRL:
965 MODIFIER(GLUT_ACTIVE_CTRL);
966 return 0;
967 case K_ALT:
968 case K_ALTGR:
969 MODIFIER(GLUT_ACTIVE_ALT);
970 return 0;
971 }
972
973 if(!release && labelval >= K_F1 && labelval <= K_F12)
974 if(KeyboardModifiers & GLUT_ACTIVE_ALT) {
975 /* VT switch, we must do it */
976 if(ioctl(ConsoleFD, VT_ACTIVATE, labelval - K_F1 + 1) < 0)
977 sprintf(exiterror, "Error switching console\n");
978 return 0;
979 }
980
981 switch(labelval) {
982 case K_CAPS:
983 LedModifier(LED_CAP, release);
984 return 0;
985 case K_NUM:
986 LedModifier(LED_NUM, release);
987 return 0;
988 case K_HOLD: /* scroll lock suspends glut */
989 LedModifier(LED_SCR, release);
990 while(KeyboardLedState & LED_SCR) {
991 usleep(10000);
992 ReadKey();
993 }
994 return 0;
995 }
996
997 /* we could queue keypresses here */
998 if(KeyboardLedState & LED_SCR)
999 return 0;
1000
1001 if(release)
1002 return 0;
1003
1004 if(labelval >= K_F1 && labelval <= K_F12)
1005 specialkey = GLUT_KEY_F1 + labelval - K_F1;
1006 else
1007 switch(labelval) {
1008 case K_LEFT:
1009 specialkey = GLUT_KEY_LEFT; break;
1010 case K_UP:
1011 specialkey = GLUT_KEY_UP; break;
1012 case K_RIGHT:
1013 specialkey = GLUT_KEY_RIGHT; break;
1014 case K_DOWN:
1015 specialkey = GLUT_KEY_DOWN; break;
1016 case K_PGUP:
1017 specialkey = GLUT_KEY_PAGE_UP; break;
1018 case K_PGDN:
1019 specialkey = GLUT_KEY_PAGE_DOWN; break;
1020 case K_FIND:
1021 specialkey = GLUT_KEY_HOME; break;
1022 case K_SELECT:
1023 specialkey = GLUT_KEY_END; break;
1024 case K_INSERT:
1025 specialkey = GLUT_KEY_INSERT; break;
1026 case K_REMOVE:
1027 labelval = '\b'; break;
1028 case K_ENTER:
1029 labelval = '\n'; break;
1030 }
1031
1032 if(specialkey) {
1033 if(SpecialFunc)
1034 SpecialFunc(specialkey, MouseX, MouseY);
1035 } else
1036 if(KeyboardFunc) {
1037 char c = labelval;
1038 if(KeyboardLedState & LED_CAP) {
1039 if(c >= 'A' && c <= 'Z')
1040 c += 'a' - 'A';
1041 else
1042 if(c >= 'a' && c <= 'z')
1043 c += 'A' - 'a';
1044 }
1045 KeyboardFunc(c, MouseX, MouseY);
1046 }
1047 return 1;
1048 }
1049
1050 static void HandleMousePress(int button, int pressed)
1051 {
1052 if(ActiveMenu && !pressed) {
1053 if(MenuStatusFunc)
1054 MenuStatusFunc(GLUT_MENU_NOT_IN_USE, MouseX, MouseY);
1055 if(MenuStateFunc)
1056 MenuStateFunc(GLUT_MENU_NOT_IN_USE);
1057 if(SelectedMenu > 0) {
1058 int selected = Menus[SelectedMenu].selected;
1059 if(selected >= 0)
1060 if(Menus[SelectedMenu].Items[selected].submenu == 0)
1061 Menus[SelectedMenu].func(Menus[SelectedMenu].Items
1062 [selected].value);
1063 }
1064 ActiveMenu = 0;
1065 Redisplay = 1;
1066 return;
1067 }
1068
1069 if(AttachedMenus[button] && pressed) {
1070 ActiveMenu = AttachedMenus[button];
1071 if(MenuStatusFunc)
1072 MenuStatusFunc(GLUT_MENU_IN_USE, MouseX, MouseY);
1073 if(MenuStateFunc)
1074 MenuStateFunc(GLUT_MENU_IN_USE);
1075 Menus[ActiveMenu].x = MouseX - Menus[ActiveMenu].width/2;
1076 Menus[ActiveMenu].y = MouseY - Menus[ActiveMenu].NumItems*MENU_FONT_HEIGHT/2;
1077 Menus[ActiveMenu].selected = -1;
1078 Redisplay = 1;
1079 return;
1080 }
1081
1082 if(MouseFunc)
1083 MouseFunc(button, pressed ? GLUT_DOWN : GLUT_UP, MouseX, MouseY);
1084 }
1085
1086 static int ReadMouse(void)
1087 {
1088 int l, r, m;
1089 static int ll, lm, lr;
1090 signed char dx, dy;
1091
1092 #ifdef HAVE_GPM
1093 if(GpmMouse) {
1094 Gpm_Event event;
1095 struct pollfd pfd;
1096 pfd.fd = gpm_fd;
1097 pfd.events = POLLIN;
1098 if(poll(&pfd, 1, 1) != 1)
1099 return 0;
1100
1101 if(Gpm_GetEvent(&event) != 1)
1102 return 0;
1103
1104 l = event.buttons & GPM_B_LEFT;
1105 m = event.buttons & GPM_B_MIDDLE;
1106 r = event.buttons & GPM_B_RIGHT;
1107
1108 /* gpm is weird in that it gives a button number when the button
1109 is released, with type set to GPM_UP, this is only a problem
1110 if it is the last button released */
1111
1112 if(event.type & GPM_UP)
1113 if(event.buttons == GPM_B_LEFT || event.buttons == GPM_B_MIDDLE ||
1114 event.buttons == GPM_B_RIGHT || event.buttons == GPM_B_FOURTH)
1115 l = m = r = 0;
1116
1117 dx = event.dx;
1118 dy = event.dy;
1119 } else
1120 #endif
1121 {
1122 if(MouseFD == -1)
1123 return 0;
1124
1125 if(fcntl(MouseFD, F_SETFL, O_NONBLOCK) == -1) {
1126 close(MouseFD);
1127 MouseFD = -1;
1128 return 0;
1129 }
1130
1131 char data[4];
1132 if(read(MouseFD, data, 4) != 4)
1133 return 0;
1134
1135 l = ((data[0] & 0x20) >> 3);
1136 m = ((data[3] & 0x10) >> 3);
1137 r = ((data[0] & 0x10) >> 4);
1138
1139 dx = (((data[0] & 0x03) << 6) | (data[1] & 0x3F));
1140 dy = (((data[0] & 0x0C) << 4) | (data[2] & 0x3F));
1141 }
1142
1143 MouseX += dx * MouseSpeed;
1144 if(MouseX < 0)
1145 MouseX = 0;
1146 else
1147 if(MouseX >= VarInfo.xres)
1148 MouseX = VarInfo.xres - 1;
1149
1150 MouseY += dy * MouseSpeed;
1151 if(MouseY < 0)
1152 MouseY = 0;
1153 else
1154 if(MouseY >= VarInfo.yres)
1155 MouseY = VarInfo.yres - 1;
1156
1157 if(l != ll)
1158 HandleMousePress(GLUT_LEFT_BUTTON, l);
1159 if(m != lm)
1160 HandleMousePress(GLUT_MIDDLE_BUTTON, m);
1161 if(r != lr)
1162 HandleMousePress(GLUT_RIGHT_BUTTON, r);
1163
1164 ll = l, lm = m, lr = r;
1165
1166 if(dx || dy) {
1167 if(l || m || r) {
1168 if(MotionFunc)
1169 MotionFunc(MouseX, MouseY);
1170 } else
1171 if(PassiveMotionFunc)
1172 PassiveMotionFunc(MouseX, MouseY);
1173
1174 EraseCursor();
1175 if(ActiveMenu)
1176 Redisplay = 1;
1177 else
1178 SwapCursor();
1179 }
1180
1181 return 1;
1182 }
1183
1184 static void RecieveEvents(void)
1185 {
1186 while(ReadKey());
1187
1188 if(MouseEnabled)
1189 while(ReadMouse());
1190 }
1191
1192 static void ProcessTimers(void)
1193 {
1194 if(GlutTimers && GlutTimers->time < glutGet(GLUT_ELAPSED_TIME)) {
1195 struct GlutTimer *timer = GlutTimers;
1196 timer->func(timer->value);
1197 GlutTimers = timer->next;
1198 free(timer);
1199 }
1200 }
1201
1202 void glutMainLoop(void)
1203 {
1204 if(ReshapeFunc)
1205 ReshapeFunc(VarInfo.xres, VarInfo.yres);
1206
1207 if(!DisplayFunc) {
1208 sprintf(exiterror, "Fatal Error: No Display Function registered\n");
1209 exit(0);
1210 }
1211
1212 for(;;) {
1213 ProcessTimers();
1214
1215 if(Active)
1216 RecieveEvents();
1217 else
1218 if(VisiblePoll)
1219 TestVisible();
1220
1221 if(IdleFunc)
1222 IdleFunc();
1223
1224 if(VisibleSwitch) {
1225 VisibleSwitch = 0;
1226 if(VisibilityFunc)
1227 VisibilityFunc(Visible ? GLUT_VISIBLE : GLUT_NOT_VISIBLE);
1228 }
1229
1230 if(Visible && Redisplay) {
1231 Redisplay = 0;
1232 if(MouseEnabled)
1233 EraseCursor();
1234 DisplayFunc();
1235 if(!(DisplayMode & GLUT_DOUBLE)) {
1236 if(ActiveMenu)
1237 DrawMenus();
1238 if(MouseEnabled)
1239 DrawCursor();
1240 }
1241 }
1242 }
1243 }
1244
1245 /* ---------- Window Management ----------*/
1246 static void ParseFBModes(void)
1247 {
1248 char buf[1024];
1249 struct fb_var_screeninfo vi = VarInfo;
1250
1251 FILE *fbmodes = fopen(FBMODES, "r");
1252
1253 if(!fbmodes) {
1254 sprintf(exiterror, "Warning: could not open "
1255 FBMODES" using current mode\n");
1256 return;
1257 }
1258
1259 if(InitialWidthHint == 0 && InitialHeightHint == 0
1260 && RequiredWidth == 0)
1261 return; /* use current mode */
1262
1263 while(fgets(buf, sizeof buf, fbmodes)) {
1264 char *c;
1265 int v;
1266
1267 if(!(c = strstr(buf, "geometry")))
1268 continue;
1269 v = sscanf(c, "geometry %d %d %d %d %d", &vi.xres, &vi.yres,
1270 &vi.xres_virtual, &vi.yres_virtual, &vi.bits_per_pixel);
1271 if(v != 5)
1272 continue;
1273
1274 /* now we have to decide what is best */
1275 if(RequiredWidth) {
1276 if(RequiredWidth != vi.xres || RequiredHeight != vi.yres)
1277 continue;
1278 } else {
1279 if(VarInfo.xres < vi.xres && VarInfo.xres < InitialWidthHint)
1280 v++;
1281 if(VarInfo.xres > vi.xres && vi.xres > InitialWidthHint)
1282 v++;
1283
1284 if(VarInfo.yres < vi.yres && VarInfo.yres < InitialHeightHint)
1285 v++;
1286 if(VarInfo.yres > vi.yres && vi.yres > InitialHeightHint)
1287 v++;
1288
1289 if(v < 7)
1290 continue;
1291 }
1292
1293 fgets(buf, sizeof buf, fbmodes);
1294 if(!(c = strstr(buf, "timings")))
1295 continue;
1296
1297 v = sscanf(c, "timings %d %d %d %d %d %d %d", &vi.pixclock,
1298 &vi.left_margin, &vi.right_margin, &vi.upper_margin,
1299 &vi.lower_margin, &vi.hsync_len, &vi.vsync_len);
1300 if(v != 7)
1301 continue;
1302
1303 VarInfo = vi; /* finally found a better mode */
1304 if(RequiredWidth) {
1305 fclose(fbmodes);
1306 return;
1307 }
1308 }
1309
1310 fclose(fbmodes);
1311
1312 if(RequiredWidth) {
1313 sprintf(exiterror, "No mode (%dx%d) found in "FBMODES"\n",
1314 RequiredWidth, RequiredHeight);
1315 exit(0);
1316 }
1317 }
1318
1319 int glutCreateWindow (const char *title)
1320 {
1321 if(ConsoleFD == -1) {
1322 int argc = 0;
1323 char *argv[] = {NULL};
1324 glutInit(&argc, argv);
1325 }
1326
1327 if(Context)
1328 return 0;
1329
1330 char *fbdev = getenv("FRAMEBUFFER");
1331 if(fbdev) {
1332 #ifdef MULTIHEAD
1333 if(!sscanf(fbdev, "/dev/fb%d", &FramebufferIndex))
1334 if(!sscanf(fbdev, "/dev/fb/%d", &FramebufferIndex))
1335 sprintf(exiterror, "Could not determine Framebuffer index!\n");
1336 #endif
1337 } else {
1338 static char fb[128];
1339 FramebufferIndex = 0;
1340 struct fb_con2fbmap confb;
1341 int fd = open("/dev/fb0", O_RDWR);
1342 confb.console = CurrentVT;
1343 if(ioctl(fd, FBIOGET_CON2FBMAP, &confb) != -1)
1344 FramebufferIndex = confb.framebuffer;
1345 sprintf(fb, "/dev/fb%d", FramebufferIndex);
1346 fbdev = fb;
1347 close(fd);
1348 }
1349
1350 /* open the framebuffer device */
1351 FrameBufferFD = open(fbdev, O_RDWR);
1352 if (FrameBufferFD < 0) {
1353 sprintf(exiterror, "Error opening %s: %s\n", fbdev, strerror(errno));
1354 exit(0);
1355 }
1356
1357 /* Get the fixed screen info */
1358 if (ioctl(FrameBufferFD, FBIOGET_FSCREENINFO, &FixedInfo)) {
1359 sprintf(exiterror, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
1360 strerror(errno));
1361 exit(0);
1362 }
1363
1364 /* get the variable screen info */
1365 if (ioctl(FrameBufferFD, FBIOGET_VSCREENINFO, &OrigVarInfo)) {
1366 sprintf(exiterror, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
1367 strerror(errno));
1368 exit(0);
1369 }
1370
1371 /* operate on a copy */
1372 VarInfo = OrigVarInfo;
1373
1374 /* set the depth, resolution, etc */
1375 ParseFBModes();
1376
1377 if(DisplayMode & GLUT_INDEX)
1378 VarInfo.bits_per_pixel = 8;
1379 else
1380 if(VarInfo.bits_per_pixel == 8)
1381 VarInfo.bits_per_pixel = 32;
1382
1383 if (DesiredDepth)
1384 VarInfo.bits_per_pixel = DesiredDepth;
1385
1386 VarInfo.xoffset = 0;
1387 VarInfo.yoffset = 0;
1388 VarInfo.nonstd = 0;
1389 VarInfo.vmode &= ~FB_VMODE_YWRAP; /* turn off scrolling */
1390
1391 /* set new variable screen info */
1392 if (ioctl(FrameBufferFD, FBIOPUT_VSCREENINFO, &VarInfo)) {
1393 sprintf(exiterror, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
1394 strerror(errno));
1395 exit(0);
1396 }
1397
1398 /* reload the screen info to update offsets */
1399 if (ioctl(FrameBufferFD, FBIOGET_VSCREENINFO, &VarInfo)) {
1400 sprintf(exiterror, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
1401 strerror(errno));
1402 exit(0);
1403 }
1404
1405 /* reload the fixed info to update color mode */
1406 if (ioctl(FrameBufferFD, FBIOGET_FSCREENINFO, &FixedInfo)) {
1407 sprintf(exiterror, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
1408 strerror(errno));
1409 exit(0);
1410 }
1411
1412 if(DisplayMode & GLUT_INDEX) {
1413 /* initialize colormap */
1414 if (FixedInfo.visual != FB_VISUAL_DIRECTCOLOR) {
1415 static unsigned short red[256], green[256], blue[256];
1416 /* we're assuming 256 entries here */
1417
1418 ColorMap.start = 0;
1419 ColorMap.len = 256;
1420 ColorMap.red = red;
1421 ColorMap.green = green;
1422 ColorMap.blue = blue;
1423 ColorMap.transp = NULL;
1424
1425 if (ioctl(FrameBufferFD, FBIOGETCMAP, (void *) &ColorMap) < 0)
1426 sprintf(exiterror, "ioctl(FBIOGETCMAP) failed!\n");
1427
1428 } else {
1429 sprintf(exiterror, "error: Could not set 8 bit color mode\n");
1430 exit(0);
1431 }
1432 }
1433
1434 /* mmap the framebuffer into our address space */
1435 FrameBuffer = mmap(0, FixedInfo.smem_len, PROT_READ | PROT_WRITE,
1436 MAP_SHARED, FrameBufferFD, 0);
1437 if (FrameBuffer == MAP_FAILED) {
1438 sprintf(exiterror, "error: unable to mmap framebuffer: %s\n",
1439 strerror(errno));
1440 exit(0);
1441 }
1442
1443 int attribs[9];
1444 int i;
1445
1446 int mask = DisplayMode;
1447 for(i=0; i<8 && mask; i++) {
1448 if(mask & GLUT_DOUBLE) {
1449 attribs[i] = GLFBDEV_DOUBLE_BUFFER;
1450 mask &= ~GLUT_DOUBLE;
1451 continue;
1452 }
1453
1454 if(mask & GLUT_INDEX) {
1455 attribs[i] = GLFBDEV_COLOR_INDEX;
1456 mask &= ~GLUT_INDEX;
1457 continue;
1458 }
1459
1460 if(mask & GLUT_DEPTH) {
1461 attribs[i] = GLFBDEV_DEPTH_SIZE;
1462 attribs[++i] = DepthSize;
1463 mask &= ~GLUT_DEPTH;
1464 continue;
1465 }
1466
1467 if(mask & GLUT_STENCIL) {
1468 attribs[i] = GLFBDEV_STENCIL_SIZE;
1469 attribs[++i] = StencilSize;
1470 mask &= ~GLUT_STENCIL;
1471 continue;
1472 }
1473
1474 if(mask & GLUT_ACCUM) {
1475 attribs[i] = GLFBDEV_ACCUM_SIZE;
1476 attribs[++i] = AccumSize;
1477 mask &= ~GLUT_ACCUM;
1478 continue;
1479 }
1480
1481 if(mask & GLUT_ALPHA)
1482 if(!(DisplayMode & GLUT_INDEX)) {
1483 mask &= ~GLUT_ALPHA;
1484 i--;
1485 continue;
1486 }
1487
1488 sprintf(exiterror, "Invalid mode from glutInitDisplayMode\n");
1489 exit(0);
1490 }
1491
1492 attribs[i] = GLFBDEV_NONE;
1493
1494 if(!(Visual = glFBDevCreateVisual( &FixedInfo, &VarInfo, attribs ))) {
1495 sprintf(exiterror, "Failure to create Visual\n");
1496 exit(0);
1497 }
1498
1499 int size = VarInfo.xres_virtual * VarInfo.yres_virtual
1500 * VarInfo.bits_per_pixel / 8;
1501 if(DisplayMode & GLUT_DOUBLE) {
1502 if(!(BackBuffer = malloc(size))) {
1503 sprintf(exiterror, "Failed to allocate double buffer\n");
1504 exit(0);
1505 }
1506 } else
1507 BackBuffer = FrameBuffer;
1508
1509 if(!(Buffer = glFBDevCreateBuffer( &FixedInfo, &VarInfo, Visual,
1510 FrameBuffer, BackBuffer, size))) {
1511 sprintf(exiterror, "Failure to create Buffer\n");
1512 exit(0);
1513 }
1514
1515 if(!(Context = glFBDevCreateContext(Visual, NULL))) {
1516 sprintf(exiterror, "Failure to create Context\n");
1517 exit(0);
1518 }
1519
1520 if(!glFBDevMakeCurrent( Context, Buffer, Buffer )) {
1521 sprintf(exiterror, "Failure to Make Current\n");
1522 exit(0);
1523 }
1524
1525 Visible = 1;
1526 VisibleSwitch = 1;
1527 Redisplay = 1;
1528
1529 /* set up mouse */
1530 if((MouseBuffer = malloc(CURSOR_WIDTH * CURSOR_HEIGHT
1531 * VarInfo.bits_per_pixel / 8)) == NULL) {
1532 sprintf(exiterror, "malloc failure\n");
1533 exit(0);
1534 }
1535
1536 MouseX = VarInfo.xres / 2;
1537 MouseY = VarInfo.yres / 2;
1538
1539 /* set up menus */
1540 InitMenuMatrices();
1541 return 1;
1542 }
1543
1544 int glutCreateSubWindow(int win, int x, int y, int width, int height)
1545 {
1546 return 0;
1547 }
1548
1549 void glutSetWindow(int win)
1550 {
1551 }
1552
1553 int glutGetWindow(void)
1554 {
1555 return 1;
1556 }
1557
1558 void glutDestroyWindow(int win)
1559 {
1560 }
1561
1562 void glutPostRedisplay(void)
1563 {
1564 Redisplay = 1;
1565 }
1566
1567 void glutSwapBuffers(void)
1568 {
1569 glFlush();
1570
1571 if(DisplayMode & GLUT_DOUBLE) {
1572 if(ActiveMenu)
1573 DrawMenus();
1574 if(MouseEnabled)
1575 DrawCursor();
1576 glFBDevSwapBuffers(Buffer);
1577 }
1578 }
1579
1580 void glutPositionWindow(int x, int y)
1581 {
1582 }
1583
1584 void glutReshapeWindow(int width, int height)
1585 {
1586 }
1587
1588 void glutFullScreen(void)
1589 {
1590 }
1591
1592 void glutPopWindow(void)
1593 {
1594 }
1595
1596 void glutPushWindow(void)
1597 {
1598 }
1599
1600 void glutShowWindow(void)
1601 {
1602 }
1603
1604 void glutHideWindow(void)
1605 {
1606 }
1607
1608 void glutIconifyWindow(void)
1609 {
1610 }
1611
1612 void glutSetWindowTitle(const char *name)
1613 {
1614 }
1615
1616 void glutSetIconTitle(const char *name)
1617 {
1618 }
1619
1620 void glutSetCursor(int cursor)
1621 {
1622 if(cursor == GLUT_CURSOR_FULL_CROSSHAIR)
1623 cursor = GLUT_CURSOR_CROSSHAIR;
1624 CurrentCursor = cursor;
1625 MouseEnabled = 1;
1626 EraseCursor();
1627 SwapCursor();
1628 }
1629
1630 /* --------- Overlays ------------*/
1631 void glutEstablishOverlay(void)
1632 {
1633 exit(0);
1634 }
1635
1636 void glutUseLayer(GLenum layer)
1637 {
1638 }
1639
1640 void glutRemoveOverlay(void)
1641 {
1642 }
1643
1644 void glutPostOverlayRedisplay(void)
1645 {
1646 }
1647
1648 void glutShowOverlay(void)
1649 {
1650 }
1651
1652 void glutHideOverlay(void)
1653 {
1654 }
1655
1656 /* --------- Menus ------------*/
1657 int glutCreateMenu(void (*func)(int value))
1658 {
1659 MouseEnabled = 1;
1660 CurrentMenu = NumMenus;
1661 NumMenus++;
1662 Menus = realloc(Menus, sizeof(*Menus) * NumMenus);
1663 Menus[CurrentMenu].NumItems = 0;
1664 Menus[CurrentMenu].Items = NULL;
1665 Menus[CurrentMenu].func = func;
1666 Menus[CurrentMenu].width = 0;
1667 return CurrentMenu;
1668 }
1669
1670 void glutSetMenu(int menu)
1671 {
1672 CurrentMenu = menu;
1673 }
1674
1675 int glutGetMenu(void)
1676 {
1677 return CurrentMenu;
1678 }
1679
1680 void glutDestroyMenu(int menu)
1681 {
1682 if(menu == CurrentMenu)
1683 CurrentMenu = 0;
1684 }
1685
1686 static void NameMenuEntry(int entry, const char *name)
1687 {
1688 int cm = CurrentMenu;
1689 if(!(Menus[cm].Items[entry-1].name = realloc(Menus[cm].Items[entry-1].name,
1690 strlen(name) + 1))) {
1691 sprintf(exiterror, "realloc failed in NameMenuEntry\n");
1692 exit(0);
1693 }
1694 strcpy(Menus[cm].Items[entry-1].name, name);
1695 if(strlen(name) * MENU_FONT_WIDTH > Menus[cm].width)
1696 Menus[cm].width = strlen(name) * MENU_FONT_WIDTH;
1697 }
1698
1699 static int AddMenuItem(const char *name)
1700 {
1701 int cm = CurrentMenu;
1702 int item = Menus[cm].NumItems++;
1703 if(!(Menus[cm].Items = realloc(Menus[cm].Items,
1704 Menus[cm].NumItems * sizeof(*Menus[0].Items)))) {
1705 sprintf(exiterror, "realloc failed in AddMenuItem\n");
1706 exit(0);
1707 }
1708 Menus[cm].Items[item].name = NULL;
1709 NameMenuEntry(item+1, name);
1710 return item;
1711 }
1712
1713 void glutAddMenuEntry(const char *name, int value)
1714 {
1715 int item = AddMenuItem(name);
1716 Menus[CurrentMenu].Items[item].value = value;
1717 Menus[CurrentMenu].Items[item].submenu = 0;
1718 }
1719
1720 void glutAddSubMenu(const char *name, int menu)
1721 {
1722 int item = AddMenuItem(name);
1723 if(menu == CurrentMenu) {
1724 sprintf(exiterror, "Recursive menus not supported\n");
1725 exit(0);
1726 }
1727 Menus[CurrentMenu].Items[item].submenu = menu;
1728 }
1729
1730 void glutChangeToMenuEntry(int entry, const char *name, int value)
1731 {
1732 NameMenuEntry(entry, name);
1733 Menus[CurrentMenu].Items[entry-1].value = value;
1734 Menus[CurrentMenu].Items[entry-1].submenu = 0;
1735 }
1736
1737 void glutChangeToSubMenu(int entry, const char *name, int menu)
1738 {
1739 NameMenuEntry(entry, name);
1740 Menus[CurrentMenu].Items[entry-1].submenu = menu;
1741 }
1742
1743 void glutRemoveMenuItem(int entry)
1744 {
1745 memmove(Menus[CurrentMenu].Items + entry - 1,
1746 Menus[CurrentMenu].Items + entry,
1747 sizeof(*Menus[0].Items) * (Menus[CurrentMenu].NumItems - entry));
1748 Menus[CurrentMenu].NumItems--;
1749 }
1750
1751 void glutAttachMenu(int button)
1752 {
1753 AttachedMenus[button] = CurrentMenu;
1754 }
1755
1756 void glutDetachMenu(int button)
1757 {
1758 AttachedMenus[button] = 0;
1759 }
1760
1761 /* --------- Callbacks ------------ */
1762 void glutDisplayFunc(void (*func)(void))
1763 {
1764 DisplayFunc = func;
1765 }
1766
1767 void glutOverlayDisplayFunc(void (*func)(void))
1768 {
1769 }
1770
1771 void glutReshapeFunc(void (*func)(int width, int height))
1772 {
1773 ReshapeFunc = func;
1774 }
1775
1776 void glutKeyboardFunc(void (*func)(unsigned char key, int x, int y))
1777 {
1778 KeyboardFunc = func;
1779 }
1780
1781 void glutMouseFunc(void (*func)(int button, int state, int x, int y))
1782 {
1783 MouseEnabled = 1;
1784 MouseFunc = func;
1785 }
1786
1787 void glutMotionFunc(void (*func)(int x, int y))
1788 {
1789 MouseEnabled = 1;
1790 MotionFunc = func;
1791 }
1792
1793 void glutPassiveMotionFunc(void (*func)(int x, int y))
1794 {
1795 MouseEnabled = 1;
1796 PassiveMotionFunc = func;
1797 }
1798
1799 void glutVisibilityFunc(void (*func)(int state))
1800 {
1801 VisibilityFunc = func;
1802 }
1803
1804 void glutEntryFunc(void (*func)(int state))
1805 {
1806 }
1807
1808 void glutSpecialFunc(void (*func)(int key, int x, int y))
1809 {
1810 SpecialFunc = func;
1811 }
1812
1813 void glutSpaceballMotionFunc(void (*func)(int x, int y, int z))
1814 {
1815 }
1816
1817 void glutSpaceballRotateFunc(void (*func)(int x, int y, int z))
1818 {
1819 }
1820
1821 void glutButtonBoxFunc(void (*func)(int button, int state))
1822 {
1823 }
1824
1825 void glutDialsFunc(void (*func)(int dial, int value))
1826 {
1827 }
1828
1829 void glutTabletMotionFunc(void (*func)(int x, int y))
1830 {
1831 }
1832
1833 void glutTabletButtonFunc(void (*func)(int button, int state,
1834 int x, int y))
1835 {
1836 }
1837
1838 void glutMenuStatusFunc(void (*func)(int status, int x, int y))
1839 {
1840 MenuStatusFunc = func;
1841 }
1842
1843 void glutMenuStateFunc(void (*func)(int status))
1844 {
1845 MenuStateFunc = func;
1846 }
1847
1848 void glutIdleFunc(void (*func)(void))
1849 {
1850 IdleFunc = func;
1851 }
1852
1853 void glutTimerFunc(unsigned int msecs,
1854 void (*func)(int value), int value)
1855 {
1856 struct GlutTimer *timer = malloc(sizeof *timer);
1857 timer->time = glutGet(GLUT_ELAPSED_TIME) + msecs;
1858 timer->func = func;
1859 timer->value = value;
1860
1861 struct GlutTimer **head = &GlutTimers;
1862 while(*head && (*head)->time < timer->time)
1863 head = &(*head)->next;
1864
1865 timer->next = *head;
1866 *head = timer;
1867 }
1868
1869 /* --------- Color Map ------------*/
1870 #define TOCMAP(x) (unsigned short)((x<0?0:x>1?1:x) * (GLfloat) (2<<16))
1871 #define FROMCMAP(x) (GLfloat)x / (GLfloat)(2<<16)
1872
1873 void glutSetColor(int cell, GLfloat red, GLfloat green, GLfloat blue)
1874 {
1875 if(cell >=0 && cell < 256) {
1876
1877 ColorMap.red[cell] = TOCMAP(red);
1878 ColorMap.green[cell] = TOCMAP(green);
1879 ColorMap.blue[cell] = TOCMAP(blue);
1880
1881 ColorMap.start = cell;
1882 ColorMap.len = 1;
1883
1884 if (ioctl(FrameBufferFD, FBIOPUTCMAP, (void *) &ColorMap) < 0)
1885 fprintf(stderr, "ioctl(FBIOPUTCMAP) failed [%d]\n", cell);
1886 }
1887 }
1888
1889 GLfloat glutGetColor(int cell, int component)
1890 {
1891 if(!(DisplayMode & GLUT_INDEX))
1892 return -1.0;
1893
1894 if(cell < 0 || cell > 256)
1895 return -1.0;
1896
1897 switch(component) {
1898 case GLUT_RED:
1899 return FROMCMAP(ColorMap.red[cell]);
1900 case GLUT_GREEN:
1901 return FROMCMAP(ColorMap.green[cell]);
1902 case GLUT_BLUE:
1903 return FROMCMAP(ColorMap.blue[cell]);
1904 }
1905 return -1.0;
1906 }
1907
1908 void glutCopyColormap(int win)
1909 {
1910 }
1911
1912 /* --------- State ------------*/
1913 void glutWarpPointer(int x, int y)
1914 {
1915 if(x < 0)
1916 x = 0;
1917 if(x >= VarInfo.xres)
1918 x = VarInfo.xres - 1;
1919 MouseX = x;
1920
1921 if(y < 0)
1922 y = 0;
1923 if(y >= VarInfo.yres)
1924 y = VarInfo.yres - 1;
1925 MouseY = y;
1926
1927 EraseCursor();
1928 SwapCursor();
1929 }
1930
1931 int glutGet(GLenum state)
1932 {
1933 switch(state) {
1934 case GLUT_WINDOW_X:
1935 return 0;
1936 case GLUT_WINDOW_Y:
1937 return 0;
1938 case GLUT_INIT_WINDOW_WIDTH:
1939 case GLUT_WINDOW_WIDTH:
1940 case GLUT_SCREEN_WIDTH:
1941 return VarInfo.xres;
1942 case GLUT_INIT_WINDOW_HEIGHT:
1943 case GLUT_WINDOW_HEIGHT:
1944 case GLUT_SCREEN_HEIGHT:
1945 return VarInfo.yres;
1946 case GLUT_WINDOW_BUFFER_SIZE:
1947 return VarInfo.bits_per_pixel;
1948 case GLUT_WINDOW_STENCIL_SIZE:
1949 return StencilSize;
1950 case GLUT_WINDOW_DEPTH_SIZE:
1951 return DepthSize;
1952 case GLUT_WINDOW_RED_SIZE:
1953 return VarInfo.red.length;
1954 case GLUT_WINDOW_GREEN_SIZE:
1955 return VarInfo.green.length;
1956 case GLUT_WINDOW_BLUE_SIZE:
1957 return VarInfo.green.length;
1958 case GLUT_WINDOW_ALPHA_SIZE:
1959 return VarInfo.transp.length;
1960 case GLUT_WINDOW_ACCUM_RED_SIZE:
1961 case GLUT_WINDOW_ACCUM_GREEN_SIZE:
1962 case GLUT_WINDOW_ACCUM_BLUE_SIZE:
1963 case GLUT_WINDOW_ACCUM_ALPHA_SIZE:
1964 return AccumSize;
1965 case GLUT_WINDOW_DOUBLEBUFFER:
1966 if(DisplayMode & GLUT_DOUBLE)
1967 return 1;
1968 return 0;
1969 case GLUT_WINDOW_RGBA:
1970 if(DisplayMode & GLUT_INDEX)
1971 return 0;
1972 return 1;
1973 case GLUT_WINDOW_PARENT:
1974 return 0;
1975 case GLUT_WINDOW_NUM_CHILDREN:
1976 return 0;
1977 case GLUT_WINDOW_COLORMAP_SIZE:
1978 if(DisplayMode & GLUT_INDEX)
1979 return 256;
1980 return 0;
1981 case GLUT_WINDOW_NUM_SAMPLES:
1982 return 0;
1983 case GLUT_WINDOW_STEREO:
1984 return 0;
1985 case GLUT_WINDOW_CURSOR:
1986 return CurrentCursor;
1987 case GLUT_SCREEN_WIDTH_MM:
1988 return VarInfo.width;
1989 case GLUT_SCREEN_HEIGHT_MM:
1990 return VarInfo.height;
1991 case GLUT_MENU_NUM_ITEMS:
1992 if(CurrentMenu)
1993 return Menus[CurrentMenu].NumItems;
1994 return 0;
1995 case GLUT_DISPLAY_MODE_POSSIBLE:
1996 if((DisplayMode & GLUT_MULTISAMPLE)
1997 || (DisplayMode & GLUT_STEREO)
1998 || (DisplayMode & GLUT_LUMINANCE)
1999 || (DisplayMode & GLUT_ALPHA) && (DisplayMode & GLUT_INDEX))
2000 return 0;
2001 return 1;
2002 case GLUT_INIT_DISPLAY_MODE:
2003 return DisplayMode;
2004 case GLUT_INIT_WINDOW_X:
2005 case GLUT_INIT_WINDOW_Y:
2006 return 0;
2007 case GLUT_ELAPSED_TIME:
2008 {
2009 static struct timeval tv;
2010 gettimeofday(&tv, 0);
2011 return 1000 * (tv.tv_sec - StartTime.tv_sec)
2012 + (tv.tv_usec - StartTime.tv_usec) / 1000;
2013 }
2014 }
2015 }
2016
2017 int glutLayerGet(GLenum info)
2018 {
2019 switch(info) {
2020 case GLUT_OVERLAY_POSSIBLE:
2021 return 0;
2022 case GLUT_LAYER_IN_USE:
2023 return GLUT_NORMAL;
2024 case GLUT_HAS_OVERLAY:
2025 return 0;
2026 case GLUT_TRANSPARENT_INDEX:
2027 return -1;
2028 case GLUT_NORMAL_DAMAGED:
2029 return Redisplay;
2030 case GLUT_OVERLAY_DAMAGED:
2031 return -1;
2032 }
2033 return -1;
2034 }
2035
2036 int glutDeviceGet(GLenum info)
2037 {
2038 switch(info) {
2039 case GLUT_HAS_KEYBOARD:
2040 return 1;
2041 case GLUT_HAS_MOUSE:
2042 case GLUT_NUM_MOUSE_BUTTONS:
2043 return NumMouseButtons;
2044 case GLUT_HAS_SPACEBALL:
2045 case GLUT_HAS_DIAL_AND_BUTTON_BOX:
2046 case GLUT_HAS_TABLET:
2047 return 0;
2048 case GLUT_NUM_SPACEBALL_BUTTONS:
2049 case GLUT_NUM_BUTTON_BOX_BUTTONS:
2050 case GLUT_NUM_DIALS:
2051 case GLUT_NUM_TABLET_BUTTONS:
2052 return 0;
2053 }
2054 return -1;
2055 }
2056
2057 int glutGetModifiers(void){
2058 return KeyboardModifiers;
2059 }
2060
2061 /* ------------- extensions ------------ */
2062 int glutExtensionSupported(const char *extension)
2063 {
2064 const char *exts = (const char *) glGetString(GL_EXTENSIONS);
2065 const char *start = exts;
2066 int len = strlen(extension);
2067
2068 for(;;) {
2069 const char *p = strstr(exts, extension);
2070 if(!p)
2071 break;
2072 if((p == start || p[-1] == ' ') && (p[len] == ' ' || p[len] == 0))
2073 return 1;
2074 exts = p + len;
2075 }
2076 return 0;
2077 }
2078
2079 void glutReportErrors(void)
2080 {
2081 GLenum error;
2082
2083 while ((error = glGetError()) != GL_NO_ERROR)
2084 fprintf(stderr, "GL error: %s", gluErrorString(error));
2085 }
2086
2087 static struct {
2088 const char *name;
2089 const GLUTproc address;
2090 } glut_functions[] = {
2091 { "glutInit", (const GLUTproc) glutInit },
2092 { "glutInitDisplayMode", (const GLUTproc) glutInitDisplayMode },
2093 { "glutInitWindowPosition", (const GLUTproc) glutInitWindowPosition },
2094 { "glutInitWindowSize", (const GLUTproc) glutInitWindowSize },
2095 { "glutMainLoop", (const GLUTproc) glutMainLoop },
2096 { "glutCreateWindow", (const GLUTproc) glutCreateWindow },
2097 { "glutCreateSubWindow", (const GLUTproc) glutCreateSubWindow },
2098 { "glutDestroyWindow", (const GLUTproc) glutDestroyWindow },
2099 { "glutPostRedisplay", (const GLUTproc) glutPostRedisplay },
2100 { "glutSwapBuffers", (const GLUTproc) glutSwapBuffers },
2101 { "glutGetWindow", (const GLUTproc) glutGetWindow },
2102 { "glutSetWindow", (const GLUTproc) glutSetWindow },
2103 { "glutSetWindowTitle", (const GLUTproc) glutSetWindowTitle },
2104 { "glutSetIconTitle", (const GLUTproc) glutSetIconTitle },
2105 { "glutPositionWindow", (const GLUTproc) glutPositionWindow },
2106 { "glutReshapeWindow", (const GLUTproc) glutReshapeWindow },
2107 { "glutPopWindow", (const GLUTproc) glutPopWindow },
2108 { "glutPushWindow", (const GLUTproc) glutPushWindow },
2109 { "glutIconifyWindow", (const GLUTproc) glutIconifyWindow },
2110 { "glutShowWindow", (const GLUTproc) glutShowWindow },
2111 { "glutHideWindow", (const GLUTproc) glutHideWindow },
2112 { "glutFullScreen", (const GLUTproc) glutFullScreen },
2113 { "glutSetCursor", (const GLUTproc) glutSetCursor },
2114 { "glutWarpPointer", (const GLUTproc) glutWarpPointer },
2115 { "glutEstablishOverlay", (const GLUTproc) glutEstablishOverlay },
2116 { "glutRemoveOverlay", (const GLUTproc) glutRemoveOverlay },
2117 { "glutUseLayer", (const GLUTproc) glutUseLayer },
2118 { "glutPostOverlayRedisplay", (const GLUTproc) glutPostOverlayRedisplay },
2119 { "glutShowOverlay", (const GLUTproc) glutShowOverlay },
2120 { "glutHideOverlay", (const GLUTproc) glutHideOverlay },
2121 { "glutCreateMenu", (const GLUTproc) glutCreateMenu },
2122 { "glutDestroyMenu", (const GLUTproc) glutDestroyMenu },
2123 { "glutGetMenu", (const GLUTproc) glutGetMenu },
2124 { "glutSetMenu", (const GLUTproc) glutSetMenu },
2125 { "glutAddMenuEntry", (const GLUTproc) glutAddMenuEntry },
2126 { "glutAddSubMenu", (const GLUTproc) glutAddSubMenu },
2127 { "glutChangeToMenuEntry", (const GLUTproc) glutChangeToMenuEntry },
2128 { "glutChangeToSubMenu", (const GLUTproc) glutChangeToSubMenu },
2129 { "glutRemoveMenuItem", (const GLUTproc) glutRemoveMenuItem },
2130 { "glutAttachMenu", (const GLUTproc) glutAttachMenu },
2131 { "glutDetachMenu", (const GLUTproc) glutDetachMenu },
2132 { "glutDisplayFunc", (const GLUTproc) glutDisplayFunc },
2133 { "glutReshapeFunc", (const GLUTproc) glutReshapeFunc },
2134 { "glutKeyboardFunc", (const GLUTproc) glutKeyboardFunc },
2135 { "glutMouseFunc", (const GLUTproc) glutMouseFunc },
2136 { "glutMotionFunc", (const GLUTproc) glutMotionFunc },
2137 { "glutPassiveMotionFunc", (const GLUTproc) glutPassiveMotionFunc },
2138 { "glutEntryFunc", (const GLUTproc) glutEntryFunc },
2139 { "glutVisibilityFunc", (const GLUTproc) glutVisibilityFunc },
2140 { "glutIdleFunc", (const GLUTproc) glutIdleFunc },
2141 { "glutTimerFunc", (const GLUTproc) glutTimerFunc },
2142 { "glutMenuStateFunc", (const GLUTproc) glutMenuStateFunc },
2143 { "glutSpecialFunc", (const GLUTproc) glutSpecialFunc },
2144 { "glutSpaceballRotateFunc", (const GLUTproc) glutSpaceballRotateFunc },
2145 { "glutButtonBoxFunc", (const GLUTproc) glutButtonBoxFunc },
2146 { "glutDialsFunc", (const GLUTproc) glutDialsFunc },
2147 { "glutTabletMotionFunc", (const GLUTproc) glutTabletMotionFunc },
2148 { "glutTabletButtonFunc", (const GLUTproc) glutTabletButtonFunc },
2149 { "glutMenuStatusFunc", (const GLUTproc) glutMenuStatusFunc },
2150 { "glutOverlayDisplayFunc", (const GLUTproc) glutOverlayDisplayFunc },
2151 { "glutSetColor", (const GLUTproc) glutSetColor },
2152 { "glutGetColor", (const GLUTproc) glutGetColor },
2153 { "glutCopyColormap", (const GLUTproc) glutCopyColormap },
2154 { "glutGet", (const GLUTproc) glutGet },
2155 { "glutDeviceGet", (const GLUTproc) glutDeviceGet },
2156 { "glutExtensionSupported", (const GLUTproc) glutExtensionSupported },
2157 { "glutGetModifiers", (const GLUTproc) glutGetModifiers },
2158 { "glutLayerGet", (const GLUTproc) glutLayerGet },
2159 { "glutGetProcAddress", (const GLUTproc) glutGetProcAddress },
2160 { "glutBitmapCharacter", (const GLUTproc) glutBitmapCharacter },
2161 { "glutBitmapWidth", (const GLUTproc) glutBitmapWidth },
2162 { "glutStrokeCharacter", (const GLUTproc) glutStrokeCharacter },
2163 { "glutStrokeWidth", (const GLUTproc) glutStrokeWidth },
2164 { "glutBitmapLength", (const GLUTproc) glutBitmapLength },
2165 { "glutStrokeLength", (const GLUTproc) glutStrokeLength },
2166 { "glutWireSphere", (const GLUTproc) glutWireSphere },
2167 { "glutSolidSphere", (const GLUTproc) glutSolidSphere },
2168 { "glutWireCone", (const GLUTproc) glutWireCone },
2169 { "glutSolidCone", (const GLUTproc) glutSolidCone },
2170 { "glutWireCube", (const GLUTproc) glutWireCube },
2171 { "glutSolidCube", (const GLUTproc) glutSolidCube },
2172 { "glutWireTorus", (const GLUTproc) glutWireTorus },
2173 { "glutSolidTorus", (const GLUTproc) glutSolidTorus },
2174 { "glutWireDodecahedron", (const GLUTproc) glutWireDodecahedron },
2175 { "glutSolidDodecahedron", (const GLUTproc) glutSolidDodecahedron },
2176 { "glutWireTeapot", (const GLUTproc) glutWireTeapot },
2177 { "glutSolidTeapot", (const GLUTproc) glutSolidTeapot },
2178 { "glutWireOctahedron", (const GLUTproc) glutWireOctahedron },
2179 { "glutSolidOctahedron", (const GLUTproc) glutSolidOctahedron },
2180 { "glutWireTetrahedron", (const GLUTproc) glutWireTetrahedron },
2181 { "glutSolidTetrahedron", (const GLUTproc) glutSolidTetrahedron },
2182 { "glutWireIcosahedron", (const GLUTproc) glutWireIcosahedron },
2183 { "glutSolidIcosahedron", (const GLUTproc) glutSolidIcosahedron },
2184 { "glutReportErrors", (const GLUTproc) glutReportErrors },
2185 { NULL, NULL }
2186 };
2187
2188 GLUTproc glutGetProcAddress(const char *procName)
2189 {
2190 /* Try GLUT functions first */
2191 int i;
2192 for (i = 0; glut_functions[i].name; i++) {
2193 if (strcmp(glut_functions[i].name, procName) == 0)
2194 return glut_functions[i].address;
2195 }
2196
2197 /* Try core GL functions */
2198 return (GLUTproc) glFBDevGetProcAddress(procName);
2199 }