mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-01-27 07:40:31 +01:00
2199 lines
52 KiB
C
2199 lines
52 KiB
C
/*
|
|
* Mesa 3-D graphics library
|
|
* Version: 6.5
|
|
* Copyright (C) 1995-2006 Brian Paul
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the Free
|
|
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
/*
|
|
* Library for glut using mesa fbdev driver
|
|
*
|
|
* Written by Sean D'Epagnier (c) 2006
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <termios.h>
|
|
#include <inttypes.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/types.h>
|
|
#include <sys/time.h>
|
|
#include <sys/poll.h>
|
|
#include <sys/types.h>
|
|
#include <sys/kd.h>
|
|
|
|
#include <linux/fb.h>
|
|
#include <linux/keyboard.h>
|
|
#include <linux/vt.h>
|
|
|
|
#include <GL/gl.h>
|
|
#include <GL/glfbdev.h>
|
|
#include <GL/glut.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include "../../mesa/main/config.h"
|
|
|
|
#define MULTIHEAD /* enable multihead hacks,
|
|
it allows the program to continue drawing
|
|
without reading input when a second fbdev
|
|
has keyboard focus it can cause
|
|
screen corruption that requires C-l to fix */
|
|
|
|
#define FBMODES "/etc/fb.modes"
|
|
|
|
#define HAVE_GPM
|
|
|
|
#ifdef HAVE_GPM
|
|
#include <gpm.h>
|
|
static int GpmMouse;
|
|
#endif
|
|
|
|
#define MOUSEDEV "/dev/gpmdata"
|
|
|
|
static int CurrentVT;
|
|
static int ConsoleFD = - 1;
|
|
|
|
/* save settings to restore on exit */
|
|
static int OldKDMode = -1;
|
|
static int OldMode;
|
|
struct vt_mode OldVTMode;
|
|
struct termios OldTermios;
|
|
|
|
static struct fb_fix_screeninfo FixedInfo;
|
|
static struct fb_var_screeninfo VarInfo, OrigVarInfo;
|
|
struct fb_cmap ColorMap;
|
|
|
|
static int DesiredDepth = 0;
|
|
|
|
static int FrameBufferFD = -1;
|
|
static caddr_t FrameBuffer = (caddr_t) -1;
|
|
static caddr_t BackBuffer = NULL;
|
|
static int DisplayMode;
|
|
|
|
static int AccumSize = 16; /* per channel size of accumulation buffer */
|
|
static int DepthSize = DEFAULT_SOFTWARE_DEPTH_BITS;
|
|
static int StencilSize = STENCIL_BITS;
|
|
|
|
#define MENU_FONT_WIDTH 9
|
|
#define MENU_FONT_HEIGHT 15
|
|
#define MENU_FONT GLUT_BITMAP_9_BY_15
|
|
#define SUBMENU_OFFSET 20
|
|
|
|
static int AttachedMenus[3];
|
|
static int ActiveMenu;
|
|
static int SelectedMenu;
|
|
static int CurrentMenu;
|
|
static int NumMenus = 1;
|
|
|
|
static struct {
|
|
int NumItems;
|
|
int x, y;
|
|
int width;
|
|
int selected;
|
|
struct {
|
|
int value;
|
|
int submenu;
|
|
char *name;
|
|
} *Items;
|
|
void (*func)(int);
|
|
} *Menus = NULL;
|
|
|
|
struct GlutTimer {
|
|
int time;
|
|
void (*func)(int);
|
|
int value;
|
|
struct GlutTimer *next;
|
|
};
|
|
|
|
struct GlutTimer *GlutTimers = NULL;
|
|
|
|
static struct timeval StartTime;
|
|
|
|
static int KeyboardModifiers;
|
|
static int KeyboardLedState;
|
|
|
|
static int MouseFD;
|
|
static int NumMouseButtons;
|
|
static int MouseX;
|
|
static int MouseY;
|
|
static double MouseSpeed = 0;
|
|
static int CurrentCursor = GLUT_CURSOR_LEFT_ARROW;
|
|
/* only display the mouse if there is a registered callback for it */
|
|
static int MouseEnabled = 0;
|
|
|
|
/* per window data */
|
|
static GLFBDevContextPtr Context;
|
|
static GLFBDevBufferPtr Buffer;
|
|
static GLFBDevVisualPtr Visual;
|
|
static void (*DisplayFunc)(void) = NULL;
|
|
static void (*ReshapeFunc)(int width, int height) = NULL;
|
|
static void (*KeyboardFunc)(unsigned char key, int x, int y) = NULL;
|
|
static void (*MouseFunc)(int key, int state, int x, int y) = NULL;
|
|
static void (*MotionFunc)(int x, int y) = NULL;
|
|
static void (*PassiveMotionFunc)(int x, int y) = NULL;
|
|
static void (*VisibilityFunc)(int state) = NULL;
|
|
static void (*SpecialFunc)(int key, int x, int y) = NULL;
|
|
static void (*IdleFunc)(void) = NULL;
|
|
static void (*MenuStatusFunc)(int state, int x, int y) = NULL;
|
|
static void (*MenuStateFunc)(int state) = NULL;
|
|
|
|
static int Redisplay;
|
|
static int Visible;
|
|
static int VisibleSwitch;
|
|
static int Active;
|
|
/* we have to poll to see if we are visible
|
|
on a framebuffer that is not active */
|
|
static int VisiblePoll;
|
|
static int FramebufferIndex;
|
|
|
|
static int RequiredWidth;
|
|
static int RequiredHeight;
|
|
static int InitialWidthHint;
|
|
static int InitialHeightHint;
|
|
|
|
static char exiterror[256];
|
|
|
|
/* --------- Initialization ------------*/
|
|
/* test if the active console is attached to the same framebuffer */
|
|
static void TestVisible(void) {
|
|
struct fb_con2fbmap confb;
|
|
struct vt_stat st;
|
|
int ret;
|
|
ioctl(ConsoleFD, VT_GETSTATE, &st);
|
|
confb.console = st.v_active;
|
|
|
|
ret = ioctl(FrameBufferFD, FBIOGET_CON2FBMAP, &confb);
|
|
|
|
if(ret == -1 || confb.framebuffer == FramebufferIndex) {
|
|
VisibleSwitch = 1;
|
|
Visible = 0;
|
|
VisiblePoll = 0;
|
|
}
|
|
}
|
|
|
|
static void VTSwitchHandler(int sig)
|
|
{
|
|
struct vt_stat st;
|
|
switch(sig) {
|
|
case SIGUSR1:
|
|
ioctl(ConsoleFD, VT_RELDISP, 1);
|
|
Active = 0;
|
|
#ifdef MULTIHEAD
|
|
VisiblePoll = 1;
|
|
TestVisible();
|
|
#else
|
|
VisibleSwitch = 1;
|
|
Visible = 0;
|
|
#endif
|
|
break;
|
|
case SIGUSR2:
|
|
ioctl(ConsoleFD, VT_GETSTATE, &st);
|
|
if(st.v_active)
|
|
ioctl(ConsoleFD, VT_RELDISP, VT_ACKACQ);
|
|
|
|
/* this is a hack to turn the cursor off */
|
|
ioctl(FrameBufferFD, FBIOPUT_VSCREENINFO, &VarInfo);
|
|
|
|
/* restore color map */
|
|
if(DisplayMode & GLUT_INDEX) {
|
|
ColorMap.start = 0;
|
|
ColorMap.len = 256;
|
|
|
|
if (ioctl(FrameBufferFD, FBIOPUTCMAP, (void *) &ColorMap) < 0)
|
|
fprintf(stderr, "ioctl(FBIOPUTCMAP) failed!\n");
|
|
}
|
|
|
|
Active = 1;
|
|
Visible = 1;
|
|
VisibleSwitch = 1;
|
|
|
|
Redisplay = 1;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void Cleanup(void)
|
|
{
|
|
if(ConsoleFD >= 0)
|
|
if (tcsetattr(0, TCSANOW, &OldTermios) < 0)
|
|
fprintf(stderr, "tcsetattr failed\n");
|
|
|
|
if(ConsoleFD > 0) {
|
|
/* restore keyboard state */
|
|
if (ioctl(ConsoleFD, VT_SETMODE, &OldVTMode) < 0)
|
|
fprintf(stderr, "Failed to set vtmode\n");
|
|
|
|
if (ioctl(ConsoleFD, KDSKBMODE, OldKDMode) < 0)
|
|
fprintf(stderr, "ioctl KDSKBMODE failed!\n");
|
|
|
|
if(ioctl(ConsoleFD, KDSETMODE, OldMode) < 0)
|
|
fprintf(stderr, "ioctl KDSETMODE failed!\n");
|
|
|
|
close(ConsoleFD);
|
|
}
|
|
|
|
/* close mouse */
|
|
#ifdef HAVE_GPM
|
|
if(GpmMouse) {
|
|
if(NumMouseButtons)
|
|
Gpm_Close();
|
|
} else
|
|
#endif
|
|
if(MouseFD >= 0)
|
|
close(MouseFD);
|
|
|
|
glFBDevMakeCurrent( NULL, NULL, NULL);
|
|
|
|
glFBDevDestroyContext(Context);
|
|
glFBDevDestroyBuffer(Buffer);
|
|
glFBDevDestroyVisual(Visual);
|
|
|
|
struct vt_mode VT;
|
|
|
|
/* restore original variable screen info */
|
|
if(FrameBufferFD != -1) {
|
|
if (ioctl(FrameBufferFD, FBIOPUT_VSCREENINFO, &OrigVarInfo))
|
|
fprintf(stderr, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
|
|
strerror(errno));
|
|
|
|
munmap(FrameBuffer, FixedInfo.smem_len);
|
|
close(FrameBufferFD);
|
|
}
|
|
|
|
/* free allocated back buffer */
|
|
if(DisplayMode & GLUT_DOUBLE)
|
|
free(BackBuffer);
|
|
|
|
/* free menu items */
|
|
int i, j;
|
|
|
|
for(i = 1; i<NumMenus; i++) {
|
|
for(i = 1; i<Menus[i].NumItems; i++)
|
|
free(Menus[i].Items[j].name);
|
|
free(Menus[i].Items);
|
|
}
|
|
free(Menus);
|
|
|
|
if(exiterror[0])
|
|
fprintf(stderr, "[glfbdev glut] %s", exiterror);
|
|
}
|
|
|
|
static void CrashHandler(int sig)
|
|
{
|
|
sprintf(exiterror, "Caught signal %d, cleaning up\n", sig);
|
|
exit(0);
|
|
}
|
|
|
|
static void InitializeVT(int usestdin)
|
|
{
|
|
/* terminos settings for straight-through mode */
|
|
if (tcgetattr(0, &OldTermios) < 0) {
|
|
sprintf(exiterror, "tcgetattr failed\n");
|
|
exit(0);
|
|
}
|
|
|
|
struct termios tio = OldTermios;
|
|
|
|
tio.c_lflag &= ~(ICANON | ECHO | ISIG);
|
|
tio.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON);
|
|
tio.c_iflag |= IGNBRK;
|
|
tio.c_cc[VMIN] = 0;
|
|
tio.c_cc[VTIME] = 0;
|
|
|
|
if (tcsetattr(0, TCSANOW, &tio) < 0) {
|
|
sprintf(exiterror, "tcsetattr failed\n");
|
|
exit(0);
|
|
}
|
|
|
|
if(fcntl(0, F_SETFL, O_NONBLOCK) < 0) {
|
|
sprintf(exiterror, "Failed to set keyboard to non-blocking\n");
|
|
exit(0);
|
|
}
|
|
|
|
Active = 1;
|
|
|
|
if(usestdin) {
|
|
ConsoleFD = 0;
|
|
return;
|
|
}
|
|
|
|
/* detect the current vt if it was not specified */
|
|
if(CurrentVT == 0) {
|
|
int fd = open("/dev/tty", O_RDWR | O_NDELAY, 0);
|
|
struct vt_stat st;
|
|
if(fd == -1) {
|
|
sprintf(exiterror, "Failed to open /dev/tty\n");
|
|
exit(0);
|
|
}
|
|
if(ioctl(fd, VT_GETSTATE, &st) == -1) {
|
|
fprintf(stderr, "Could not detect current vt, specify with -vt\n");
|
|
fprintf(stderr, "Defaulting to stdin input\n");
|
|
ConsoleFD = 0;
|
|
close(fd);
|
|
return;
|
|
} else
|
|
CurrentVT = st.v_active;
|
|
|
|
close(fd);
|
|
}
|
|
|
|
/* open the console tty */
|
|
char console[128];
|
|
sprintf(console, "/dev/tty%d", CurrentVT);
|
|
ConsoleFD = open(console, O_RDWR | O_NDELAY, 0);
|
|
if (ConsoleFD < 0) {
|
|
sprintf(exiterror, "error couldn't open %s,"
|
|
" defaulting to stdin \n", console);
|
|
ConsoleFD = 0;
|
|
return;
|
|
}
|
|
|
|
signal(SIGUSR1, VTSwitchHandler);
|
|
signal(SIGUSR2, VTSwitchHandler);
|
|
|
|
struct vt_mode vt;
|
|
|
|
if (ioctl(ConsoleFD, VT_GETMODE, &OldVTMode) < 0) {
|
|
sprintf(exiterror,"Failed to grab %s, defaulting to stdin\n", console);
|
|
close(ConsoleFD);
|
|
ConsoleFD = 0;
|
|
return;
|
|
}
|
|
|
|
vt = OldVTMode;
|
|
|
|
vt.mode = VT_PROCESS;
|
|
vt.waitv = 0;
|
|
vt.relsig = SIGUSR1;
|
|
vt.acqsig = SIGUSR2;
|
|
if (ioctl(ConsoleFD, VT_SETMODE, &vt) < 0) {
|
|
sprintf(exiterror, "error: ioctl(VT_SETMODE) failed: %s\n",
|
|
strerror(errno));
|
|
close(ConsoleFD);
|
|
ConsoleFD = 0;
|
|
exit(1);
|
|
}
|
|
|
|
if (ioctl(ConsoleFD, KDGKBMODE, &OldKDMode) < 0) {
|
|
fprintf(stderr, "warning: ioctl KDGKBMODE failed!\n");
|
|
OldKDMode = K_XLATE;
|
|
}
|
|
|
|
if(ioctl(ConsoleFD, KDGETMODE, &OldMode) < 0)
|
|
sprintf(exiterror, "Warning: Failed to get terminal mode\n");
|
|
|
|
#ifdef HAVE_GPM
|
|
if(!GpmMouse)
|
|
#endif
|
|
if(ioctl(ConsoleFD, KDSETMODE, KD_GRAPHICS) < 0)
|
|
sprintf(exiterror,"Warning: Failed to set terminal to graphics\n");
|
|
|
|
|
|
if (ioctl(ConsoleFD, KDSKBMODE, K_MEDIUMRAW) < 0) {
|
|
sprintf(exiterror, "ioctl KDSKBMODE failed!\n");
|
|
tcsetattr(0, TCSANOW, &OldTermios);
|
|
exit(0);
|
|
}
|
|
|
|
if( ioctl(ConsoleFD, KDGKBLED, &KeyboardLedState) < 0) {
|
|
sprintf(exiterror, "ioctl KDGKBLED failed!\n");
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
static void InitializeMouse(void)
|
|
{
|
|
#ifdef HAVE_GPM
|
|
if(GpmMouse) {
|
|
Gpm_Connect conn;
|
|
int c;
|
|
conn.eventMask = ~0; /* Want to know about all the events */
|
|
conn.defaultMask = 0; /* don't handle anything by default */
|
|
conn.minMod = 0; /* want everything */
|
|
conn.maxMod = ~0; /* all modifiers included */
|
|
if(Gpm_Open(&conn, 0) == -1) {
|
|
fprintf(stderr, "Cannot open gpmctl. Continuing without Mouse\n");
|
|
return;
|
|
}
|
|
|
|
if(!MouseSpeed)
|
|
MouseSpeed = 5;
|
|
} else
|
|
#endif
|
|
{
|
|
const char *mousedev = getenv("MOUSE");
|
|
if(!mousedev)
|
|
mousedev = MOUSEDEV;
|
|
if((MouseFD = open(mousedev, O_RDONLY)) < 0) {
|
|
fprintf(stderr,"Cannot open %s.\n"
|
|
"Continuing without Mouse\n", MOUSEDEV);
|
|
return;
|
|
}
|
|
|
|
if(!MouseSpeed)
|
|
MouseSpeed = 1;
|
|
}
|
|
|
|
NumMouseButtons = 3;
|
|
}
|
|
|
|
static void removeArgs(int *argcp, char **argv, int num)
|
|
{
|
|
int i;
|
|
for (i = 0; argv[i+num]; i++)
|
|
argv[i] = argv[i+num];
|
|
|
|
argv[i] = NULL;
|
|
*argcp -= num;
|
|
}
|
|
|
|
#define REQPARAM(PARAM) \
|
|
if (i >= *argcp - 1) { \
|
|
fprintf(stderr, PARAM" requires a parameter\n"); \
|
|
exit(0); \
|
|
}
|
|
|
|
void glutInit (int *argcp, char **argv)
|
|
{
|
|
int i;
|
|
int nomouse = 0;
|
|
int nokeyboard = 0;
|
|
int usestdin = 0;
|
|
|
|
/* parse out args */
|
|
for (i = 1; i < *argcp;) {
|
|
if (!strcmp(argv[i], "-geometry")) {
|
|
REQPARAM("geometry");
|
|
if(sscanf(argv[i+1], "%dx%d", &RequiredWidth,
|
|
&RequiredHeight) != 2) {
|
|
fprintf(stderr,"Please specify geometry as widthxheight\n");
|
|
exit(0);
|
|
}
|
|
removeArgs(argcp, &argv[i], 2);
|
|
} else
|
|
if (!strcmp(argv[i], "-bpp")) {
|
|
REQPARAM("bpp");
|
|
if(sscanf(argv[i+1], "%d", &DesiredDepth) != 1) {
|
|
fprintf(stderr, "Please specify a parameter for bpp\n");
|
|
exit(0);
|
|
}
|
|
|
|
removeArgs(argcp, &argv[i], 2);
|
|
} else
|
|
if (!strcmp(argv[i], "-vt")) {
|
|
REQPARAM("vt");
|
|
if(sscanf(argv[i+1], "%d", &CurrentVT) != 1) {
|
|
fprintf(stderr, "Please specify a parameter for vt\n");
|
|
exit(0);
|
|
}
|
|
removeArgs(argcp, &argv[i], 2);
|
|
} else
|
|
if (!strcmp(argv[i], "-mousespeed")) {
|
|
REQPARAM("mousespeed");
|
|
if(sscanf(argv[i+1], "%lf", &MouseSpeed) != 1) {
|
|
fprintf(stderr, "Please specify a mouse speed, eg: 2.5\n");
|
|
exit(0);
|
|
}
|
|
removeArgs(argcp, &argv[i], 2);
|
|
} else
|
|
if (!strcmp(argv[i], "-nomouse")) {
|
|
nomouse = 1;
|
|
removeArgs(argcp, &argv[i], 1);
|
|
} else
|
|
if (!strcmp(argv[i], "-nokeyboard")) {
|
|
nokeyboard = 1;
|
|
removeArgs(argcp, &argv[i], 1);
|
|
} else
|
|
if (!strcmp(argv[i], "-stdin")) {
|
|
usestdin = 1;
|
|
removeArgs(argcp, &argv[i], 1);
|
|
} else
|
|
if (!strcmp(argv[i], "-gpmmouse")) {
|
|
#ifdef HAVE_GPM
|
|
GpmMouse = 1;
|
|
#else
|
|
fprintf(stderr, "gpm support was not compiled\n");
|
|
exit(0);
|
|
#endif
|
|
removeArgs(argcp, &argv[i], 1);
|
|
} else
|
|
if (!strcmp(argv[i], "--")) {
|
|
removeArgs(argcp, &argv[i], 1);
|
|
break;
|
|
} else
|
|
i++;
|
|
}
|
|
|
|
gettimeofday(&StartTime, 0);
|
|
atexit(Cleanup);
|
|
|
|
signal(SIGSEGV, CrashHandler);
|
|
signal(SIGINT, CrashHandler);
|
|
signal(SIGTERM, CrashHandler);
|
|
|
|
if(nomouse == 0)
|
|
InitializeMouse();
|
|
if(nokeyboard == 0)
|
|
InitializeVT(usestdin);
|
|
}
|
|
|
|
void glutInitDisplayMode (unsigned int mode)
|
|
{
|
|
DisplayMode = mode;
|
|
}
|
|
|
|
void glutInitWindowPosition (int x, int y)
|
|
{
|
|
}
|
|
|
|
void glutInitWindowSize (int width, int height)
|
|
{
|
|
InitialWidthHint = width;
|
|
InitialHeightHint = height;
|
|
}
|
|
|
|
/* --------- Mouse Rendering ------------*/
|
|
#include "cursors.h"
|
|
static int LastMouseX;
|
|
static int LastMouseY;
|
|
static unsigned char *MouseBuffer;
|
|
|
|
static void EraseCursor(void)
|
|
{
|
|
int off = LastMouseY * FixedInfo.line_length
|
|
+ LastMouseX * VarInfo.bits_per_pixel / 8;
|
|
int stride = CURSOR_WIDTH * VarInfo.bits_per_pixel / 8;
|
|
int i;
|
|
|
|
unsigned char *src = MouseBuffer;
|
|
|
|
for(i = 0; i<CURSOR_HEIGHT; i++) {
|
|
memcpy(BackBuffer + off, src, stride);
|
|
src += stride;
|
|
off += FixedInfo.line_length;
|
|
}
|
|
}
|
|
|
|
static void SaveCursor(int x, int y)
|
|
{
|
|
if(x < 0)
|
|
LastMouseX = 0;
|
|
else
|
|
if(x > (int)VarInfo.xres - CURSOR_WIDTH)
|
|
LastMouseX = VarInfo.xres - CURSOR_WIDTH;
|
|
else
|
|
LastMouseX = x;
|
|
|
|
if(y < 0)
|
|
LastMouseY = 0;
|
|
else
|
|
if(y > (int)VarInfo.yres - CURSOR_HEIGHT)
|
|
LastMouseY = VarInfo.yres - CURSOR_HEIGHT;
|
|
else
|
|
LastMouseY = y;
|
|
|
|
int off = LastMouseY * FixedInfo.line_length
|
|
+ LastMouseX * VarInfo.bits_per_pixel / 8;
|
|
int stride = CURSOR_WIDTH * VarInfo.bits_per_pixel / 8;
|
|
int i;
|
|
unsigned char *src = MouseBuffer;
|
|
for(i = 0; i<CURSOR_HEIGHT; i++) {
|
|
memcpy(src, BackBuffer + off, stride);
|
|
src += stride;
|
|
off += FixedInfo.line_length;
|
|
}
|
|
}
|
|
|
|
static void DrawCursor(void)
|
|
{
|
|
if(CurrentCursor < 0 || CurrentCursor >= NUM_CURSORS)
|
|
return;
|
|
|
|
int px = MouseX - CursorsXOffset[CurrentCursor];
|
|
int py = MouseY - CursorsYOffset[CurrentCursor];
|
|
|
|
SaveCursor(px, py);
|
|
|
|
int xoff = 0;
|
|
if(px < 0)
|
|
xoff = -px;
|
|
|
|
int xlen = CURSOR_WIDTH;
|
|
if(px + CURSOR_WIDTH > VarInfo.xres)
|
|
xlen = VarInfo.xres - px;
|
|
|
|
int yoff = 0;
|
|
if(py < 0)
|
|
yoff = -py;
|
|
|
|
int ylen = CURSOR_HEIGHT;
|
|
if(py + CURSOR_HEIGHT > VarInfo.yres)
|
|
ylen = VarInfo.yres - py;
|
|
|
|
int bypp = VarInfo.bits_per_pixel / 8;
|
|
|
|
unsigned char *c = BackBuffer + FixedInfo.line_length * (py + yoff)
|
|
+ (px + xoff) * bypp;
|
|
|
|
unsigned char *d = Cursors[CurrentCursor] + (CURSOR_WIDTH * yoff + xoff)*4;
|
|
int i, j;
|
|
|
|
int dstride = (CURSOR_WIDTH - xlen + xoff) * 4;
|
|
int cstride = FixedInfo.line_length - bypp * (xlen - xoff);
|
|
|
|
switch(bypp) {
|
|
case 1: /* no support for 8bpp mouse yet */
|
|
break;
|
|
case 2:
|
|
{
|
|
uint16_t *e = (void*)c;
|
|
cstride /= 2;
|
|
for(i = yoff; i < ylen; i++) {
|
|
for(j = xoff; j < xlen; j++) {
|
|
e[0] = ((((d[0] + (((int)(((e[0] >> 8) & 0xf8)
|
|
| ((c[0] >> 11) & 0x7)) * d[3]) >> 8)) & 0xf8) << 8)
|
|
| (((d[1] + (((int)(((e[0] >> 3) & 0xfc)
|
|
| ((e[0] >> 5) & 0x3)) * d[3]) >> 8)) & 0xfc) << 3)
|
|
| ((d[2] + (((int)(((e[0] << 3) & 0xf8)
|
|
| (e[0] & 0x7)) * d[3]) >> 8)) >> 3));
|
|
|
|
e++;
|
|
d+=4;
|
|
}
|
|
d += dstride;
|
|
e += cstride;
|
|
}
|
|
}
|
|
break;
|
|
case 3:
|
|
case 4:
|
|
for(i = yoff; i < ylen; i++) {
|
|
for(j = xoff; j < xlen; j++) {
|
|
c[0] = d[0] + (((int)c[0] * d[3]) >> 8);
|
|
c[1] = d[1] + (((int)c[1] * d[3]) >> 8);
|
|
c[2] = d[2] + (((int)c[2] * d[3]) >> 8);
|
|
|
|
c+=bypp;
|
|
d+=4;
|
|
}
|
|
d += dstride;
|
|
c += cstride;
|
|
} break;
|
|
}
|
|
}
|
|
|
|
#define MIN(x, y) x < y ? x : y
|
|
static void SwapCursor(void)
|
|
{
|
|
int px = MouseX - CursorsXOffset[CurrentCursor];
|
|
int py = MouseY - CursorsYOffset[CurrentCursor];
|
|
|
|
int minx = MIN(px, LastMouseX);
|
|
int sizex = abs(px - LastMouseX);
|
|
|
|
int miny = MIN(py, LastMouseY);
|
|
int sizey = abs(py - LastMouseY);
|
|
|
|
DrawCursor();
|
|
/* now update the portion of the screen that has changed */
|
|
|
|
if(DisplayMode & GLUT_DOUBLE && (sizex || sizey)) {
|
|
if(minx < 0)
|
|
minx = 0;
|
|
if(miny < 0)
|
|
miny = 0;
|
|
|
|
if(minx + sizex > VarInfo.xres)
|
|
sizex = VarInfo.xres - minx;
|
|
if(miny + sizey > VarInfo.yres)
|
|
sizey = VarInfo.yres - miny;
|
|
int off = FixedInfo.line_length * miny
|
|
+ minx * VarInfo.bits_per_pixel / 8;
|
|
int stride = (sizex + CURSOR_WIDTH) * VarInfo.bits_per_pixel / 8;
|
|
int i;
|
|
for(i = 0; i< sizey + CURSOR_HEIGHT; i++) {
|
|
memcpy(FrameBuffer+off, BackBuffer+off, stride);
|
|
off += FixedInfo.line_length;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* --------- Menu Rendering ------------*/
|
|
static double MenuProjection[16];
|
|
static double MenuModelview[16];
|
|
|
|
static void InitMenuMatrices(void)
|
|
{
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
gluOrtho2D(0.0,VarInfo.xres,VarInfo.yres,0.0);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
glViewport(0,0,VarInfo.xres,VarInfo.yres);
|
|
glGetDoublev(GL_PROJECTION_MATRIX, MenuProjection);
|
|
glGetDoublev(GL_MODELVIEW_MATRIX, MenuModelview);
|
|
}
|
|
|
|
static int DrawMenu(int menu, int x, int *y)
|
|
{
|
|
int i;
|
|
int ret = 1;
|
|
for(i=0; i < Menus[menu].NumItems; i++) {
|
|
char *s = Menus[menu].Items[i].name;
|
|
int a =0;
|
|
if(MouseY >= *y && MouseY < *y + MENU_FONT_HEIGHT &&
|
|
MouseX >= x && MouseX < x + Menus[menu].width) {
|
|
a = 1;
|
|
SelectedMenu = menu;
|
|
ret = 0;
|
|
Menus[menu].selected = i;
|
|
glColor3f(1,0,0);
|
|
} else
|
|
glColor3f(0,0,1);
|
|
|
|
*y += MENU_FONT_HEIGHT;
|
|
glRasterPos2i(x, *y);
|
|
for(; *s; s++)
|
|
glutBitmapCharacter(MENU_FONT, *s);
|
|
|
|
if(Menus[menu].selected == i)
|
|
if(Menus[menu].Items[i].submenu)
|
|
if(DrawMenu(Menus[menu].Items[i].submenu, x
|
|
+ SUBMENU_OFFSET, y)) {
|
|
if(!a)
|
|
Menus[menu].selected = -1;
|
|
} else
|
|
ret = 0;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static void DrawMenus(void)
|
|
{
|
|
/* save old settings */
|
|
glPushAttrib(-1);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
glLoadMatrixd(MenuModelview);
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPushMatrix();
|
|
glLoadMatrixd(MenuProjection);
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_ALPHA_TEST);
|
|
glDisable(GL_LIGHTING);
|
|
glDisable(GL_FOG);
|
|
glDisable(GL_TEXTURE_2D);
|
|
// glEnable(GL_LOGIC_OP);
|
|
//glEnable(GL_COLOR_LOGIC_OP);
|
|
// glLogicOp(GL_XOR);
|
|
|
|
int x = Menus[ActiveMenu].x;
|
|
int y = Menus[ActiveMenu].y;
|
|
|
|
if(DrawMenu(ActiveMenu, x, &y))
|
|
Menus[ActiveMenu].selected = -1;
|
|
|
|
/* restore settings */
|
|
|
|
glPopMatrix();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPopMatrix();
|
|
|
|
glPopAttrib();
|
|
}
|
|
|
|
/* --------- Event Processing ------------*/
|
|
#define MODIFIER(mod) \
|
|
KeyboardModifiers = release ? KeyboardModifiers & ~mod \
|
|
: KeyboardModifiers | mod;
|
|
|
|
#define READKEY read(ConsoleFD, &code, 1)
|
|
|
|
static void LedModifier(int led, int release)
|
|
{
|
|
static int releaseflag = K_CAPS | K_NUM;
|
|
if(release)
|
|
releaseflag |= led;
|
|
else
|
|
if(releaseflag & led) {
|
|
KeyboardLedState ^= led;
|
|
releaseflag &= ~led;
|
|
}
|
|
ioctl(ConsoleFD, KDSKBLED, KeyboardLedState);
|
|
ioctl(ConsoleFD, KDSETLED, 0x80);
|
|
}
|
|
|
|
static int ReadKey(void)
|
|
{
|
|
int x;
|
|
unsigned char code;
|
|
int specialkey = 0;
|
|
if(READKEY == 0)
|
|
return 0;
|
|
|
|
if(code == 0)
|
|
return 0;
|
|
|
|
/* stdin input escape code based */
|
|
if(ConsoleFD == 0) {
|
|
KeyboardModifiers = 0;
|
|
altset:
|
|
if(code == 27 && READKEY == 1) {
|
|
switch(code) {
|
|
case 79: /* function key */
|
|
READKEY;
|
|
if(code == 50) {
|
|
READKEY;
|
|
shiftfunc:
|
|
KeyboardModifiers |= GLUT_ACTIVE_SHIFT;
|
|
specialkey = GLUT_KEY_F1 + code - 53;
|
|
READKEY;
|
|
} else {
|
|
READKEY;
|
|
specialkey = GLUT_KEY_F1 + code - 80;
|
|
}
|
|
break;
|
|
case 91:
|
|
READKEY;
|
|
switch(code) {
|
|
case 68:
|
|
specialkey = GLUT_KEY_LEFT; break;
|
|
case 65:
|
|
specialkey = GLUT_KEY_UP; break;
|
|
case 67:
|
|
specialkey = GLUT_KEY_RIGHT; break;
|
|
case 66:
|
|
specialkey = GLUT_KEY_DOWN; break;
|
|
case 53:
|
|
specialkey = GLUT_KEY_PAGE_UP; READKEY; break;
|
|
case 54:
|
|
specialkey = GLUT_KEY_PAGE_DOWN; READKEY; break;
|
|
case 49:
|
|
specialkey = GLUT_KEY_HOME; READKEY; break;
|
|
case 52:
|
|
specialkey = GLUT_KEY_END; READKEY; break;
|
|
case 50:
|
|
READKEY;
|
|
if(code != 126)
|
|
goto shiftfunc;
|
|
specialkey = GLUT_KEY_INSERT;
|
|
break;
|
|
case 51:
|
|
code = '\b'; goto stdkey;
|
|
case 91:
|
|
READKEY;
|
|
specialkey = GLUT_KEY_F1 + code - 65;
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
break;
|
|
default:
|
|
KeyboardModifiers |= GLUT_ACTIVE_ALT;
|
|
goto altset;
|
|
}
|
|
}
|
|
stdkey:
|
|
if(specialkey) {
|
|
if(SpecialFunc)
|
|
SpecialFunc(specialkey, MouseX, MouseY);
|
|
} else {
|
|
if(code >= 1 && code <= 26) {
|
|
KeyboardModifiers |= GLUT_ACTIVE_CTRL;
|
|
code += 'a' - 1;
|
|
}
|
|
if((code >= 43 && code <= 34) || (code == 60)
|
|
|| (code >= 62 && code <= 90) || (code == 94)
|
|
|| (code == 95) || (code >= 123 && code <= 126))
|
|
KeyboardModifiers |= GLUT_ACTIVE_SHIFT;
|
|
|
|
if(KeyboardFunc)
|
|
KeyboardFunc(code, MouseX, MouseY);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* linux kbd reading */
|
|
struct kbentry entry;
|
|
entry.kb_table = 0;
|
|
if(KeyboardModifiers & GLUT_ACTIVE_SHIFT)
|
|
entry.kb_table |= K_SHIFTTAB;
|
|
|
|
int release = code & 0x80;
|
|
code &= 0x7F;
|
|
|
|
entry.kb_index = code;
|
|
|
|
if (ioctl(ConsoleFD, KDGKBENT, &entry) < 0) {
|
|
sprintf(exiterror, "ioctl(KDGKBENT) failed.\n");
|
|
exit(0);
|
|
}
|
|
|
|
int labelval = entry.kb_value;
|
|
|
|
switch(labelval) {
|
|
case K_SHIFT:
|
|
case K_SHIFTL:
|
|
MODIFIER(GLUT_ACTIVE_SHIFT);
|
|
return 0;
|
|
case K_CTRL:
|
|
MODIFIER(GLUT_ACTIVE_CTRL);
|
|
return 0;
|
|
case K_ALT:
|
|
case K_ALTGR:
|
|
MODIFIER(GLUT_ACTIVE_ALT);
|
|
return 0;
|
|
}
|
|
|
|
if(!release && labelval >= K_F1 && labelval <= K_F12)
|
|
if(KeyboardModifiers & GLUT_ACTIVE_ALT) {
|
|
/* VT switch, we must do it */
|
|
if(ioctl(ConsoleFD, VT_ACTIVATE, labelval - K_F1 + 1) < 0)
|
|
sprintf(exiterror, "Error switching console\n");
|
|
return 0;
|
|
}
|
|
|
|
switch(labelval) {
|
|
case K_CAPS:
|
|
LedModifier(LED_CAP, release);
|
|
return 0;
|
|
case K_NUM:
|
|
LedModifier(LED_NUM, release);
|
|
return 0;
|
|
case K_HOLD: /* scroll lock suspends glut */
|
|
LedModifier(LED_SCR, release);
|
|
while(KeyboardLedState & LED_SCR) {
|
|
usleep(10000);
|
|
ReadKey();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* we could queue keypresses here */
|
|
if(KeyboardLedState & LED_SCR)
|
|
return 0;
|
|
|
|
if(release)
|
|
return 0;
|
|
|
|
if(labelval >= K_F1 && labelval <= K_F12)
|
|
specialkey = GLUT_KEY_F1 + labelval - K_F1;
|
|
else
|
|
switch(labelval) {
|
|
case K_LEFT:
|
|
specialkey = GLUT_KEY_LEFT; break;
|
|
case K_UP:
|
|
specialkey = GLUT_KEY_UP; break;
|
|
case K_RIGHT:
|
|
specialkey = GLUT_KEY_RIGHT; break;
|
|
case K_DOWN:
|
|
specialkey = GLUT_KEY_DOWN; break;
|
|
case K_PGUP:
|
|
specialkey = GLUT_KEY_PAGE_UP; break;
|
|
case K_PGDN:
|
|
specialkey = GLUT_KEY_PAGE_DOWN; break;
|
|
case K_FIND:
|
|
specialkey = GLUT_KEY_HOME; break;
|
|
case K_SELECT:
|
|
specialkey = GLUT_KEY_END; break;
|
|
case K_INSERT:
|
|
specialkey = GLUT_KEY_INSERT; break;
|
|
case K_REMOVE:
|
|
labelval = '\b'; break;
|
|
case K_ENTER:
|
|
labelval = '\n'; break;
|
|
}
|
|
|
|
if(specialkey) {
|
|
if(SpecialFunc)
|
|
SpecialFunc(specialkey, MouseX, MouseY);
|
|
} else
|
|
if(KeyboardFunc) {
|
|
char c = labelval;
|
|
if(KeyboardLedState & LED_CAP) {
|
|
if(c >= 'A' && c <= 'Z')
|
|
c += 'a' - 'A';
|
|
else
|
|
if(c >= 'a' && c <= 'z')
|
|
c += 'A' - 'a';
|
|
}
|
|
KeyboardFunc(c, MouseX, MouseY);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static void HandleMousePress(int button, int pressed)
|
|
{
|
|
if(ActiveMenu && !pressed) {
|
|
if(MenuStatusFunc)
|
|
MenuStatusFunc(GLUT_MENU_NOT_IN_USE, MouseX, MouseY);
|
|
if(MenuStateFunc)
|
|
MenuStateFunc(GLUT_MENU_NOT_IN_USE);
|
|
if(SelectedMenu > 0) {
|
|
int selected = Menus[SelectedMenu].selected;
|
|
if(selected >= 0)
|
|
if(Menus[SelectedMenu].Items[selected].submenu == 0)
|
|
Menus[SelectedMenu].func(Menus[SelectedMenu].Items
|
|
[selected].value);
|
|
}
|
|
ActiveMenu = 0;
|
|
Redisplay = 1;
|
|
return;
|
|
}
|
|
|
|
if(AttachedMenus[button] && pressed) {
|
|
ActiveMenu = AttachedMenus[button];
|
|
if(MenuStatusFunc)
|
|
MenuStatusFunc(GLUT_MENU_IN_USE, MouseX, MouseY);
|
|
if(MenuStateFunc)
|
|
MenuStateFunc(GLUT_MENU_IN_USE);
|
|
Menus[ActiveMenu].x = MouseX - Menus[ActiveMenu].width/2;
|
|
Menus[ActiveMenu].y = MouseY - Menus[ActiveMenu].NumItems*MENU_FONT_HEIGHT/2;
|
|
Menus[ActiveMenu].selected = -1;
|
|
Redisplay = 1;
|
|
return;
|
|
}
|
|
|
|
if(MouseFunc)
|
|
MouseFunc(button, pressed ? GLUT_DOWN : GLUT_UP, MouseX, MouseY);
|
|
}
|
|
|
|
static int ReadMouse(void)
|
|
{
|
|
int l, r, m;
|
|
static int ll, lm, lr;
|
|
signed char dx, dy;
|
|
|
|
#ifdef HAVE_GPM
|
|
if(GpmMouse) {
|
|
Gpm_Event event;
|
|
struct pollfd pfd;
|
|
pfd.fd = gpm_fd;
|
|
pfd.events = POLLIN;
|
|
if(poll(&pfd, 1, 1) != 1)
|
|
return 0;
|
|
|
|
if(Gpm_GetEvent(&event) != 1)
|
|
return 0;
|
|
|
|
l = event.buttons & GPM_B_LEFT;
|
|
m = event.buttons & GPM_B_MIDDLE;
|
|
r = event.buttons & GPM_B_RIGHT;
|
|
|
|
/* gpm is weird in that it gives a button number when the button
|
|
is released, with type set to GPM_UP, this is only a problem
|
|
if it is the last button released */
|
|
|
|
if(event.type & GPM_UP)
|
|
if(event.buttons == GPM_B_LEFT || event.buttons == GPM_B_MIDDLE ||
|
|
event.buttons == GPM_B_RIGHT || event.buttons == GPM_B_FOURTH)
|
|
l = m = r = 0;
|
|
|
|
dx = event.dx;
|
|
dy = event.dy;
|
|
} else
|
|
#endif
|
|
{
|
|
if(MouseFD == -1)
|
|
return 0;
|
|
|
|
if(fcntl(MouseFD, F_SETFL, O_NONBLOCK) == -1) {
|
|
close(MouseFD);
|
|
MouseFD = -1;
|
|
return 0;
|
|
}
|
|
|
|
char data[4];
|
|
if(read(MouseFD, data, 4) != 4)
|
|
return 0;
|
|
|
|
l = ((data[0] & 0x20) >> 3);
|
|
m = ((data[3] & 0x10) >> 3);
|
|
r = ((data[0] & 0x10) >> 4);
|
|
|
|
dx = (((data[0] & 0x03) << 6) | (data[1] & 0x3F));
|
|
dy = (((data[0] & 0x0C) << 4) | (data[2] & 0x3F));
|
|
}
|
|
|
|
MouseX += dx * MouseSpeed;
|
|
if(MouseX < 0)
|
|
MouseX = 0;
|
|
else
|
|
if(MouseX >= VarInfo.xres)
|
|
MouseX = VarInfo.xres - 1;
|
|
|
|
MouseY += dy * MouseSpeed;
|
|
if(MouseY < 0)
|
|
MouseY = 0;
|
|
else
|
|
if(MouseY >= VarInfo.yres)
|
|
MouseY = VarInfo.yres - 1;
|
|
|
|
if(l != ll)
|
|
HandleMousePress(GLUT_LEFT_BUTTON, l);
|
|
if(m != lm)
|
|
HandleMousePress(GLUT_MIDDLE_BUTTON, m);
|
|
if(r != lr)
|
|
HandleMousePress(GLUT_RIGHT_BUTTON, r);
|
|
|
|
ll = l, lm = m, lr = r;
|
|
|
|
if(dx || dy) {
|
|
if(l || m || r) {
|
|
if(MotionFunc)
|
|
MotionFunc(MouseX, MouseY);
|
|
} else
|
|
if(PassiveMotionFunc)
|
|
PassiveMotionFunc(MouseX, MouseY);
|
|
|
|
EraseCursor();
|
|
if(ActiveMenu)
|
|
Redisplay = 1;
|
|
else
|
|
SwapCursor();
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void RecieveEvents(void)
|
|
{
|
|
while(ReadKey());
|
|
|
|
if(MouseEnabled)
|
|
while(ReadMouse());
|
|
}
|
|
|
|
static void ProcessTimers(void)
|
|
{
|
|
if(GlutTimers && GlutTimers->time < glutGet(GLUT_ELAPSED_TIME)) {
|
|
struct GlutTimer *timer = GlutTimers;
|
|
timer->func(timer->value);
|
|
GlutTimers = timer->next;
|
|
free(timer);
|
|
}
|
|
}
|
|
|
|
void glutMainLoop(void)
|
|
{
|
|
if(ReshapeFunc)
|
|
ReshapeFunc(VarInfo.xres, VarInfo.yres);
|
|
|
|
if(!DisplayFunc) {
|
|
sprintf(exiterror, "Fatal Error: No Display Function registered\n");
|
|
exit(0);
|
|
}
|
|
|
|
for(;;) {
|
|
ProcessTimers();
|
|
|
|
if(Active)
|
|
RecieveEvents();
|
|
else
|
|
if(VisiblePoll)
|
|
TestVisible();
|
|
|
|
if(IdleFunc)
|
|
IdleFunc();
|
|
|
|
if(VisibleSwitch) {
|
|
VisibleSwitch = 0;
|
|
if(VisibilityFunc)
|
|
VisibilityFunc(Visible ? GLUT_VISIBLE : GLUT_NOT_VISIBLE);
|
|
}
|
|
|
|
if(Visible && Redisplay) {
|
|
Redisplay = 0;
|
|
if(MouseEnabled)
|
|
EraseCursor();
|
|
DisplayFunc();
|
|
if(!(DisplayMode & GLUT_DOUBLE)) {
|
|
if(ActiveMenu)
|
|
DrawMenus();
|
|
if(MouseEnabled)
|
|
DrawCursor();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ---------- Window Management ----------*/
|
|
static void ParseFBModes(void)
|
|
{
|
|
char buf[1024];
|
|
struct fb_var_screeninfo vi = VarInfo;
|
|
|
|
FILE *fbmodes = fopen(FBMODES, "r");
|
|
|
|
if(!fbmodes) {
|
|
sprintf(exiterror, "Warning: could not open "
|
|
FBMODES" using current mode\n");
|
|
return;
|
|
}
|
|
|
|
if(InitialWidthHint == 0 && InitialHeightHint == 0
|
|
&& RequiredWidth == 0)
|
|
return; /* use current mode */
|
|
|
|
while(fgets(buf, sizeof buf, fbmodes)) {
|
|
char *c;
|
|
int v;
|
|
|
|
if(!(c = strstr(buf, "geometry")))
|
|
continue;
|
|
v = sscanf(c, "geometry %d %d %d %d %d", &vi.xres, &vi.yres,
|
|
&vi.xres_virtual, &vi.yres_virtual, &vi.bits_per_pixel);
|
|
if(v != 5)
|
|
continue;
|
|
|
|
/* now we have to decide what is best */
|
|
if(RequiredWidth) {
|
|
if(RequiredWidth != vi.xres || RequiredHeight != vi.yres)
|
|
continue;
|
|
} else {
|
|
if(VarInfo.xres < vi.xres && VarInfo.xres < InitialWidthHint)
|
|
v++;
|
|
if(VarInfo.xres > vi.xres && vi.xres > InitialWidthHint)
|
|
v++;
|
|
|
|
if(VarInfo.yres < vi.yres && VarInfo.yres < InitialHeightHint)
|
|
v++;
|
|
if(VarInfo.yres > vi.yres && vi.yres > InitialHeightHint)
|
|
v++;
|
|
|
|
if(v < 7)
|
|
continue;
|
|
}
|
|
|
|
fgets(buf, sizeof buf, fbmodes);
|
|
if(!(c = strstr(buf, "timings")))
|
|
continue;
|
|
|
|
v = sscanf(c, "timings %d %d %d %d %d %d %d", &vi.pixclock,
|
|
&vi.left_margin, &vi.right_margin, &vi.upper_margin,
|
|
&vi.lower_margin, &vi.hsync_len, &vi.vsync_len);
|
|
if(v != 7)
|
|
continue;
|
|
|
|
VarInfo = vi; /* finally found a better mode */
|
|
if(RequiredWidth) {
|
|
fclose(fbmodes);
|
|
return;
|
|
}
|
|
}
|
|
|
|
fclose(fbmodes);
|
|
|
|
if(RequiredWidth) {
|
|
sprintf(exiterror, "No mode (%dx%d) found in "FBMODES"\n",
|
|
RequiredWidth, RequiredHeight);
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
int glutCreateWindow (const char *title)
|
|
{
|
|
if(ConsoleFD == -1) {
|
|
int argc = 0;
|
|
char *argv[] = {NULL};
|
|
glutInit(&argc, argv);
|
|
}
|
|
|
|
if(Context)
|
|
return 0;
|
|
|
|
char *fbdev = getenv("FRAMEBUFFER");
|
|
if(fbdev) {
|
|
#ifdef MULTIHEAD
|
|
if(!sscanf(fbdev, "/dev/fb%d", &FramebufferIndex))
|
|
if(!sscanf(fbdev, "/dev/fb/%d", &FramebufferIndex))
|
|
sprintf(exiterror, "Could not determine Framebuffer index!\n");
|
|
#endif
|
|
} else {
|
|
static char fb[128];
|
|
FramebufferIndex = 0;
|
|
struct fb_con2fbmap confb;
|
|
int fd = open("/dev/fb0", O_RDWR);
|
|
confb.console = CurrentVT;
|
|
if(ioctl(fd, FBIOGET_CON2FBMAP, &confb) != -1)
|
|
FramebufferIndex = confb.framebuffer;
|
|
sprintf(fb, "/dev/fb%d", FramebufferIndex);
|
|
fbdev = fb;
|
|
close(fd);
|
|
}
|
|
|
|
/* open the framebuffer device */
|
|
FrameBufferFD = open(fbdev, O_RDWR);
|
|
if (FrameBufferFD < 0) {
|
|
sprintf(exiterror, "Error opening %s: %s\n", fbdev, strerror(errno));
|
|
exit(0);
|
|
}
|
|
|
|
/* Get the fixed screen info */
|
|
if (ioctl(FrameBufferFD, FBIOGET_FSCREENINFO, &FixedInfo)) {
|
|
sprintf(exiterror, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
|
|
strerror(errno));
|
|
exit(0);
|
|
}
|
|
|
|
/* get the variable screen info */
|
|
if (ioctl(FrameBufferFD, FBIOGET_VSCREENINFO, &OrigVarInfo)) {
|
|
sprintf(exiterror, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
|
|
strerror(errno));
|
|
exit(0);
|
|
}
|
|
|
|
/* operate on a copy */
|
|
VarInfo = OrigVarInfo;
|
|
|
|
/* set the depth, resolution, etc */
|
|
ParseFBModes();
|
|
|
|
if(DisplayMode & GLUT_INDEX)
|
|
VarInfo.bits_per_pixel = 8;
|
|
else
|
|
if(VarInfo.bits_per_pixel == 8)
|
|
VarInfo.bits_per_pixel = 32;
|
|
|
|
if (DesiredDepth)
|
|
VarInfo.bits_per_pixel = DesiredDepth;
|
|
|
|
VarInfo.xoffset = 0;
|
|
VarInfo.yoffset = 0;
|
|
VarInfo.nonstd = 0;
|
|
VarInfo.vmode &= ~FB_VMODE_YWRAP; /* turn off scrolling */
|
|
|
|
/* set new variable screen info */
|
|
if (ioctl(FrameBufferFD, FBIOPUT_VSCREENINFO, &VarInfo)) {
|
|
sprintf(exiterror, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
|
|
strerror(errno));
|
|
exit(0);
|
|
}
|
|
|
|
/* reload the screen info to update offsets */
|
|
if (ioctl(FrameBufferFD, FBIOGET_VSCREENINFO, &VarInfo)) {
|
|
sprintf(exiterror, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
|
|
strerror(errno));
|
|
exit(0);
|
|
}
|
|
|
|
/* reload the fixed info to update color mode */
|
|
if (ioctl(FrameBufferFD, FBIOGET_FSCREENINFO, &FixedInfo)) {
|
|
sprintf(exiterror, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
|
|
strerror(errno));
|
|
exit(0);
|
|
}
|
|
|
|
if(DisplayMode & GLUT_INDEX) {
|
|
/* initialize colormap */
|
|
if (FixedInfo.visual != FB_VISUAL_DIRECTCOLOR) {
|
|
static unsigned short red[256], green[256], blue[256];
|
|
/* we're assuming 256 entries here */
|
|
|
|
ColorMap.start = 0;
|
|
ColorMap.len = 256;
|
|
ColorMap.red = red;
|
|
ColorMap.green = green;
|
|
ColorMap.blue = blue;
|
|
ColorMap.transp = NULL;
|
|
|
|
if (ioctl(FrameBufferFD, FBIOGETCMAP, (void *) &ColorMap) < 0)
|
|
sprintf(exiterror, "ioctl(FBIOGETCMAP) failed!\n");
|
|
|
|
} else {
|
|
sprintf(exiterror, "error: Could not set 8 bit color mode\n");
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
/* mmap the framebuffer into our address space */
|
|
FrameBuffer = mmap(0, FixedInfo.smem_len, PROT_READ | PROT_WRITE,
|
|
MAP_SHARED, FrameBufferFD, 0);
|
|
if (FrameBuffer == MAP_FAILED) {
|
|
sprintf(exiterror, "error: unable to mmap framebuffer: %s\n",
|
|
strerror(errno));
|
|
exit(0);
|
|
}
|
|
|
|
int attribs[9];
|
|
int i;
|
|
|
|
int mask = DisplayMode;
|
|
for(i=0; i<8 && mask; i++) {
|
|
if(mask & GLUT_DOUBLE) {
|
|
attribs[i] = GLFBDEV_DOUBLE_BUFFER;
|
|
mask &= ~GLUT_DOUBLE;
|
|
continue;
|
|
}
|
|
|
|
if(mask & GLUT_INDEX) {
|
|
attribs[i] = GLFBDEV_COLOR_INDEX;
|
|
mask &= ~GLUT_INDEX;
|
|
continue;
|
|
}
|
|
|
|
if(mask & GLUT_DEPTH) {
|
|
attribs[i] = GLFBDEV_DEPTH_SIZE;
|
|
attribs[++i] = DepthSize;
|
|
mask &= ~GLUT_DEPTH;
|
|
continue;
|
|
}
|
|
|
|
if(mask & GLUT_STENCIL) {
|
|
attribs[i] = GLFBDEV_STENCIL_SIZE;
|
|
attribs[++i] = StencilSize;
|
|
mask &= ~GLUT_STENCIL;
|
|
continue;
|
|
}
|
|
|
|
if(mask & GLUT_ACCUM) {
|
|
attribs[i] = GLFBDEV_ACCUM_SIZE;
|
|
attribs[++i] = AccumSize;
|
|
mask &= ~GLUT_ACCUM;
|
|
continue;
|
|
}
|
|
|
|
if(mask & GLUT_ALPHA)
|
|
if(!(DisplayMode & GLUT_INDEX)) {
|
|
mask &= ~GLUT_ALPHA;
|
|
i--;
|
|
continue;
|
|
}
|
|
|
|
sprintf(exiterror, "Invalid mode from glutInitDisplayMode\n");
|
|
exit(0);
|
|
}
|
|
|
|
attribs[i] = GLFBDEV_NONE;
|
|
|
|
if(!(Visual = glFBDevCreateVisual( &FixedInfo, &VarInfo, attribs ))) {
|
|
sprintf(exiterror, "Failure to create Visual\n");
|
|
exit(0);
|
|
}
|
|
|
|
int size = VarInfo.xres_virtual * VarInfo.yres_virtual
|
|
* VarInfo.bits_per_pixel / 8;
|
|
if(DisplayMode & GLUT_DOUBLE) {
|
|
if(!(BackBuffer = malloc(size))) {
|
|
sprintf(exiterror, "Failed to allocate double buffer\n");
|
|
exit(0);
|
|
}
|
|
} else
|
|
BackBuffer = FrameBuffer;
|
|
|
|
if(!(Buffer = glFBDevCreateBuffer( &FixedInfo, &VarInfo, Visual,
|
|
FrameBuffer, BackBuffer, size))) {
|
|
sprintf(exiterror, "Failure to create Buffer\n");
|
|
exit(0);
|
|
}
|
|
|
|
if(!(Context = glFBDevCreateContext(Visual, NULL))) {
|
|
sprintf(exiterror, "Failure to create Context\n");
|
|
exit(0);
|
|
}
|
|
|
|
if(!glFBDevMakeCurrent( Context, Buffer, Buffer )) {
|
|
sprintf(exiterror, "Failure to Make Current\n");
|
|
exit(0);
|
|
}
|
|
|
|
Visible = 1;
|
|
VisibleSwitch = 1;
|
|
Redisplay = 1;
|
|
|
|
/* set up mouse */
|
|
if((MouseBuffer = malloc(CURSOR_WIDTH * CURSOR_HEIGHT
|
|
* VarInfo.bits_per_pixel / 8)) == NULL) {
|
|
sprintf(exiterror, "malloc failure\n");
|
|
exit(0);
|
|
}
|
|
|
|
MouseX = VarInfo.xres / 2;
|
|
MouseY = VarInfo.yres / 2;
|
|
|
|
/* set up menus */
|
|
InitMenuMatrices();
|
|
return 1;
|
|
}
|
|
|
|
int glutCreateSubWindow(int win, int x, int y, int width, int height)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void glutSetWindow(int win)
|
|
{
|
|
}
|
|
|
|
int glutGetWindow(void)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
void glutDestroyWindow(int win)
|
|
{
|
|
}
|
|
|
|
void glutPostRedisplay(void)
|
|
{
|
|
Redisplay = 1;
|
|
}
|
|
|
|
void glutSwapBuffers(void)
|
|
{
|
|
glFlush();
|
|
|
|
if(DisplayMode & GLUT_DOUBLE) {
|
|
if(ActiveMenu)
|
|
DrawMenus();
|
|
if(MouseEnabled)
|
|
DrawCursor();
|
|
glFBDevSwapBuffers(Buffer);
|
|
}
|
|
}
|
|
|
|
void glutPositionWindow(int x, int y)
|
|
{
|
|
}
|
|
|
|
void glutReshapeWindow(int width, int height)
|
|
{
|
|
}
|
|
|
|
void glutFullScreen(void)
|
|
{
|
|
}
|
|
|
|
void glutPopWindow(void)
|
|
{
|
|
}
|
|
|
|
void glutPushWindow(void)
|
|
{
|
|
}
|
|
|
|
void glutShowWindow(void)
|
|
{
|
|
}
|
|
|
|
void glutHideWindow(void)
|
|
{
|
|
}
|
|
|
|
void glutIconifyWindow(void)
|
|
{
|
|
}
|
|
|
|
void glutSetWindowTitle(const char *name)
|
|
{
|
|
}
|
|
|
|
void glutSetIconTitle(const char *name)
|
|
{
|
|
}
|
|
|
|
void glutSetCursor(int cursor)
|
|
{
|
|
if(cursor == GLUT_CURSOR_FULL_CROSSHAIR)
|
|
cursor = GLUT_CURSOR_CROSSHAIR;
|
|
CurrentCursor = cursor;
|
|
MouseEnabled = 1;
|
|
EraseCursor();
|
|
SwapCursor();
|
|
}
|
|
|
|
/* --------- Overlays ------------*/
|
|
void glutEstablishOverlay(void)
|
|
{
|
|
exit(0);
|
|
}
|
|
|
|
void glutUseLayer(GLenum layer)
|
|
{
|
|
}
|
|
|
|
void glutRemoveOverlay(void)
|
|
{
|
|
}
|
|
|
|
void glutPostOverlayRedisplay(void)
|
|
{
|
|
}
|
|
|
|
void glutShowOverlay(void)
|
|
{
|
|
}
|
|
|
|
void glutHideOverlay(void)
|
|
{
|
|
}
|
|
|
|
/* --------- Menus ------------*/
|
|
int glutCreateMenu(void (*func)(int value))
|
|
{
|
|
MouseEnabled = 1;
|
|
CurrentMenu = NumMenus;
|
|
NumMenus++;
|
|
Menus = realloc(Menus, sizeof(*Menus) * NumMenus);
|
|
Menus[CurrentMenu].NumItems = 0;
|
|
Menus[CurrentMenu].Items = NULL;
|
|
Menus[CurrentMenu].func = func;
|
|
Menus[CurrentMenu].width = 0;
|
|
return CurrentMenu;
|
|
}
|
|
|
|
void glutSetMenu(int menu)
|
|
{
|
|
CurrentMenu = menu;
|
|
}
|
|
|
|
int glutGetMenu(void)
|
|
{
|
|
return CurrentMenu;
|
|
}
|
|
|
|
void glutDestroyMenu(int menu)
|
|
{
|
|
if(menu == CurrentMenu)
|
|
CurrentMenu = 0;
|
|
}
|
|
|
|
static void NameMenuEntry(int entry, const char *name)
|
|
{
|
|
int cm = CurrentMenu;
|
|
if(!(Menus[cm].Items[entry-1].name = realloc(Menus[cm].Items[entry-1].name,
|
|
strlen(name) + 1))) {
|
|
sprintf(exiterror, "realloc failed in NameMenuEntry\n");
|
|
exit(0);
|
|
}
|
|
strcpy(Menus[cm].Items[entry-1].name, name);
|
|
if(strlen(name) * MENU_FONT_WIDTH > Menus[cm].width)
|
|
Menus[cm].width = strlen(name) * MENU_FONT_WIDTH;
|
|
}
|
|
|
|
static int AddMenuItem(const char *name)
|
|
{
|
|
int cm = CurrentMenu;
|
|
int item = Menus[cm].NumItems++;
|
|
if(!(Menus[cm].Items = realloc(Menus[cm].Items,
|
|
Menus[cm].NumItems * sizeof(*Menus[0].Items)))) {
|
|
sprintf(exiterror, "realloc failed in AddMenuItem\n");
|
|
exit(0);
|
|
}
|
|
Menus[cm].Items[item].name = NULL;
|
|
NameMenuEntry(item+1, name);
|
|
return item;
|
|
}
|
|
|
|
void glutAddMenuEntry(const char *name, int value)
|
|
{
|
|
int item = AddMenuItem(name);
|
|
Menus[CurrentMenu].Items[item].value = value;
|
|
Menus[CurrentMenu].Items[item].submenu = 0;
|
|
}
|
|
|
|
void glutAddSubMenu(const char *name, int menu)
|
|
{
|
|
int item = AddMenuItem(name);
|
|
if(menu == CurrentMenu) {
|
|
sprintf(exiterror, "Recursive menus not supported\n");
|
|
exit(0);
|
|
}
|
|
Menus[CurrentMenu].Items[item].submenu = menu;
|
|
}
|
|
|
|
void glutChangeToMenuEntry(int entry, const char *name, int value)
|
|
{
|
|
NameMenuEntry(entry, name);
|
|
Menus[CurrentMenu].Items[entry-1].value = value;
|
|
Menus[CurrentMenu].Items[entry-1].submenu = 0;
|
|
}
|
|
|
|
void glutChangeToSubMenu(int entry, const char *name, int menu)
|
|
{
|
|
NameMenuEntry(entry, name);
|
|
Menus[CurrentMenu].Items[entry-1].submenu = menu;
|
|
}
|
|
|
|
void glutRemoveMenuItem(int entry)
|
|
{
|
|
memmove(Menus[CurrentMenu].Items + entry - 1,
|
|
Menus[CurrentMenu].Items + entry,
|
|
sizeof(*Menus[0].Items) * (Menus[CurrentMenu].NumItems - entry));
|
|
Menus[CurrentMenu].NumItems--;
|
|
}
|
|
|
|
void glutAttachMenu(int button)
|
|
{
|
|
AttachedMenus[button] = CurrentMenu;
|
|
}
|
|
|
|
void glutDetachMenu(int button)
|
|
{
|
|
AttachedMenus[button] = 0;
|
|
}
|
|
|
|
/* --------- Callbacks ------------ */
|
|
void glutDisplayFunc(void (*func)(void))
|
|
{
|
|
DisplayFunc = func;
|
|
}
|
|
|
|
void glutOverlayDisplayFunc(void (*func)(void))
|
|
{
|
|
}
|
|
|
|
void glutReshapeFunc(void (*func)(int width, int height))
|
|
{
|
|
ReshapeFunc = func;
|
|
}
|
|
|
|
void glutKeyboardFunc(void (*func)(unsigned char key, int x, int y))
|
|
{
|
|
KeyboardFunc = func;
|
|
}
|
|
|
|
void glutMouseFunc(void (*func)(int button, int state, int x, int y))
|
|
{
|
|
MouseEnabled = 1;
|
|
MouseFunc = func;
|
|
}
|
|
|
|
void glutMotionFunc(void (*func)(int x, int y))
|
|
{
|
|
MouseEnabled = 1;
|
|
MotionFunc = func;
|
|
}
|
|
|
|
void glutPassiveMotionFunc(void (*func)(int x, int y))
|
|
{
|
|
MouseEnabled = 1;
|
|
PassiveMotionFunc = func;
|
|
}
|
|
|
|
void glutVisibilityFunc(void (*func)(int state))
|
|
{
|
|
VisibilityFunc = func;
|
|
}
|
|
|
|
void glutEntryFunc(void (*func)(int state))
|
|
{
|
|
}
|
|
|
|
void glutSpecialFunc(void (*func)(int key, int x, int y))
|
|
{
|
|
SpecialFunc = func;
|
|
}
|
|
|
|
void glutSpaceballMotionFunc(void (*func)(int x, int y, int z))
|
|
{
|
|
}
|
|
|
|
void glutSpaceballRotateFunc(void (*func)(int x, int y, int z))
|
|
{
|
|
}
|
|
|
|
void glutButtonBoxFunc(void (*func)(int button, int state))
|
|
{
|
|
}
|
|
|
|
void glutDialsFunc(void (*func)(int dial, int value))
|
|
{
|
|
}
|
|
|
|
void glutTabletMotionFunc(void (*func)(int x, int y))
|
|
{
|
|
}
|
|
|
|
void glutTabletButtonFunc(void (*func)(int button, int state,
|
|
int x, int y))
|
|
{
|
|
}
|
|
|
|
void glutMenuStatusFunc(void (*func)(int status, int x, int y))
|
|
{
|
|
MenuStatusFunc = func;
|
|
}
|
|
|
|
void glutMenuStateFunc(void (*func)(int status))
|
|
{
|
|
MenuStateFunc = func;
|
|
}
|
|
|
|
void glutIdleFunc(void (*func)(void))
|
|
{
|
|
IdleFunc = func;
|
|
}
|
|
|
|
void glutTimerFunc(unsigned int msecs,
|
|
void (*func)(int value), int value)
|
|
{
|
|
struct GlutTimer *timer = malloc(sizeof *timer);
|
|
timer->time = glutGet(GLUT_ELAPSED_TIME) + msecs;
|
|
timer->func = func;
|
|
timer->value = value;
|
|
|
|
struct GlutTimer **head = &GlutTimers;
|
|
while(*head && (*head)->time < timer->time)
|
|
head = &(*head)->next;
|
|
|
|
timer->next = *head;
|
|
*head = timer;
|
|
}
|
|
|
|
/* --------- Color Map ------------*/
|
|
#define TOCMAP(x) (unsigned short)((x<0?0:x>1?1:x) * (GLfloat) (2<<16))
|
|
#define FROMCMAP(x) (GLfloat)x / (GLfloat)(2<<16)
|
|
|
|
void glutSetColor(int cell, GLfloat red, GLfloat green, GLfloat blue)
|
|
{
|
|
if(cell >=0 && cell < 256) {
|
|
|
|
ColorMap.red[cell] = TOCMAP(red);
|
|
ColorMap.green[cell] = TOCMAP(green);
|
|
ColorMap.blue[cell] = TOCMAP(blue);
|
|
|
|
ColorMap.start = cell;
|
|
ColorMap.len = 1;
|
|
|
|
if (ioctl(FrameBufferFD, FBIOPUTCMAP, (void *) &ColorMap) < 0)
|
|
fprintf(stderr, "ioctl(FBIOPUTCMAP) failed [%d]\n", cell);
|
|
}
|
|
}
|
|
|
|
GLfloat glutGetColor(int cell, int component)
|
|
{
|
|
if(!(DisplayMode & GLUT_INDEX))
|
|
return -1.0;
|
|
|
|
if(cell < 0 || cell > 256)
|
|
return -1.0;
|
|
|
|
switch(component) {
|
|
case GLUT_RED:
|
|
return FROMCMAP(ColorMap.red[cell]);
|
|
case GLUT_GREEN:
|
|
return FROMCMAP(ColorMap.green[cell]);
|
|
case GLUT_BLUE:
|
|
return FROMCMAP(ColorMap.blue[cell]);
|
|
}
|
|
return -1.0;
|
|
}
|
|
|
|
void glutCopyColormap(int win)
|
|
{
|
|
}
|
|
|
|
/* --------- State ------------*/
|
|
void glutWarpPointer(int x, int y)
|
|
{
|
|
if(x < 0)
|
|
x = 0;
|
|
if(x >= VarInfo.xres)
|
|
x = VarInfo.xres - 1;
|
|
MouseX = x;
|
|
|
|
if(y < 0)
|
|
y = 0;
|
|
if(y >= VarInfo.yres)
|
|
y = VarInfo.yres - 1;
|
|
MouseY = y;
|
|
|
|
EraseCursor();
|
|
SwapCursor();
|
|
}
|
|
|
|
int glutGet(GLenum state)
|
|
{
|
|
switch(state) {
|
|
case GLUT_WINDOW_X:
|
|
return 0;
|
|
case GLUT_WINDOW_Y:
|
|
return 0;
|
|
case GLUT_INIT_WINDOW_WIDTH:
|
|
case GLUT_WINDOW_WIDTH:
|
|
case GLUT_SCREEN_WIDTH:
|
|
return VarInfo.xres;
|
|
case GLUT_INIT_WINDOW_HEIGHT:
|
|
case GLUT_WINDOW_HEIGHT:
|
|
case GLUT_SCREEN_HEIGHT:
|
|
return VarInfo.yres;
|
|
case GLUT_WINDOW_BUFFER_SIZE:
|
|
return VarInfo.bits_per_pixel;
|
|
case GLUT_WINDOW_STENCIL_SIZE:
|
|
return StencilSize;
|
|
case GLUT_WINDOW_DEPTH_SIZE:
|
|
return DepthSize;
|
|
case GLUT_WINDOW_RED_SIZE:
|
|
return VarInfo.red.length;
|
|
case GLUT_WINDOW_GREEN_SIZE:
|
|
return VarInfo.green.length;
|
|
case GLUT_WINDOW_BLUE_SIZE:
|
|
return VarInfo.green.length;
|
|
case GLUT_WINDOW_ALPHA_SIZE:
|
|
return VarInfo.transp.length;
|
|
case GLUT_WINDOW_ACCUM_RED_SIZE:
|
|
case GLUT_WINDOW_ACCUM_GREEN_SIZE:
|
|
case GLUT_WINDOW_ACCUM_BLUE_SIZE:
|
|
case GLUT_WINDOW_ACCUM_ALPHA_SIZE:
|
|
return AccumSize;
|
|
case GLUT_WINDOW_DOUBLEBUFFER:
|
|
if(DisplayMode & GLUT_DOUBLE)
|
|
return 1;
|
|
return 0;
|
|
case GLUT_WINDOW_RGBA:
|
|
if(DisplayMode & GLUT_INDEX)
|
|
return 0;
|
|
return 1;
|
|
case GLUT_WINDOW_PARENT:
|
|
return 0;
|
|
case GLUT_WINDOW_NUM_CHILDREN:
|
|
return 0;
|
|
case GLUT_WINDOW_COLORMAP_SIZE:
|
|
if(DisplayMode & GLUT_INDEX)
|
|
return 256;
|
|
return 0;
|
|
case GLUT_WINDOW_NUM_SAMPLES:
|
|
return 0;
|
|
case GLUT_WINDOW_STEREO:
|
|
return 0;
|
|
case GLUT_WINDOW_CURSOR:
|
|
return CurrentCursor;
|
|
case GLUT_SCREEN_WIDTH_MM:
|
|
return VarInfo.width;
|
|
case GLUT_SCREEN_HEIGHT_MM:
|
|
return VarInfo.height;
|
|
case GLUT_MENU_NUM_ITEMS:
|
|
if(CurrentMenu)
|
|
return Menus[CurrentMenu].NumItems;
|
|
return 0;
|
|
case GLUT_DISPLAY_MODE_POSSIBLE:
|
|
if((DisplayMode & GLUT_MULTISAMPLE)
|
|
|| (DisplayMode & GLUT_STEREO)
|
|
|| (DisplayMode & GLUT_LUMINANCE)
|
|
|| (DisplayMode & GLUT_ALPHA) && (DisplayMode & GLUT_INDEX))
|
|
return 0;
|
|
return 1;
|
|
case GLUT_INIT_DISPLAY_MODE:
|
|
return DisplayMode;
|
|
case GLUT_INIT_WINDOW_X:
|
|
case GLUT_INIT_WINDOW_Y:
|
|
return 0;
|
|
case GLUT_ELAPSED_TIME:
|
|
{
|
|
static struct timeval tv;
|
|
gettimeofday(&tv, 0);
|
|
return 1000 * (tv.tv_sec - StartTime.tv_sec)
|
|
+ (tv.tv_usec - StartTime.tv_usec) / 1000;
|
|
}
|
|
}
|
|
}
|
|
|
|
int glutLayerGet(GLenum info)
|
|
{
|
|
switch(info) {
|
|
case GLUT_OVERLAY_POSSIBLE:
|
|
return 0;
|
|
case GLUT_LAYER_IN_USE:
|
|
return GLUT_NORMAL;
|
|
case GLUT_HAS_OVERLAY:
|
|
return 0;
|
|
case GLUT_TRANSPARENT_INDEX:
|
|
return -1;
|
|
case GLUT_NORMAL_DAMAGED:
|
|
return Redisplay;
|
|
case GLUT_OVERLAY_DAMAGED:
|
|
return -1;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int glutDeviceGet(GLenum info)
|
|
{
|
|
switch(info) {
|
|
case GLUT_HAS_KEYBOARD:
|
|
return 1;
|
|
case GLUT_HAS_MOUSE:
|
|
case GLUT_NUM_MOUSE_BUTTONS:
|
|
return NumMouseButtons;
|
|
case GLUT_HAS_SPACEBALL:
|
|
case GLUT_HAS_DIAL_AND_BUTTON_BOX:
|
|
case GLUT_HAS_TABLET:
|
|
return 0;
|
|
case GLUT_NUM_SPACEBALL_BUTTONS:
|
|
case GLUT_NUM_BUTTON_BOX_BUTTONS:
|
|
case GLUT_NUM_DIALS:
|
|
case GLUT_NUM_TABLET_BUTTONS:
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int glutGetModifiers(void){
|
|
return KeyboardModifiers;
|
|
}
|
|
|
|
/* ------------- extensions ------------ */
|
|
int glutExtensionSupported(const char *extension)
|
|
{
|
|
const char *exts = (const char *) glGetString(GL_EXTENSIONS);
|
|
const char *start = exts;
|
|
int len = strlen(extension);
|
|
|
|
for(;;) {
|
|
const char *p = strstr(exts, extension);
|
|
if(!p)
|
|
break;
|
|
if((p == start || p[-1] == ' ') && (p[len] == ' ' || p[len] == 0))
|
|
return 1;
|
|
exts = p + len;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void glutReportErrors(void)
|
|
{
|
|
GLenum error;
|
|
|
|
while ((error = glGetError()) != GL_NO_ERROR)
|
|
fprintf(stderr, "GL error: %s", gluErrorString(error));
|
|
}
|
|
|
|
static struct {
|
|
const char *name;
|
|
const GLUTproc address;
|
|
} glut_functions[] = {
|
|
{ "glutInit", (const GLUTproc) glutInit },
|
|
{ "glutInitDisplayMode", (const GLUTproc) glutInitDisplayMode },
|
|
{ "glutInitWindowPosition", (const GLUTproc) glutInitWindowPosition },
|
|
{ "glutInitWindowSize", (const GLUTproc) glutInitWindowSize },
|
|
{ "glutMainLoop", (const GLUTproc) glutMainLoop },
|
|
{ "glutCreateWindow", (const GLUTproc) glutCreateWindow },
|
|
{ "glutCreateSubWindow", (const GLUTproc) glutCreateSubWindow },
|
|
{ "glutDestroyWindow", (const GLUTproc) glutDestroyWindow },
|
|
{ "glutPostRedisplay", (const GLUTproc) glutPostRedisplay },
|
|
{ "glutSwapBuffers", (const GLUTproc) glutSwapBuffers },
|
|
{ "glutGetWindow", (const GLUTproc) glutGetWindow },
|
|
{ "glutSetWindow", (const GLUTproc) glutSetWindow },
|
|
{ "glutSetWindowTitle", (const GLUTproc) glutSetWindowTitle },
|
|
{ "glutSetIconTitle", (const GLUTproc) glutSetIconTitle },
|
|
{ "glutPositionWindow", (const GLUTproc) glutPositionWindow },
|
|
{ "glutReshapeWindow", (const GLUTproc) glutReshapeWindow },
|
|
{ "glutPopWindow", (const GLUTproc) glutPopWindow },
|
|
{ "glutPushWindow", (const GLUTproc) glutPushWindow },
|
|
{ "glutIconifyWindow", (const GLUTproc) glutIconifyWindow },
|
|
{ "glutShowWindow", (const GLUTproc) glutShowWindow },
|
|
{ "glutHideWindow", (const GLUTproc) glutHideWindow },
|
|
{ "glutFullScreen", (const GLUTproc) glutFullScreen },
|
|
{ "glutSetCursor", (const GLUTproc) glutSetCursor },
|
|
{ "glutWarpPointer", (const GLUTproc) glutWarpPointer },
|
|
{ "glutEstablishOverlay", (const GLUTproc) glutEstablishOverlay },
|
|
{ "glutRemoveOverlay", (const GLUTproc) glutRemoveOverlay },
|
|
{ "glutUseLayer", (const GLUTproc) glutUseLayer },
|
|
{ "glutPostOverlayRedisplay", (const GLUTproc) glutPostOverlayRedisplay },
|
|
{ "glutShowOverlay", (const GLUTproc) glutShowOverlay },
|
|
{ "glutHideOverlay", (const GLUTproc) glutHideOverlay },
|
|
{ "glutCreateMenu", (const GLUTproc) glutCreateMenu },
|
|
{ "glutDestroyMenu", (const GLUTproc) glutDestroyMenu },
|
|
{ "glutGetMenu", (const GLUTproc) glutGetMenu },
|
|
{ "glutSetMenu", (const GLUTproc) glutSetMenu },
|
|
{ "glutAddMenuEntry", (const GLUTproc) glutAddMenuEntry },
|
|
{ "glutAddSubMenu", (const GLUTproc) glutAddSubMenu },
|
|
{ "glutChangeToMenuEntry", (const GLUTproc) glutChangeToMenuEntry },
|
|
{ "glutChangeToSubMenu", (const GLUTproc) glutChangeToSubMenu },
|
|
{ "glutRemoveMenuItem", (const GLUTproc) glutRemoveMenuItem },
|
|
{ "glutAttachMenu", (const GLUTproc) glutAttachMenu },
|
|
{ "glutDetachMenu", (const GLUTproc) glutDetachMenu },
|
|
{ "glutDisplayFunc", (const GLUTproc) glutDisplayFunc },
|
|
{ "glutReshapeFunc", (const GLUTproc) glutReshapeFunc },
|
|
{ "glutKeyboardFunc", (const GLUTproc) glutKeyboardFunc },
|
|
{ "glutMouseFunc", (const GLUTproc) glutMouseFunc },
|
|
{ "glutMotionFunc", (const GLUTproc) glutMotionFunc },
|
|
{ "glutPassiveMotionFunc", (const GLUTproc) glutPassiveMotionFunc },
|
|
{ "glutEntryFunc", (const GLUTproc) glutEntryFunc },
|
|
{ "glutVisibilityFunc", (const GLUTproc) glutVisibilityFunc },
|
|
{ "glutIdleFunc", (const GLUTproc) glutIdleFunc },
|
|
{ "glutTimerFunc", (const GLUTproc) glutTimerFunc },
|
|
{ "glutMenuStateFunc", (const GLUTproc) glutMenuStateFunc },
|
|
{ "glutSpecialFunc", (const GLUTproc) glutSpecialFunc },
|
|
{ "glutSpaceballRotateFunc", (const GLUTproc) glutSpaceballRotateFunc },
|
|
{ "glutButtonBoxFunc", (const GLUTproc) glutButtonBoxFunc },
|
|
{ "glutDialsFunc", (const GLUTproc) glutDialsFunc },
|
|
{ "glutTabletMotionFunc", (const GLUTproc) glutTabletMotionFunc },
|
|
{ "glutTabletButtonFunc", (const GLUTproc) glutTabletButtonFunc },
|
|
{ "glutMenuStatusFunc", (const GLUTproc) glutMenuStatusFunc },
|
|
{ "glutOverlayDisplayFunc", (const GLUTproc) glutOverlayDisplayFunc },
|
|
{ "glutSetColor", (const GLUTproc) glutSetColor },
|
|
{ "glutGetColor", (const GLUTproc) glutGetColor },
|
|
{ "glutCopyColormap", (const GLUTproc) glutCopyColormap },
|
|
{ "glutGet", (const GLUTproc) glutGet },
|
|
{ "glutDeviceGet", (const GLUTproc) glutDeviceGet },
|
|
{ "glutExtensionSupported", (const GLUTproc) glutExtensionSupported },
|
|
{ "glutGetModifiers", (const GLUTproc) glutGetModifiers },
|
|
{ "glutLayerGet", (const GLUTproc) glutLayerGet },
|
|
{ "glutGetProcAddress", (const GLUTproc) glutGetProcAddress },
|
|
{ "glutBitmapCharacter", (const GLUTproc) glutBitmapCharacter },
|
|
{ "glutBitmapWidth", (const GLUTproc) glutBitmapWidth },
|
|
{ "glutStrokeCharacter", (const GLUTproc) glutStrokeCharacter },
|
|
{ "glutStrokeWidth", (const GLUTproc) glutStrokeWidth },
|
|
{ "glutBitmapLength", (const GLUTproc) glutBitmapLength },
|
|
{ "glutStrokeLength", (const GLUTproc) glutStrokeLength },
|
|
{ "glutWireSphere", (const GLUTproc) glutWireSphere },
|
|
{ "glutSolidSphere", (const GLUTproc) glutSolidSphere },
|
|
{ "glutWireCone", (const GLUTproc) glutWireCone },
|
|
{ "glutSolidCone", (const GLUTproc) glutSolidCone },
|
|
{ "glutWireCube", (const GLUTproc) glutWireCube },
|
|
{ "glutSolidCube", (const GLUTproc) glutSolidCube },
|
|
{ "glutWireTorus", (const GLUTproc) glutWireTorus },
|
|
{ "glutSolidTorus", (const GLUTproc) glutSolidTorus },
|
|
{ "glutWireDodecahedron", (const GLUTproc) glutWireDodecahedron },
|
|
{ "glutSolidDodecahedron", (const GLUTproc) glutSolidDodecahedron },
|
|
{ "glutWireTeapot", (const GLUTproc) glutWireTeapot },
|
|
{ "glutSolidTeapot", (const GLUTproc) glutSolidTeapot },
|
|
{ "glutWireOctahedron", (const GLUTproc) glutWireOctahedron },
|
|
{ "glutSolidOctahedron", (const GLUTproc) glutSolidOctahedron },
|
|
{ "glutWireTetrahedron", (const GLUTproc) glutWireTetrahedron },
|
|
{ "glutSolidTetrahedron", (const GLUTproc) glutSolidTetrahedron },
|
|
{ "glutWireIcosahedron", (const GLUTproc) glutWireIcosahedron },
|
|
{ "glutSolidIcosahedron", (const GLUTproc) glutSolidIcosahedron },
|
|
{ "glutReportErrors", (const GLUTproc) glutReportErrors },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
GLUTproc glutGetProcAddress(const char *procName)
|
|
{
|
|
/* Try GLUT functions first */
|
|
int i;
|
|
for (i = 0; glut_functions[i].name; i++) {
|
|
if (strcmp(glut_functions[i].name, procName) == 0)
|
|
return glut_functions[i].address;
|
|
}
|
|
|
|
/* Try core GL functions */
|
|
return (GLUTproc) glFBDevGetProcAddress(procName);
|
|
}
|