blob: 30be36af7af802f6f3a30831be9ee3e2e9cbd32b [file] [log] [blame]
/*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <linux/fb.h>
#include <GL/glut.h>
#include "internal.h"
int GameMode;
static int ModePossible, DispChanged;
static struct fb_var_screeninfo NormVarInfo, GameVarInfo;
static GLFBDevContextPtr GameContext;
static GLFBDevVisualPtr NormVisual;
/* storage for non-gamemode callbacks */
void (*KeyFuncs[2])(unsigned char key, int x, int y);
static void (*NormFuncs[8])();
static const char*SetOpers(const char *p, unsigned int *min, unsigned int *max)
{
char *endptr;
int comp = *p, val, neq = 0;
if(p[1] == '=') {
neq = 0;
p++;
}
val = strtol(p+1, &endptr, 10);
if(endptr == p+1)
return p;
switch(comp) {
case '=':
*min = *max = val;
break;
case '!':
*min = val + 1;
*max = val - 1;
break;
case '<':
*max = val - neq;
break;
case '>':
*min = val + neq;
break;
}
return endptr;
}
void glutGameModeString(const char *string)
{
const char *p = string;
unsigned int minb = 15, maxb = 32;
unsigned int minw = 0, maxw = -1;
unsigned int minh, maxh = -1;
unsigned int minf = 0, maxf = MAX_VSYNC;
char *endptr;
int count = -1, val;
ModePossible = 0;
if(DisplayMode & GLUT_INDEX)
minb = maxb = 8;
again:
count++;
if((val = strtol(p, &endptr, 10)) && *endptr=='x') {
maxw = minw = val;
p = endptr + 1;
maxh = minh = strtol(p, &endptr, 10);
p = endptr;
goto again;
}
if(*p == ':') {
minb = strtol(p+1, &endptr, 10);
p = endptr;
if(DisplayMode & GLUT_INDEX) {
if(minb != 8)
return;
} else
if(minb != 15 && minb != 16 && minb != 24 && minb != 32)
return;
maxb = minb;
goto again;
}
if(*p == '@') {
minf = strtol(p+1, &endptr, 10) - 5;
maxf = minf + 10;
p = endptr;
goto again;
}
if(count == 0)
while(*p) {
if(*p == ' ')
p++;
else
if(memcmp(p, "bpp", 3) == 0)
p = SetOpers(p+3, &minb, &maxb);
else
if(memcmp(p, "height", 6) == 0)
p = SetOpers(p+6, &minh, &maxh);
else
if(memcmp(p, "hertz", 5) == 0)
p = SetOpers(p+5, &minf, &maxf);
else
if(memcmp(p, "width", 5) == 0)
p = SetOpers(p+5, &minw, &maxw);
else
if(p = strchr(p, ' '))
p++;
else
break;
}
NormVarInfo = VarInfo;
if(!ParseFBModes(minw, maxw, minh, maxh, minf, maxf))
return;
GameVarInfo = VarInfo;
VarInfo = NormVarInfo;
/* determine optimal bitdepth, make sure we have enough video memory */
if(VarInfo.bits_per_pixel && VarInfo.bits_per_pixel <= maxb)
GameVarInfo.bits_per_pixel = VarInfo.bits_per_pixel;
else
GameVarInfo.bits_per_pixel = maxb;
while(FixedInfo.smem_len < GameVarInfo.xres * GameVarInfo.yres
* GameVarInfo.bits_per_pixel / 8) {
if(GameVarInfo.bits_per_pixel < minb)
return;
GameVarInfo.bits_per_pixel = ((GameVarInfo.bits_per_pixel+1)/8)*8-8;
}
ModePossible = 1;
}
int glutEnterGameMode(void)
{
if(ActiveMenu)
return 0;
if(!ModePossible)
return 0;
if(GameMode) {
if(!memcmp(&GameVarInfo, &VarInfo, sizeof VarInfo)) {
DispChanged = 0;
return 1;
}
glutLeaveGameMode();
}
if (ioctl(FrameBufferFD, FBIOPUT_VSCREENINFO, &GameVarInfo))
return 0;
NormVarInfo = VarInfo;
VarInfo = GameVarInfo;
NormVisual = Visual;
SetVideoMode();
CreateVisual();
CreateBuffer();
if(!(GameContext = glFBDevCreateContext(Visual, NULL))) {
sprintf(exiterror, "Failure to create Context\n");
exit(0);
}
if(!glFBDevMakeCurrent( GameContext, Buffer, Buffer )) {
sprintf(exiterror, "Failure to Make Game Current\n");
exit(0);
}
InitializeCursor();
KeyFuncs[0] = KeyboardFunc;
KeyFuncs[1] = KeyboardUpFunc;
NormFuncs[0] = DisplayFunc;
NormFuncs[1] = ReshapeFunc;
NormFuncs[2] = MouseFunc;
NormFuncs[3] = MotionFunc;
NormFuncs[4] = PassiveMotionFunc;
NormFuncs[5] = VisibilityFunc;
NormFuncs[6] = SpecialFunc;
NormFuncs[7] = SpecialUpFunc;
DisplayFunc = NULL;
ReshapeFunc = NULL;
KeyboardFunc = NULL;
KeyboardUpFunc = NULL;
MouseFunc = NULL;
MotionFunc = NULL;
PassiveMotionFunc = NULL;
VisibilityFunc = NULL;
SpecialFunc = SpecialUpFunc = NULL;
DispChanged = 1;
GameMode = 1;
Visible = 1;
VisibleSwitch = 1;
Redisplay = 1;
return 1;
}
void glutLeaveGameMode(void)
{
if(!GameMode)
return;
glFBDevDestroyContext(GameContext);
glFBDevDestroyVisual(Visual);
VarInfo = NormVarInfo;
Visual = NormVisual;
if(Visual) {
SetVideoMode();
CreateBuffer();
if(!glFBDevMakeCurrent( Context, Buffer, Buffer )) {
sprintf(exiterror, "Failure to Make Current\n");
exit(0);
}
Redisplay = 1;
}
KeyboardFunc = KeyFuncs[0];
KeyboardUpFunc = KeyFuncs[1];
DisplayFunc = NormFuncs[0];
ReshapeFunc = NormFuncs[1];
MouseFunc = NormFuncs[2];
MotionFunc = NormFuncs[3];
PassiveMotionFunc = NormFuncs[4];
VisibilityFunc = NormFuncs[5];
SpecialFunc = NormFuncs[6];
SpecialUpFunc = NormFuncs[7];
GameMode = 0;
}
int glutGameModeGet(GLenum mode) {
switch(mode) {
case GLUT_GAME_MODE_ACTIVE:
return GameMode;
case GLUT_GAME_MODE_POSSIBLE:
return ModePossible;
case GLUT_GAME_MODE_DISPLAY_CHANGED:
return DispChanged;
}
if(!ModePossible)
return -1;
switch(mode) {
case GLUT_GAME_MODE_WIDTH:
return GameVarInfo.xres;
case GLUT_GAME_MODE_HEIGHT:
return GameVarInfo.yres;
case GLUT_GAME_MODE_PIXEL_DEPTH:
return GameVarInfo.bits_per_pixel;
case GLUT_GAME_MODE_REFRESH_RATE:
return 1E12/GameVarInfo.pixclock
/ (GameVarInfo.left_margin + GameVarInfo.xres
+ GameVarInfo.right_margin + GameVarInfo.hsync_len)
/ (GameVarInfo.upper_margin + GameVarInfo.yres
+ GameVarInfo.lower_margin + GameVarInfo.vsync_len);
}
}